pcsxr-1.9.92
[pcsx_rearmed.git] / plugins / peopsxgl / gpu.c
CommitLineData
ef79bbde
P
1/***************************************************************************\r
2 gpu.c - description\r
3 -------------------\r
4 begin : Sun Mar 08 2009\r
5 copyright : (C) 1999-2009 by Pete Bernert\r
6 email : BlackDove@addcom.de\r
7 ***************************************************************************/\r
8\r
9/***************************************************************************\r
10 * *\r
11 * This program is free software; you can redistribute it and/or modify *\r
12 * it under the terms of the GNU General Public License as published by *\r
13 * the Free Software Foundation; either version 2 of the License, or *\r
14 * (at your option) any later version. See also the license.txt file for *\r
15 * additional informations. *\r
16 * *\r
17 ***************************************************************************/\r
18\r
19// !!! enable this, if Linux XF86VidMode is not supported: \r
20//#define NOVMODE\r
21\r
22#include "stdafx.h"\r
23#include "config.h"\r
24\r
25#ifndef NOVMODE\r
26#include <X11/extensions/xf86vmode.h>\r
27static XF86VidModeModeInfo **modes=0;\r
28static int iOldMode=0;\r
29#endif\r
30\r
31#define _IN_GPU\r
32\r
33#include "externals.h"\r
34#include "gpu.h"\r
35#include "draw.h"\r
36#include "cfg.h"\r
37#include "prim.h"\r
38#include "psemu_plugin_defs.h"\r
39#include "texture.h"\r
40#include "menu.h"\r
41#include "fps.h"\r
42#include "key.h"\r
43#ifdef ENABLE_NLS\r
44#include <libintl.h>\r
45#include <locale.h>\r
46#define _(x) gettext(x)\r
47#define N_(x) (x)\r
48#else\r
49#define _(x) (x)\r
50#define N_(x) (x)\r
51#endif\r
52 \r
53////////////////////////////////////////////////////////////////////////\r
54// PPDK developer must change libraryName field and can change revision and build\r
55////////////////////////////////////////////////////////////////////////\r
56\r
57const unsigned char version = 1; // do not touch - library for PSEmu 1.x\r
58const unsigned char revision = 1;\r
59const unsigned char build = 78;\r
60\r
61static char *libraryName = N_("OpenGL Driver");\r
62\r
63static char *PluginAuthor = N_("Pete Bernert");\r
64static char *libraryInfo = N_("Based on P.E.Op.S. MesaGL Driver V1.78\nCoded by Pete Bernert\n");\r
65\r
66////////////////////////////////////////////////////////////////////////\r
67// memory image of the PSX vram\r
68////////////////////////////////////////////////////////////////////////\r
69\r
70unsigned char *psxVSecure;\r
71unsigned char *psxVub;\r
72signed char *psxVsb;\r
73unsigned short *psxVuw;\r
74unsigned short *psxVuw_eom;\r
75signed short *psxVsw;\r
76uint32_t *psxVul;\r
77signed int *psxVsl;\r
78\r
79// macro for easy access to packet information\r
80#define GPUCOMMAND(x) ((x>>24) & 0xff)\r
81\r
82GLfloat gl_z=0.0f;\r
83BOOL bNeedInterlaceUpdate=FALSE;\r
84BOOL bNeedRGB24Update=FALSE;\r
85BOOL bChangeWinMode=FALSE;\r
86\r
87uint32_t ulStatusControl[256];\r
88\r
89////////////////////////////////////////////////////////////////////////\r
90// global GPU vars\r
91////////////////////////////////////////////////////////////////////////\r
92\r
93static int GPUdataRet;\r
94int lGPUstatusRet;\r
95char szDispBuf[64];\r
96\r
97uint32_t dwGPUVersion = 0;\r
98int iGPUHeight = 512;\r
99int iGPUHeightMask = 511;\r
100int GlobalTextIL = 0;\r
101int iTileCheat = 0;\r
102\r
103static uint32_t gpuDataM[256];\r
104static unsigned char gpuCommand = 0;\r
105static int gpuDataC = 0;\r
106static int gpuDataP = 0;\r
107\r
108VRAMLoad_t VRAMWrite;\r
109VRAMLoad_t VRAMRead;\r
110int iDataWriteMode;\r
111int iDataReadMode;\r
112\r
113int lClearOnSwap;\r
114int lClearOnSwapColor;\r
115BOOL bSkipNextFrame = FALSE;\r
116int iColDepth;\r
117BOOL bChangeRes;\r
118BOOL bWindowMode;\r
119int iWinSize;\r
120\r
121// possible psx display widths\r
122short dispWidths[8] = {256,320,512,640,368,384,512,640};\r
123\r
124PSXDisplay_t PSXDisplay;\r
125PSXDisplay_t PreviousPSXDisplay;\r
126TWin_t TWin;\r
127short imageX0,imageX1;\r
128short imageY0,imageY1;\r
129BOOL bDisplayNotSet = TRUE;\r
130GLuint uiScanLine=0;\r
131int iUseScanLines=0;\r
132int lSelectedSlot=0;\r
133unsigned char * pGfxCardScreen=0;\r
134int iBlurBuffer=0;\r
135int iScanBlend=0;\r
136int iRenderFVR=0;\r
137int iNoScreenSaver=0;\r
138uint32_t ulGPUInfoVals[16];\r
139int iFakePrimBusy = 0;\r
140int iRumbleVal = 0;\r
141int iRumbleTime = 0;\r
142\r
143////////////////////////////////////////////////////////////////////////\r
144// stuff to make this a true PDK module\r
145////////////////////////////////////////////////////////////////////////\r
146\r
147char * CALLBACK PSEgetLibName(void)\r
148{\r
149 return _(libraryName);\r
150}\r
151\r
152unsigned long CALLBACK PSEgetLibType(void)\r
153{\r
154 return PSE_LT_GPU;\r
155}\r
156\r
157unsigned long CALLBACK PSEgetLibVersion(void)\r
158{\r
159 return version<<16|revision<<8|build;\r
160}\r
161\r
162char * GPUgetLibInfos(void)\r
163{\r
164 return _(libraryInfo);\r
165}\r
166\r
167////////////////////////////////////////////////////////////////////////\r
168// snapshot funcs (saves screen to bitmap / text infos into file)\r
169////////////////////////////////////////////////////////////////////////\r
170\r
171char * GetConfigInfos(int hW)\r
172{\r
173 char szO[2][4]={"off","on "};\r
174 char szTxt[256];\r
175 char * pB=(char *)malloc(32767);\r
176\r
177 if(!pB) return NULL;\r
178 *pB=0;\r
179 //----------------------------------------------------//\r
180 sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build);\r
181 strcat(pB,szTxt);\r
182 sprintf(szTxt,"Author: %s\r\n",PluginAuthor);\r
183 strcat(pB,szTxt);\r
184\r
185 sprintf(szTxt,"Card vendor: %s\r\n",(char *)glGetString(GL_VENDOR));\r
186 strcat(pB,szTxt);\r
187 sprintf(szTxt,"GFX card: %s\r\n",(char *)glGetString(GL_RENDERER));\r
188 strcat(pB,szTxt);\r
189 sprintf(szTxt,"OGL version: %s\r\n\r\n",(char *)glGetString(GL_VERSION));\r
190 strcat(pB,szTxt);\r
191 //strcat(pB,(char *)glGetString(GL_EXTENSIONS));\r
192 //strcat(pB,"\r\n\r\n");\r
193\r
194 if(hW && bWindowMode)\r
195 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));\r
196 else\r
197 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);\r
198 strcat(pB,szTxt);\r
199 if(bWindowMode) sprintf(szTxt,"Window mode\r\n");\r
200 else\r
201 {\r
202 sprintf(szTxt,"Fullscreen ");\r
203 strcat(pB,szTxt);\r
204 if(bChangeRes) sprintf(szTxt,"- Desktop changing [%d Bit]\r\n",iColDepth);\r
205 else sprintf(szTxt,"- NO desktop changing\r\n");\r
206 } \r
207 strcat(pB,szTxt);\r
208\r
209 if(iForceVSync>=0) sprintf(szTxt,"- V-Sync: %s\r\n",szO[iForceVSync]);\r
210 else strcpy(szTxt,"- V-Sync: Driver\r\n");\r
211 strcat(pB,szTxt); \r
212 sprintf(szTxt,"- Keep psx aspect ratio: %s\r\n\r\n",szO[bKeepRatio]);\r
213 strcat(pB,szTxt);\r
214 //----------------------------------------------------//\r
215 strcpy(szTxt,"Textures:\r\n- ");\r
216 if(iTexQuality==0) strcat(szTxt,"Default");\r
217 else if(iTexQuality==1) strcat(szTxt,"R4G4B4A4");\r
218 else if(iTexQuality==2) strcat(szTxt,"R5G5B5A1");\r
219 else if(iTexQuality==3) strcat(szTxt,"R8G8A8A8");\r
220 else if(iTexQuality==4) strcat(szTxt,"B8G8R8A8");\r
221 if(!hW && bGLExt) strcat(szTxt," (packed pixels)\r\n");\r
222 else strcat(szTxt,"\r\n");\r
223 strcat(pB,szTxt);\r
224 if(!hW)\r
225 {\r
226 sprintf(szTxt,"- Filtering: %d - edge clamping ",iFilterType);\r
227 if(iClampType==GL_TO_EDGE_CLAMP) strcat(szTxt,"supported\r\n");\r
228 else strcat(szTxt,"NOT supported\r\n");\r
229 }\r
230 else sprintf(szTxt,"- iFiltering: %d\r\n",iFilterType);\r
231 strcat(pB,szTxt);\r
232 sprintf(szTxt,"- Hi-Res textures: %d\r\n",iHiResTextures);\r
233 strcat(pB,szTxt); \r
234 if(!hW)\r
235 {\r
236 sprintf(szTxt,"- Palettized tex windows: %s\r\n",szO[iUsePalTextures]);\r
237 strcat(pB,szTxt); \r
238 }\r
239 sprintf(szTxt,"- VRam size: %d MBytes",iVRamSize);\r
240 if(!hW)\r
241 sprintf(szTxt+strlen(szTxt)," - %d textures usable\r\n\r\n",iSortTexCnt);\r
242 else strcat(szTxt,"\r\n\r\n");\r
243 strcat(pB,szTxt);\r
244 //----------------------------------------------------//\r
245 sprintf(szTxt,"Framerate:\r\n- FPS limitation: %s\r\n",szO[bUseFrameLimit]);\r
246 strcat(pB,szTxt);\r
247 sprintf(szTxt,"- Frame skipping: %s\r\n",szO[bUseFrameSkip]);\r
248 strcat(pB,szTxt);\r
249 if(iFrameLimit==2)\r
250 strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");\r
251 else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);\r
252 strcat(pB,szTxt);\r
253 //----------------------------------------------------//\r
254 sprintf(szTxt,"Compatibility:\r\n- Offscreen drawing: %d\r\n",iOffscreenDrawing);\r
255 strcat(pB,szTxt);\r
256 sprintf(szTxt,"- Framebuffer texture: %d",iFrameTexType);\r
257 if(!hW && iFrameTexType==2)\r
258 {\r
259 if(gTexFrameName) strcat(szTxt," - texture created\r\n");\r
260 else strcat(szTxt," - not used yet\r\n");\r
261 }\r
262 else strcat(szTxt,"\r\n");\r
263 strcat(pB,szTxt);\r
264 sprintf(szTxt,"- Framebuffer access: %d\r\n",iFrameReadType);\r
265 strcat(pB,szTxt);\r
266 sprintf(szTxt,"- Alpha multipass: %s\r\n",szO[bOpaquePass]);\r
267 strcat(pB,szTxt);\r
268 sprintf(szTxt,"- Mask bit: %s\r\n",szO[iUseMask]);\r
269 strcat(pB,szTxt);\r
270 sprintf(szTxt,"- Advanced blending: %s",szO[bAdvancedBlend]);\r
271 if(!hW && bAdvancedBlend)\r
272 {\r
273 if(bGLBlend) strcat(szTxt," (hardware)\r\n");\r
274 else strcat(szTxt," (software)\r\n");\r
275 }\r
276 else strcat(szTxt,"\r\n");\r
277 strcat(pB,szTxt);\r
278\r
279 if(!hW)\r
280 {\r
281 strcpy(szTxt,"- Subtractive blending: ");\r
282 if(glBlendEquationEXTEx)\r
283 {\r
284 if(bUseMultiPass) strcat(szTxt,"supported, but not used!");\r
285 else strcat(szTxt,"activated");\r
286 }\r
287 else strcat(szTxt," NOT supported!");\r
288 strcat(szTxt,"\r\n\r\n");\r
289 }\r
290 else strcpy(szTxt,"\r\n");\r
291 \r
292 strcat(pB,szTxt); \r
293 //----------------------------------------------------//\r
294 sprintf(szTxt,"Misc:\r\n- Scanlines: %s",szO[iUseScanLines]);\r
295 strcat(pB,szTxt);\r
296 if(iUseScanLines) sprintf(szTxt," [%d]\r\n",iScanBlend);\r
297 else strcpy(szTxt,"\r\n");\r
298 strcat(pB,szTxt);\r
299 sprintf(szTxt,"- Line mode: %s\r\n",szO[bUseLines]);\r
300 strcat(pB,szTxt);\r
301// sprintf(szTxt,"- Line AA: %s\r\n",szO[bUseAntiAlias]);\r
302// fwrite(szTxt,lstrlen(szTxt),1,txtfile);\r
303 sprintf(szTxt,"- Unfiltered FB: %s\r\n",szO[bUseFastMdec]);\r
304 strcat(pB,szTxt);\r
305 sprintf(szTxt,"- 15 bit FB: %s\r\n",szO[bUse15bitMdec]);\r
306 strcat(pB,szTxt);\r
307 sprintf(szTxt,"- Dithering: %s\r\n",szO[bDrawDither]);\r
308 strcat(pB,szTxt);\r
309 sprintf(szTxt,"- Screen smoothing: %s",szO[iBlurBuffer]);\r
310 strcat(pB,szTxt);\r
311 if(!hW && iBlurBuffer) \r
312 {\r
313 if(gTexBlurName) strcat(pB," - supported\r\n");\r
314 else strcat(pB," - not supported\r\n");\r
315 }\r
316 else strcat(pB,"\r\n");\r
317 sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[bUseFixes],dwCfgFixes);\r
318 strcat(pB,szTxt);\r
319 //----------------------------------------------------//\r
320 return pB;\r
321}\r
322\r
323////////////////////////////////////////////////////////////////////////\r
324// save text infos to file\r
325////////////////////////////////////////////////////////////////////////\r
326\r
327void DoTextSnapShot(int iNum)\r
328{\r
329 FILE *txtfile;char szTxt[256];char * pB;\r
330\r
331 sprintf(szTxt,"%s/pcsx%04d.txt",getenv("HOME"),iNum);\r
332\r
333 if((txtfile=fopen(szTxt,"wb"))==NULL)\r
334 return; \r
335\r
336 pB=GetConfigInfos(0);\r
337 if(pB)\r
338 {\r
339 fwrite(pB,strlen(pB),1,txtfile);\r
340 free(pB);\r
341 }\r
342 fclose(txtfile); \r
343}\r
344\r
345////////////////////////////////////////////////////////////////////////\r
346// saves screen bitmap to file\r
347////////////////////////////////////////////////////////////////////////\r
348\r
349void DoSnapShot(void)\r
350{\r
351 unsigned char * snapshotdumpmem=NULL,* p,c;\r
352 FILE *bmpfile;char filename[256];\r
353 unsigned char header[0x36];int size;\r
354 unsigned char empty[2]={0,0};int i;\r
355 unsigned int snapshotnr = 0;\r
356 short SnapWidth;\r
357 short SnapHeigth;\r
358\r
359 bSnapShot=FALSE;\r
360\r
361 SnapWidth = iResX;\r
362 SnapHeigth = iResY;\r
363\r
364 size=SnapWidth * SnapHeigth * 3 + 0x38;\r
365\r
366 if((snapshotdumpmem=(unsigned char *)\r
367 malloc(SnapWidth*SnapHeigth*3))==NULL)\r
368 return;\r
369 \r
370 // fill in proper values for BMP\r
371 for(i=0;i<0x36;i++) header[i]=0;\r
372 header[0]='B';\r
373 header[1]='M';\r
374 header[2]=(unsigned char)(size&0xff);\r
375 header[3]=(unsigned char)((size>>8)&0xff);\r
376 header[4]=(unsigned char)((size>>16)&0xff);\r
377 header[5]=(unsigned char)((size>>24)&0xff);\r
378 header[0x0a]=0x36;\r
379 header[0x0e]=0x28;\r
380 header[0x12]=(unsigned char)(SnapWidth%256);\r
381 header[0x13]=(unsigned char)(SnapWidth/256);\r
382 header[0x16]=(unsigned char)(SnapHeigth%256);\r
383 header[0x17]=(unsigned char)(SnapHeigth/256);\r
384 header[0x1a]=0x01;\r
385 header[0x1c]=0x18;\r
386 header[0x26]=0x12;\r
387 header[0x27]=0x0B;\r
388 header[0x2A]=0x12;\r
389 header[0x2B]=0x0B;\r
390\r
391 // increment snapshot value\r
392 // get filename\r
393 do\r
394 {\r
395 snapshotnr++;\r
396 sprintf(filename,"%s/pcsx%04d.bmp",getenv("HOME"),snapshotnr);\r
397 bmpfile=fopen(filename,"rb");\r
398 if(bmpfile==NULL)break;\r
399 fclose(bmpfile);\r
400 if(snapshotnr==9999) break;\r
401 }\r
402 while(TRUE);\r
403\r
404 // try opening new snapshot file\r
405 if((bmpfile=fopen(filename,"wb"))==NULL)\r
406 {free(snapshotdumpmem);return;}\r
407\r
408 fwrite(header,0x36,1,bmpfile);\r
409\r
410 glReadPixels(0,0,SnapWidth,SnapHeigth,GL_RGB,\r
411 GL_UNSIGNED_BYTE,snapshotdumpmem);\r
412 p=snapshotdumpmem;\r
413 size=SnapWidth * SnapHeigth;\r
414\r
415 for(i=0;i<size;i++,p+=3)\r
416 {c=*p;*p=*(p+2);*(p+2)=c;}\r
417\r
418 fwrite(snapshotdumpmem,size*3,1,bmpfile);\r
419 fwrite(empty,0x2,1,bmpfile);\r
420 fclose(bmpfile); \r
421 free(snapshotdumpmem);\r
422\r
423 DoTextSnapShot(snapshotnr);\r
424} \r
425\r
426void CALLBACK GPUmakeSnapshot(void)\r
427{\r
428 bSnapShot = TRUE;\r
429} \r
430\r
431////////////////////////////////////////////////////////////////////////\r
432// GPU INIT... here starts it all (first func called by emu)\r
433////////////////////////////////////////////////////////////////////////\r
434\r
435long CALLBACK GPUinit()\r
436{\r
437 memset(ulStatusControl,0,256*sizeof(uint32_t));\r
438\r
439 // different ways of accessing PSX VRAM\r
440\r
441 psxVSecure=(unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security\r
442 if(!psxVSecure) return -1;\r
443\r
444 psxVub=psxVSecure+512*1024; // security offset into double sized psx vram!\r
445 psxVsb=(signed char *)psxVub;\r
446 psxVsw=(signed short *)psxVub;\r
447 psxVsl=(signed int *)psxVub;\r
448 psxVuw=(unsigned short *)psxVub;\r
449 psxVul=(uint32_t *)psxVub;\r
450\r
451 psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram\r
452\r
453 memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));\r
454 memset(ulGPUInfoVals,0x00,16*sizeof(uint32_t));\r
455\r
456 InitFrameCap(); // init frame rate stuff\r
457\r
458 PSXDisplay.RGB24 = 0; // init vars\r
459 PreviousPSXDisplay.RGB24= 0;\r
460 PSXDisplay.Interlaced = 0;\r
461 PSXDisplay.InterlacedTest=0;\r
462 PSXDisplay.DrawOffset.x = 0;\r
463 PSXDisplay.DrawOffset.y = 0;\r
464 PSXDisplay.DrawArea.x0 = 0;\r
465 PSXDisplay.DrawArea.y0 = 0;\r
466 PSXDisplay.DrawArea.x1 = 320;\r
467 PSXDisplay.DrawArea.y1 = 240;\r
468 PSXDisplay.DisplayMode.x= 320;\r
469 PSXDisplay.DisplayMode.y= 240;\r
470 PSXDisplay.Disabled = FALSE;\r
471 PreviousPSXDisplay.Range.x0 =0;\r
472 PreviousPSXDisplay.Range.x1 =0;\r
473 PreviousPSXDisplay.Range.y0 =0;\r
474 PreviousPSXDisplay.Range.y1 =0;\r
475 PSXDisplay.Range.x0=0;\r
476 PSXDisplay.Range.x1=0;\r
477 PSXDisplay.Range.y0=0;\r
478 PSXDisplay.Range.y1=0;\r
479 PreviousPSXDisplay.DisplayPosition.x = 1;\r
480 PreviousPSXDisplay.DisplayPosition.y = 1;\r
481 PSXDisplay.DisplayPosition.x = 1;\r
482 PSXDisplay.DisplayPosition.y = 1;\r
483 PreviousPSXDisplay.DisplayModeNew.y=0;\r
484 PSXDisplay.Double=1;\r
485 GPUdataRet=0x400;\r
486\r
487 PSXDisplay.DisplayModeNew.x=0;\r
488 PSXDisplay.DisplayModeNew.y=0;\r
489\r
490 //PreviousPSXDisplay.Height = PSXDisplay.Height = 239;\r
491 \r
492 iDataWriteMode = DR_NORMAL;\r
493\r
494 // Reset transfer values, to prevent mis-transfer of data\r
495 memset(&VRAMWrite,0,sizeof(VRAMLoad_t));\r
496 memset(&VRAMRead,0,sizeof(VRAMLoad_t));\r
497 \r
498 // device initialised already !\r
499 //lGPUstatusRet = 0x74000000;\r
500\r
501 STATUSREG = 0x14802000;\r
502 GPUIsIdle;\r
503 GPUIsReadyForCommands;\r
504\r
505 return 0;\r
506} \r
507\r
508////////////////////////////////////////////////////////////////////////\r
509// GPU OPEN: funcs to open up the gpu display (Windows)\r
510////////////////////////////////////////////////////////////////////////\r
511\r
512////////////////////////////////////////////////////////////////////////\r
513// LINUX GPU OPEN: func to open up the gpu display (X stuff)\r
514// please note: in linux we are creating our own display, and we return\r
515// the display ID to the main emu... that's cleaner\r
516////////////////////////////////////////////////////////////////////////\r
517\r
518char * pCaptionText=0;\r
519int bFullScreen=0;\r
520Display *display;\r
521\r
522static Cursor cursor;\r
523static XVisualInfo *myvisual;\r
524static Colormap colormap;\r
525static Window window;\r
526\r
527static int bModeChanged=0;\r
528\r
529typedef struct\r
530{\r
531#define MWM_HINTS_DECORATIONS 2\r
532 long flags;\r
533 long functions;\r
534 long decorations;\r
535 long input_mode;\r
536} MotifWmHints;\r
537\r
538static int dbdepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,GLX_DEPTH_SIZE,16,None};\r
539static int dbnodepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,None};\r
540static GLXContext cx;\r
541\r
542static int fx=0;\r
543\r
544////////////////////////////////////////////////////////////////////////\r
545\r
546void osd_close_display (void) // close display\r
547{\r
548 if(display) // display exists?\r
549 {\r
550 glXDestroyContext(display,cx); // -> kill context\r
551 XFreeColormap(display, colormap); // -> kill colormap\r
552 XSync(display,False); // -> sync events\r
553\r
554#ifndef NOVMODE\r
555 if(bModeChanged) // -> repair screen mode\r
556 {\r
557 int myscreen=DefaultScreen(display);\r
558 XF86VidModeSwitchToMode(display,myscreen, // --> switch mode back\r
559 modes[iOldMode]);\r
560 XF86VidModeSetViewPort(display,myscreen,0,0); // --> set viewport upperleft\r
561 free(modes); // --> finally kill mode infos\r
562 bModeChanged=0; // --> done\r
563 }\r
564#endif\r
565\r
566 XCloseDisplay(display); // -> close display\r
567 }\r
568}\r
569\r
570////////////////////////////////////////////////////////////////////////\r
571\r
572void sysdep_create_display(void) // create display\r
573{\r
574 XSetWindowAttributes winattr;float fxgamma=2;\r
575 int myscreen;char gammastr[14];\r
576 Screen * screen;XEvent event;\r
577 XSizeHints hints;XWMHints wm_hints;\r
578 MotifWmHints mwmhints;Atom mwmatom;Atom delwindow;\r
579 char *glxfx;\r
580\r
581 glxfx=getenv("MESA_GLX_FX"); // 3dfx mesa fullscreen flag\r
582 if(glxfx)\r
583 {\r
584 if(glxfx[0]=='f') // -> yup, fullscreen needed\r
585 {\r
586 fx=1; // -> raise flag\r
587 putenv("FX_GLIDE_NO_SPLASH=");\r
588 sprintf(gammastr,"SST_GAMMA=%2.1f",fxgamma); // -> set gamma\r
589 putenv(gammastr);\r
590 }\r
591 }\r
592\r
593 display=XOpenDisplay(NULL); // open display\r
594 if(!display) // no display?\r
595 {\r
596 fprintf (stderr,"Failed to open display!!!\n");\r
597 osd_close_display();\r
598 return; // -> bye\r
599 }\r
600\r
601 myscreen=DefaultScreen(display); // get screen id\r
602\r
603#ifdef NOVMODE\r
604 if(bFullScreen) {fx=1;bModeChanged=0;}\r
605#else\r
606 if(bFullScreen)\r
607 {\r
608 XF86VidModeModeLine mode;\r
609 int nmodes,iC;\r
610 fx=1; // raise flag\r
611 XF86VidModeGetModeLine(display,myscreen,&iC,&mode); // get actual mode info\r
612 if(mode.privsize) XFree(mode.private); // no need for private stuff\r
613 bModeChanged=0; // init mode change flag\r
614 if(iResX!=mode.hdisplay || iResY!=mode.vdisplay) // wanted mode is different?\r
615 {\r
616 XF86VidModeGetAllModeLines(display,myscreen, // -> enum all mode infos\r
617 &nmodes,&modes);\r
618 if(modes) // -> infos got?\r
619 {\r
620 for(iC=0;iC<nmodes;++iC) // -> loop modes\r
621 {\r
622 if(mode.hdisplay==modes[iC]->hdisplay && // -> act mode found?\r
623 mode.vdisplay==modes[iC]->vdisplay) // if yes: store mode id\r
624 iOldMode=iC;\r
625\r
626 if(iResX==modes[iC]->hdisplay && // -> wanted mode found?\r
627 iResY==modes[iC]->vdisplay)\r
628 {\r
629 XF86VidModeSwitchToMode(display,myscreen, // --> switch to mode\r
630 modes[iC]);\r
631 XF86VidModeSetViewPort(display,myscreen,0,0);\r
632 bModeChanged=1; // --> raise flag for repairing mode on close\r
633 }\r
634 }\r
635\r
636 if(bModeChanged==0) // -> no mode found?\r
637 {\r
638 free(modes); // --> free infos\r
639 printf("No proper fullscreen mode found!\n"); // --> some info output\r
640 }\r
641 }\r
642 }\r
643 }\r
644#endif\r
645\r
646 screen=DefaultScreenOfDisplay(display);\r
647\r
648 if(iZBufferDepth) // visual (with or without zbuffer)\r
649 myvisual=glXChooseVisual(display,myscreen,dbdepat);\r
650 else myvisual=glXChooseVisual(display,myscreen,dbnodepat);\r
651\r
652 if(!myvisual) // no visual?\r
653 {\r
654 fprintf(stderr,"Failed to obtain visual!!!\n"); // -> bye\r
655 osd_close_display();\r
656 return;\r
657 }\r
658\r
659 cx=glXCreateContext(display,myvisual,0,GL_TRUE); // create rendering context\r
660\r
661 if(!cx) // no context?\r
662 {\r
663 fprintf(stderr,"Failed to create OpenGL context!!!\n");\r
664 osd_close_display(); // -> bxe\r
665 return;\r
666 }\r
667\r
668 // pffff... much work for a simple blank cursor... oh, well...\r
669 if(!bFullScreen) cursor=XCreateFontCursor(display,XC_trek);\r
670 else\r
671 {\r
672 Pixmap p1,p2;XImage * img;\r
673 XColor b,w;unsigned char * idata;\r
674 XGCValues GCv;\r
675 GC GCc;\r
676\r
677 memset(&b,0,sizeof(XColor));\r
678 memset(&w,0,sizeof(XColor));\r
679 idata=(unsigned char *)malloc(8);\r
680 memset(idata,0,8);\r
681\r
682 p1=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);\r
683 p2=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);\r
684\r
685 img = XCreateImage(display,myvisual->visual,\r
686 1,XYBitmap,0,idata,8,8,8,1);\r
687\r
688 GCv.function = GXcopy;\r
689 GCv.foreground = ~0;\r
690 GCv.background = 0;\r
691 GCv.plane_mask = AllPlanes;\r
692 GCc = XCreateGC(display,p1,\r
693 (GCFunction|GCForeground|GCBackground|GCPlaneMask),&GCv);\r
694\r
695 XPutImage(display, p1,GCc,img,0,0,0,0,8,8);\r
696 XPutImage(display, p2,GCc,img,0,0,0,0,8,8);\r
697 XFreeGC(display, GCc);\r
698\r
699 cursor = XCreatePixmapCursor(display,p1,p2,&b,&w,0,0);\r
700\r
701 XFreePixmap(display,p1);\r
702 XFreePixmap(display,p2);\r
703 XDestroyImage(img); // will free idata as well\r
704 }\r
705\r
706 colormap=XCreateColormap(display, // create colormap\r
707 RootWindow(display,myvisual->screen),\r
708 myvisual->visual,AllocNone);\r
709\r
710 winattr.background_pixel=0;\r
711 winattr.border_pixel=WhitePixelOfScreen(screen);\r
712 winattr.bit_gravity=ForgetGravity;\r
713 winattr.win_gravity=NorthWestGravity;\r
714 winattr.backing_store=NotUseful;\r
715 winattr.override_redirect=False;\r
716 winattr.save_under=False;\r
717 winattr.event_mask=0;\r
718 winattr.do_not_propagate_mask=0;\r
719 winattr.colormap=colormap;\r
720 winattr.cursor=None;\r
721\r
722 window=XCreateWindow(display, // create own window\r
723 RootWindow(display,DefaultScreen(display)),\r
724 0,0,iResX,iResY,\r
725 0,myvisual->depth,\r
726 InputOutput,myvisual->visual,\r
727 CWBorderPixel | CWBackPixel |\r
728 CWEventMask | CWDontPropagate |\r
729 CWColormap | CWCursor,\r
730 &winattr);\r
731\r
732 if(!window) // no window?\r
733 {\r
734 fprintf(stderr,"Failed in XCreateWindow()!!!\n");\r
735 osd_close_display(); // -> bye\r
736 return;\r
737 }\r
738\r
739 delwindow = XInternAtom(display,"WM_DELETE_WINDOW",0);\r
740 XSetWMProtocols(display, window, &delwindow, 1);\r
741\r
742 hints.flags=PMinSize|PMaxSize; // hints\r
743 if(fx) hints.flags|=USPosition|USSize;\r
744 else hints.flags|=PSize;\r
745\r
746 hints.min_width = hints.max_width = hints.base_width = iResX;\r
747 hints.min_height = hints.max_height = hints.base_height = iResY;\r
748\r
749 wm_hints.input=1;\r
750 wm_hints.flags=InputHint;\r
751\r
752 XSetWMHints(display,window,&wm_hints);\r
753 XSetWMNormalHints(display,window,&hints);\r
754 if(pCaptionText) // caption\r
755 XStoreName(display,window,pCaptionText);\r
756 else XStoreName(display,window,"Pete MesaGL PSX Gpu");\r
757\r
758 XDefineCursor(display,window,cursor); // cursor\r
759\r
760 if(fx) // window title bar hack\r
761 {\r
762 mwmhints.flags=MWM_HINTS_DECORATIONS;\r
763 mwmhints.decorations=0;\r
764 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);\r
765 XChangeProperty(display,window,mwmatom,mwmatom,32,\r
766 PropModeReplace,(unsigned char *)&mwmhints,4);\r
767 }\r
768\r
769 XSelectInput(display,window, // input setup\r
770 FocusChangeMask | ExposureMask |\r
771 KeyPressMask | KeyReleaseMask);\r
772\r
773 XMapRaised(display,window);\r
774 XClearWindow(display,window);\r
775 XWindowEvent(display,window,ExposureMask,&event);\r
776 glXMakeCurrent(display,window,cx);\r
777\r
778/* \r
779 printf(glGetString(GL_VENDOR));\r
780 printf("\n");\r
781 printf(glGetString(GL_RENDERER));\r
782 printf("\n");\r
783*/\r
784\r
785 if (fx) // after make current: fullscreen resize\r
786 {\r
787 XResizeWindow(display,window,screen->width,screen->height);\r
788 hints.min_width = hints.max_width = hints.base_width = screen->width;\r
789 hints.min_height= hints.max_height = hints.base_height = screen->height;\r
790 XSetWMNormalHints(display,window,&hints);
791
792 // set the window layer for GNOME
793 {
794 XEvent xev;
795
796 memset(&xev, 0, sizeof(xev));
797 xev.xclient.type = ClientMessage;
798 xev.xclient.serial = 0;
799 xev.xclient.send_event = 1;
800 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
801 xev.xclient.window = window;
802 xev.xclient.format = 32;
803 xev.xclient.data.l[0] = 1;
804 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
805 xev.xclient.data.l[2] = 0;
806 xev.xclient.data.l[3] = 0;
807 xev.xclient.data.l[4] = 0;
808
809 XSendEvent(display, RootWindow(display, DefaultScreen(display)), 0,
810 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
811 }
812 }\r
813}\r
814\r
815////////////////////////////////////////////////////////////////////////\r
816\r
817long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)\r
818{\r
819 pCaptionText=CapText;\r
820 pConfigFile=CfgFile;\r
821\r
822 ReadConfig(); // read text file for config\r
823\r
824 SetFrameRateConfig(); // setup frame rate stuff\r
825\r
826 bIsFirstFrame = TRUE; // we have to init later (well, no really... in Linux we do all in GPUopen)\r
827\r
828 sysdep_create_display(); // create display\r
829\r
830 InitializeTextureStore(); // init texture mem\r
831\r
832 rRatioRect.left = rRatioRect.top=0;\r
833 rRatioRect.right = iResX;\r
834 rRatioRect.bottom = iResY;\r
835\r
836 GLinitialize(); // init opengl\r
837\r
838 if(disp)\r
839 {\r
840 *disp=(unsigned long *)display; // return display ID to main emu\r
841 }\r
842\r
843 if(display) return 0;\r
844 return -1;\r
845}\r
846\r
847////////////////////////////////////////////////////////////////////////\r
848// close\r
849////////////////////////////////////////////////////////////////////////\r
850\r
851long GPUclose() // LINUX CLOSE\r
852{\r
853 GLcleanup(); // close OGL\r
854\r
855 if(pGfxCardScreen) free(pGfxCardScreen); // free helper memory\r
856 pGfxCardScreen=0;\r
857\r
858 osd_close_display(); // destroy display\r
859\r
860 return 0;\r
861}\r
862\r
863////////////////////////////////////////////////////////////////////////\r
864// I shot the sheriff... last function called from emu \r
865////////////////////////////////////////////////////////////////////////\r
866\r
867long CALLBACK GPUshutdown()\r
868{\r
869 if(psxVSecure) free(psxVSecure); // kill emulated vram memory\r
870 psxVSecure=0;\r
871\r
872 return 0;\r
873}\r
874\r
875////////////////////////////////////////////////////////////////////////\r
876// paint it black: simple func to clean up optical border garbage\r
877////////////////////////////////////////////////////////////////////////\r
878\r
879void PaintBlackBorders(void)\r
880{\r
881 short s;\r
882\r
883 glDisable(GL_SCISSOR_TEST);\r
884 if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}\r
885 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}\r
886 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}\r
887 glDisable(GL_ALPHA_TEST);\r
888\r
889 glBegin(GL_QUADS);\r
890\r
891 vertex[0].c.lcol=0xff000000;\r
892 SETCOL(vertex[0]); \r
893\r
894 if(PreviousPSXDisplay.Range.x0)\r
895 {\r
896 s=PreviousPSXDisplay.Range.x0+1;\r
897 glVertex3f(0,0,0.99996f);\r
898 glVertex3f(0,PSXDisplay.DisplayMode.y,0.99996f);\r
899 glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);\r
900 glVertex3f(s,0,0.99996f);\r
901\r
902 s+=PreviousPSXDisplay.Range.x1-2;\r
903\r
904 glVertex3f(s,0,0.99996f);\r
905 glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);\r
906 glVertex3f(PSXDisplay.DisplayMode.x,PSXDisplay.DisplayMode.y,0.99996f);\r
907 glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);\r
908 }\r
909\r
910 if(PreviousPSXDisplay.Range.y0)\r
911 {\r
912 s=PreviousPSXDisplay.Range.y0+1;\r
913 glVertex3f(0,0,0.99996f);\r
914 glVertex3f(0,s,0.99996f);\r
915 glVertex3f(PSXDisplay.DisplayMode.x,s,0.99996f);\r
916 glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);\r
917 }\r
918\r
919 glEnd();\r
920\r
921 glEnable(GL_ALPHA_TEST);\r
922 glEnable(GL_SCISSOR_TEST);\r
923}\r
924\r
925////////////////////////////////////////////////////////////////////////\r
926// helper to draw scanlines\r
927////////////////////////////////////////////////////////////////////////\r
928\r
929__inline void XPRIMdrawTexturedQuad(OGLVertex* vertex1, OGLVertex* vertex2, \r
930 OGLVertex* vertex3, OGLVertex* vertex4) \r
931{\r
932\r
933 glBegin(GL_QUAD_STRIP);\r
934 glTexCoord2fv(&vertex1->sow);\r
935 glVertex3fv(&vertex1->x);\r
936 \r
937 glTexCoord2fv(&vertex2->sow);\r
938 glVertex3fv(&vertex2->x);\r
939 \r
940 glTexCoord2fv(&vertex4->sow);\r
941 glVertex3fv(&vertex4->x);\r
942 \r
943 glTexCoord2fv(&vertex3->sow);\r
944 glVertex3fv(&vertex3->x);\r
945 glEnd();\r
946}\r
947\r
948////////////////////////////////////////////////////////////////////////\r
949// scanlines\r
950////////////////////////////////////////////////////////////////////////\r
951\r
952void SetScanLines(void)\r
953{\r
954 glLoadIdentity();\r
955 glOrtho(0,iResX,iResY, 0, -1, 1);\r
956\r
957 if(bKeepRatio)\r
958 glViewport(0,0,iResX,iResY);\r
959\r
960 glDisable(GL_SCISSOR_TEST); \r
961 glDisable(GL_ALPHA_TEST);\r
962 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}\r
963\r
964 if(iScanBlend<0) // special texture mask scanline mode\r
965 {\r
966 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}\r
967 gTexName=gTexScanName;\r
968 glBindTexture(GL_TEXTURE_2D, gTexName);\r
969 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); \r
970 if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}\r
971 SetScanTexTrans();\r
972\r
973 vertex[0].x=0;\r
974 vertex[0].y=iResY;\r
975 vertex[0].z=0.99996f;\r
976\r
977 vertex[1].x=iResX;\r
978 vertex[1].y=iResY;\r
979 vertex[1].z=0.99996f;\r
980\r
981 vertex[2].x=iResX;\r
982 vertex[2].y=0;\r
983 vertex[2].z=0.99996f;\r
984\r
985 vertex[3].x=0;\r
986 vertex[3].y=0;\r
987 vertex[3].z=0.99996f;\r
988\r
989 vertex[0].sow=0;\r
990 vertex[0].tow=0;\r
991 vertex[1].sow=(float)iResX/4.0f;\r
992 vertex[1].tow=0;\r
993 vertex[2].sow=vertex[1].sow;\r
994 vertex[2].tow=(float)iResY/4.0f;\r
995 vertex[3].sow=0;\r
996 vertex[3].tow=vertex[2].tow;\r
997\r
998 vertex[0].c.lcol=0xffffffff;\r
999 SETCOL(vertex[0]); \r
1000\r
1001 XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);\r
1002\r
1003 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT); \r
1004 }\r
1005 else // typical line mode\r
1006 {\r
1007 if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}\r
1008\r
1009 if(iScanBlend==0)\r
1010 {\r
1011 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}\r
1012 vertex[0].c.lcol=0xff000000;\r
1013 }\r
1014 else\r
1015 {\r
1016 if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}\r
1017 SetScanTrans();\r
1018 vertex[0].c.lcol=iScanBlend<<24;\r
1019 }\r
1020\r
1021 SETCOL(vertex[0]); \r
1022\r
1023 glCallList(uiScanLine);\r
1024 }\r
1025\r
1026 glLoadIdentity();\r
1027 glOrtho(0,PSXDisplay.DisplayMode.x,\r
1028 PSXDisplay.DisplayMode.y, 0, -1, 1);\r
1029\r
1030 if(bKeepRatio)\r
1031 glViewport(rRatioRect.left,\r
1032 iResY-(rRatioRect.top+rRatioRect.bottom),\r
1033 rRatioRect.right, \r
1034 rRatioRect.bottom); // init viewport\r
1035\r
1036 glEnable(GL_ALPHA_TEST);\r
1037 glEnable(GL_SCISSOR_TEST); \r
1038}\r
1039\r
1040////////////////////////////////////////////////////////////////////////\r
1041// blur, babe, blur (heavy performance hit for a so-so fullscreen effect)\r
1042////////////////////////////////////////////////////////////////////////\r
1043\r
1044void BlurBackBuffer(void)\r
1045{\r
1046 if(!gTexBlurName) return;\r
1047\r
1048 if(bKeepRatio) glViewport(0,0,iResX,iResY);\r
1049\r
1050 glDisable(GL_SCISSOR_TEST);\r
1051 glDisable(GL_ALPHA_TEST);\r
1052 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}\r
1053 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}\r
1054 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}\r
1055 if(iZBufferDepth) glDisable(GL_DEPTH_TEST); \r
1056 if(bDrawDither) glDisable(GL_DITHER); \r
1057\r
1058 gTexName=gTexBlurName;\r
1059 glBindTexture(GL_TEXTURE_2D, gTexName);\r
1060\r
1061 glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // get back buffer in texture\r
1062 0,\r
1063 0,\r
1064 0,\r
1065 0,\r
1066 iResX,iResY);\r
1067\r
1068 vertex[0].x=0;\r
1069 vertex[0].y=PSXDisplay.DisplayMode.y;\r
1070 vertex[1].x=PSXDisplay.DisplayMode.x;\r
1071 vertex[1].y=PSXDisplay.DisplayMode.y;\r
1072 vertex[2].x=PSXDisplay.DisplayMode.x;\r
1073 vertex[2].y=0;\r
1074 vertex[3].x=0;\r
1075 vertex[3].y=0;\r
1076 vertex[0].sow=0;\r
1077 vertex[0].tow=0;\r
1078\r
1079#ifdef OWNSCALE\r
1080 vertex[1].sow=((GLfloat)iFTexA)/256.0f;\r
1081 vertex[2].tow=((GLfloat)iFTexB)/256.0f;\r
1082#else\r
1083 vertex[1].sow=iFTexA;\r
1084 vertex[2].tow=iFTexB;\r
1085#endif\r
1086 vertex[1].tow=0;\r
1087 vertex[2].sow=vertex[1].sow;\r
1088 vertex[3].sow=0;\r
1089 vertex[3].tow=vertex[2].tow;\r
1090 \r
1091 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); \r
1092 vertex[0].c.lcol=0x7fffffff;\r
1093 SETCOL(vertex[0]); \r
1094\r
1095 DrawMultiBlur(); // draw the backbuffer texture to create blur effect\r
1096\r
1097 glEnable(GL_ALPHA_TEST);\r
1098 glEnable(GL_SCISSOR_TEST);\r
1099 if(iZBufferDepth) glEnable(GL_DEPTH_TEST); \r
1100 if(bDrawDither) glEnable(GL_DITHER); \r
1101 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT); \r
1102\r
1103 if(bKeepRatio)\r
1104 glViewport(rRatioRect.left, // re-init viewport\r
1105 iResY-(rRatioRect.top+rRatioRect.bottom),\r
1106 rRatioRect.right, \r
1107 rRatioRect.bottom); \r
1108}\r
1109\r
1110////////////////////////////////////////////////////////////////////////\r
1111// "unblur" repairs the backbuffer after a blur\r
1112\r
1113void UnBlurBackBuffer(void)\r
1114{\r
1115 if(!gTexBlurName) return;\r
1116\r
1117 if(bKeepRatio) glViewport(0,0,iResX,iResY);\r
1118\r
1119 glDisable(GL_SCISSOR_TEST);\r
1120 glDisable(GL_ALPHA_TEST);\r
1121 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}\r
1122 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}\r
1123 if(iZBufferDepth) glDisable(GL_DEPTH_TEST); \r
1124 if(bDrawDither) glDisable(GL_DITHER); \r
1125\r
1126 gTexName=gTexBlurName;\r
1127 glBindTexture(GL_TEXTURE_2D, gTexName);\r
1128\r
1129 vertex[0].x=0;\r
1130 vertex[0].y=PSXDisplay.DisplayMode.y;\r
1131 vertex[1].x=PSXDisplay.DisplayMode.x;\r
1132 vertex[1].y=PSXDisplay.DisplayMode.y;\r
1133 vertex[2].x=PSXDisplay.DisplayMode.x;\r
1134 vertex[2].y=0;\r
1135 vertex[3].x=0;\r
1136 vertex[3].y=0;\r
1137 vertex[0].sow=0;\r
1138 vertex[0].tow=0;\r
1139#ifdef OWNSCALE\r
1140 vertex[1].sow=((GLfloat)iFTexA)/256.0f;\r
1141 vertex[2].tow=((GLfloat)iFTexB)/256.0f;\r
1142#else\r
1143 vertex[1].sow=iFTexA;\r
1144 vertex[2].tow=iFTexB;\r
1145#endif\r
1146 vertex[1].tow=0;\r
1147 vertex[2].sow=vertex[1].sow;\r
1148 vertex[3].sow=0;\r
1149 vertex[3].tow=vertex[2].tow;\r
1150 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); \r
1151 vertex[0].c.lcol=0xffffffff;\r
1152 SETCOL(vertex[0]); \r
1153\r
1154 // simply draw the backbuffer texture (without blur)\r
1155 XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);\r
1156\r
1157 glEnable(GL_ALPHA_TEST);\r
1158 glEnable(GL_SCISSOR_TEST);\r
1159 if(iZBufferDepth) glEnable(GL_DEPTH_TEST); \r
1160 if(bDrawDither) glEnable(GL_DITHER); // dither mode\r
1161 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT); \r
1162\r
1163 if(bKeepRatio)\r
1164 glViewport(rRatioRect.left,\r
1165 iResY-(rRatioRect.top+rRatioRect.bottom),\r
1166 rRatioRect.right, \r
1167 rRatioRect.bottom); // init viewport\r
1168}\r
1169\r
1170////////////////////////////////////////////////////////////////////////\r
1171// Update display (swap buffers)... called in interlaced mode on \r
1172// every emulated vsync, otherwise whenever the displayed screen region\r
1173// has been changed\r
1174////////////////////////////////////////////////////////////////////////\r
1175\r
1176int iLastRGB24=0; // special vars for checking when to skip two display updates\r
1177int iSkipTwo=0;\r
1178\r
1179void updateDisplay(void) // UPDATE DISPLAY\r
1180{\r
1181 BOOL bBlur=FALSE;\r
1182\r
1183 bFakeFrontBuffer=FALSE;\r
1184 bRenderFrontBuffer=FALSE;\r
1185\r
1186 if(iRenderFVR) // frame buffer read fix mode still active?\r
1187 {\r
1188 iRenderFVR--; // -> if some frames in a row without read access: turn off mode\r
1189 if(!iRenderFVR) bFullVRam=FALSE;\r
1190 }\r
1191\r
1192 if(iLastRGB24 && iLastRGB24!=PSXDisplay.RGB24+1) // (mdec) garbage check\r
1193 {\r
1194 iSkipTwo=2; // -> skip two frames to avoid garbage if color mode changes\r
1195 }\r
1196 iLastRGB24=0;\r
1197\r
1198 if(PSXDisplay.RGB24)// && !bNeedUploadAfter) // (mdec) upload wanted?\r
1199 {\r
1200 PrepareFullScreenUpload(-1);\r
1201 UploadScreen(PSXDisplay.Interlaced); // -> upload whole screen from psx vram\r
1202 bNeedUploadTest=FALSE;\r
1203 bNeedInterlaceUpdate=FALSE;\r
1204 bNeedUploadAfter=FALSE;\r
1205 bNeedRGB24Update=FALSE;\r
1206 }\r
1207 else\r
1208 if(bNeedInterlaceUpdate) // smaller upload?\r
1209 {\r
1210 bNeedInterlaceUpdate=FALSE;\r
1211 xrUploadArea=xrUploadAreaIL; // -> upload this rect\r
1212 UploadScreen(TRUE);\r
1213 }\r
1214\r
1215 if(dwActFixes&512) bCheckFF9G4(NULL); // special game fix for FF9 \r
1216\r
1217 if(PreviousPSXDisplay.Range.x0|| // paint black borders around display area, if needed\r
1218 PreviousPSXDisplay.Range.y0)\r
1219 PaintBlackBorders();\r
1220\r
1221 if(PSXDisplay.Disabled) // display disabled?\r
1222 {\r
1223 // moved here\r
1224 glDisable(GL_SCISSOR_TEST); \r
1225 glClearColor(0,0,0,128); // -> clear whole backbuffer\r
1226 glClear(uiBufferBits);\r
1227 glEnable(GL_SCISSOR_TEST); \r
1228 gl_z=0.0f;\r
1229 bDisplayNotSet = TRUE;\r
1230 }\r
1231\r
1232 if(iSkipTwo) // we are in skipping mood?\r
1233 {\r
1234 iSkipTwo--;\r
1235 iDrawnSomething=0; // -> simply lie about something drawn\r
1236 }\r
1237\r
1238 if(iBlurBuffer && !bSkipNextFrame) // "blur display" activated?\r
1239 {BlurBackBuffer();bBlur=TRUE;} // -> blur it\r
1240\r
1241 if(iUseScanLines) SetScanLines(); // "scan lines" activated? do it\r
1242\r
1243 if(usCursorActive) ShowGunCursor(); // "gun cursor" wanted? show 'em\r
1244\r
1245 if(dwActFixes&128) // special FPS limitation mode?\r
1246 {\r
1247 if(bUseFrameLimit) PCFrameCap(); // -> ok, do it\r
1248 if(bUseFrameSkip || ulKeybits&KEY_SHOWFPS) \r
1249 PCcalcfps(); \r
1250 }\r
1251\r
1252 if(gTexPicName) DisplayPic(); // some gpu info picture active? display it\r
1253\r
1254 if(bSnapShot) DoSnapShot(); // snapshot key pressed? cheeeese :)\r
1255\r
1256 if(ulKeybits&KEY_SHOWFPS) // wanna see FPS?\r
1257 {\r
1258 sprintf(szDispBuf,"%06.1f",fps_cur);\r
1259 DisplayText(); // -> show it\r
1260 }\r
1261\r
1262 //----------------------------------------------------//\r
1263 // main buffer swapping (well, or skip it)\r
1264\r
1265 if(bUseFrameSkip) // frame skipping active ?\r
1266 {\r
1267 if(!bSkipNextFrame) \r
1268 {\r
1269 if(iDrawnSomething)\r
1270 glXSwapBuffers(display,window);\r
1271 }\r
1272 if(dwActFixes&0x180) // -> special old frame skipping: skip max one in a row\r
1273 {\r
1274 if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) \r
1275 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}\r
1276 else bSkipNextFrame = FALSE;\r
1277 }\r
1278 else FrameSkip();\r
1279 }\r
1280 else // no skip ?\r
1281 {\r
1282 if(iDrawnSomething)\r
1283 glXSwapBuffers(display,window);\r
1284 }\r
1285\r
1286 iDrawnSomething=0;\r
1287\r
1288 //----------------------------------------------------//\r
1289\r
1290 if(lClearOnSwap) // clear buffer after swap?\r
1291 {\r
1292 GLclampf g,b,r;\r
1293\r
1294 if(bDisplayNotSet) // -> set new vals\r
1295 SetOGLDisplaySettings(1);\r
1296\r
1297 g=((GLclampf)GREEN(lClearOnSwapColor))/255.0f; // -> get col\r
1298 b=((GLclampf)BLUE(lClearOnSwapColor))/255.0f;\r
1299 r=((GLclampf)RED(lClearOnSwapColor))/255.0f;\r
1300 \r
1301 glDisable(GL_SCISSOR_TEST); \r
1302 glClearColor(r,g,b,128); // -> clear \r
1303 glClear(uiBufferBits);\r
1304 glEnable(GL_SCISSOR_TEST); \r
1305 lClearOnSwap=0; // -> done\r
1306 }\r
1307 else \r
1308 {\r
1309 if(bBlur) UnBlurBackBuffer(); // unblur buff, if blurred before\r
1310\r
1311 if(iZBufferDepth) // clear zbuffer as well (if activated)\r
1312 {\r
1313 glDisable(GL_SCISSOR_TEST); \r
1314 glClear(GL_DEPTH_BUFFER_BIT);\r
1315 glEnable(GL_SCISSOR_TEST); \r
1316 }\r
1317 }\r
1318 gl_z=0.0f;\r
1319\r
1320 //----------------------------------------------------//\r
1321 // additional uploads immediatly after swapping\r
1322\r
1323 if(bNeedUploadAfter) // upload wanted?\r
1324 {\r
1325 bNeedUploadAfter=FALSE; \r
1326 bNeedUploadTest=FALSE;\r
1327 UploadScreen(-1); // -> upload\r
1328 }\r
1329 \r
1330 if(bNeedUploadTest)\r
1331 {\r
1332 bNeedUploadTest=FALSE;\r
1333 if(PSXDisplay.InterlacedTest &&\r
1334 //iOffscreenDrawing>2 &&\r
1335 PreviousPSXDisplay.DisplayPosition.x==PSXDisplay.DisplayPosition.x &&\r
1336 PreviousPSXDisplay.DisplayEnd.x==PSXDisplay.DisplayEnd.x &&\r
1337 PreviousPSXDisplay.DisplayPosition.y==PSXDisplay.DisplayPosition.y &&\r
1338 PreviousPSXDisplay.DisplayEnd.y==PSXDisplay.DisplayEnd.y)\r
1339 {\r
1340 PrepareFullScreenUpload(TRUE);\r
1341 UploadScreen(TRUE);\r
1342 }\r
1343 }\r
1344\r
1345 //----------------------------------------------------//\r
1346 // rumbling (main emu pad effect)\r
1347\r
1348 if(iRumbleTime) // shake screen by modifying view port\r
1349 {\r
1350 int i1=0,i2=0,i3=0,i4=0;\r
1351\r
1352 iRumbleTime--;\r
1353 if(iRumbleTime) \r
1354 {\r
1355 i1=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
1356 i2=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
1357 i3=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
1358 i4=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
1359 }\r
1360\r
1361 glViewport(rRatioRect.left+i1, \r
1362 iResY-(rRatioRect.top+rRatioRect.bottom)+i2,\r
1363 rRatioRect.right+i3, \r
1364 rRatioRect.bottom+i4); \r
1365 }\r
1366\r
1367 if(ulKeybits&KEY_RESETTEXSTORE) ResetStuff(); // reset on gpu mode changes? do it before next frame is filled\r
1368}\r
1369\r
1370////////////////////////////////////////////////////////////////////////\r
1371// update front display: smaller update func, if something has changed \r
1372// in the frontbuffer... dirty, but hey... real men know no pain\r
1373////////////////////////////////////////////////////////////////////////\r
1374\r
1375void updateFrontDisplay(void)\r
1376{\r
1377 if(PreviousPSXDisplay.Range.x0||\r
1378 PreviousPSXDisplay.Range.y0)\r
1379 PaintBlackBorders();\r
1380\r
1381 if(iBlurBuffer) BlurBackBuffer();\r
1382\r
1383 if(iUseScanLines) SetScanLines();\r
1384\r
1385 if(usCursorActive) ShowGunCursor();\r
1386\r
1387 bFakeFrontBuffer=FALSE;\r
1388 bRenderFrontBuffer=FALSE;\r
1389\r
1390 if(gTexPicName) DisplayPic();\r
1391 if(ulKeybits&KEY_SHOWFPS) DisplayText();\r
1392\r
1393 if(iDrawnSomething) // linux:\r
1394 glXSwapBuffers(display,window);\r
1395\r
1396 if(iBlurBuffer) UnBlurBackBuffer();\r
1397}\r
1398 \r
1399////////////////////////////////////////////////////////////////////////\r
1400// check if update needed\r
1401////////////////////////////////////////////////////////////////////////\r
1402\r
1403void ChangeDispOffsetsX(void) // CENTER X\r
1404{\r
1405 int lx,l;short sO;\r
1406\r
1407 if(!PSXDisplay.Range.x1) return; // some range given?\r
1408\r
1409 l=PSXDisplay.DisplayMode.x;\r
1410\r
1411 l*=(int)PSXDisplay.Range.x1; // some funky calculation\r
1412 l/=2560;lx=l;l&=0xfffffff8;\r
1413 \r
1414 if(l==PreviousPSXDisplay.Range.x1) return; // some change?\r
1415\r
1416 sO=PreviousPSXDisplay.Range.x0; // store old\r
1417\r
1418 if(lx>=PSXDisplay.DisplayMode.x) // range bigger?\r
1419 {\r
1420 PreviousPSXDisplay.Range.x1= // -> take display width\r
1421 PSXDisplay.DisplayMode.x;\r
1422 PreviousPSXDisplay.Range.x0=0; // -> start pos is 0\r
1423 }\r
1424 else // range smaller? center it\r
1425 {\r
1426 PreviousPSXDisplay.Range.x1=l; // -> store width (8 pixel aligned)\r
1427 PreviousPSXDisplay.Range.x0= // -> calc start pos\r
1428 (PSXDisplay.Range.x0-500)/8;\r
1429 if(PreviousPSXDisplay.Range.x0<0) // -> we don't support neg. values yet\r
1430 PreviousPSXDisplay.Range.x0=0;\r
1431\r
1432 if((PreviousPSXDisplay.Range.x0+lx)> // -> uhuu... that's too much\r
1433 PSXDisplay.DisplayMode.x)\r
1434 {\r
1435 PreviousPSXDisplay.Range.x0= // -> adjust start\r
1436 PSXDisplay.DisplayMode.x-lx;\r
1437 PreviousPSXDisplay.Range.x1+=lx-l; // -> adjust width\r
1438 } \r
1439 }\r
1440\r
1441 if(sO!=PreviousPSXDisplay.Range.x0) // something changed?\r
1442 {\r
1443 bDisplayNotSet=TRUE; // -> recalc display stuff\r
1444 }\r
1445}\r
1446\r
1447////////////////////////////////////////////////////////////////////////\r
1448\r
1449void ChangeDispOffsetsY(void) // CENTER Y\r
1450{\r
1451 int iT;short sO; // store previous y size\r
1452\r
1453 if(PSXDisplay.PAL) iT=48; else iT=28; // different offsets on PAL/NTSC\r
1454\r
1455 if(PSXDisplay.Range.y0>=iT) // crossed the security line? :)\r
1456 {\r
1457 PreviousPSXDisplay.Range.y1= // -> store width\r
1458 PSXDisplay.DisplayModeNew.y;\r
1459 \r
1460 sO=(PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double; // -> calc offset\r
1461 if(sO<0) sO=0;\r
1462\r
1463 PSXDisplay.DisplayModeNew.y+=sO; // -> add offset to y size, too\r
1464 }\r
1465 else sO=0; // else no offset\r
1466\r
1467 if(sO!=PreviousPSXDisplay.Range.y0) // something changed?\r
1468 {\r
1469 PreviousPSXDisplay.Range.y0=sO;\r
1470 bDisplayNotSet=TRUE; // -> recalc display stuff\r
1471 }\r
1472}\r
1473\r
1474////////////////////////////////////////////////////////////////////////\r
1475// Aspect ratio of ogl screen: simply adjusting ogl view port\r
1476////////////////////////////////////////////////////////////////////////\r
1477\r
1478void SetAspectRatio(void)\r
1479{\r
1480 float xs,ys,s;RECT r;\r
1481\r
1482 if(!PSXDisplay.DisplayModeNew.x) return;\r
1483 if(!PSXDisplay.DisplayModeNew.y) return;\r
1484\r
1485 xs=(float)iResX/(float)PSXDisplay.DisplayModeNew.x;\r
1486 ys=(float)iResY/(float)PSXDisplay.DisplayModeNew.y;\r
1487\r
1488 s=min(xs,ys);\r
1489 r.right =(int)((float)PSXDisplay.DisplayModeNew.x*s);\r
1490 r.bottom=(int)((float)PSXDisplay.DisplayModeNew.y*s);\r
1491 if(r.right > iResX) r.right = iResX;\r
1492 if(r.bottom > iResY) r.bottom = iResY;\r
1493 if(r.right < 1) r.right = 1;\r
1494 if(r.bottom < 1) r.bottom = 1;\r
1495\r
1496 r.left = (iResX-r.right)/2;\r
1497 r.top = (iResY-r.bottom)/2;\r
1498\r
1499 if(r.bottom<rRatioRect.bottom ||\r
1500 r.right <rRatioRect.right)\r
1501 {\r
1502 RECT rC;\r
1503 glClearColor(0,0,0,128); \r
1504\r
1505 if(r.right <rRatioRect.right)\r
1506 {\r
1507 rC.left=0;\r
1508 rC.top=0;\r
1509 rC.right=r.left;\r
1510 rC.bottom=iResY;\r
1511 glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
1512 glClear(uiBufferBits);\r
1513 rC.left=iResX-rC.right;\r
1514 glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
1515 glClear(uiBufferBits);\r
1516 }\r
1517\r
1518 if(r.bottom <rRatioRect.bottom)\r
1519 {\r
1520 rC.left=0;\r
1521 rC.top=0;\r
1522 rC.right=iResX;\r
1523 rC.bottom=r.top;\r
1524 glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
1525 glClear(uiBufferBits);\r
1526 rC.top=iResY-rC.bottom;\r
1527 glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
1528 glClear(uiBufferBits);\r
1529 }\r
1530 \r
1531 bSetClip=TRUE;\r
1532 bDisplayNotSet=TRUE;\r
1533 }\r
1534\r
1535 rRatioRect=r;\r
1536\r
1537\r
1538 glViewport(rRatioRect.left,\r
1539 iResY-(rRatioRect.top+rRatioRect.bottom),\r
1540 rRatioRect.right,\r
1541 rRatioRect.bottom); // init viewport\r
1542}\r
1543\r
1544////////////////////////////////////////////////////////////////////////\r
1545// big ass check, if an ogl swap buffer is needed\r
1546////////////////////////////////////////////////////////////////////////\r
1547\r
1548void updateDisplayIfChanged(void)\r
1549{\r
1550 BOOL bUp;\r
1551\r
1552 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) && \r
1553 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))\r
1554 {\r
1555 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) && \r
1556 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) \r
1557 return; // nothing has changed? fine, no swap buffer needed\r
1558 }\r
1559 else // some res change?\r
1560 {\r
1561 glLoadIdentity();\r
1562 glOrtho(0,PSXDisplay.DisplayModeNew.x, // -> new psx resolution\r
1563 PSXDisplay.DisplayModeNew.y, 0, -1, 1);\r
1564 if(bKeepRatio) SetAspectRatio();\r
1565 }\r
1566\r
1567 bDisplayNotSet = TRUE; // re-calc offsets/display area\r
1568 \r
1569 bUp=FALSE;\r
1570 if(PSXDisplay.RGB24!=PSXDisplay.RGB24New) // clean up textures, if rgb mode change (usually mdec on/off)\r
1571 {\r
1572 PreviousPSXDisplay.RGB24=0; // no full 24 frame uploaded yet\r
1573 ResetTextureArea(FALSE);\r
1574 bUp=TRUE;\r
1575 }\r
1576\r
1577 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos\r
1578 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;\r
1579 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;\r
1580 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;\r
1581 \r
1582 PSXDisplay.DisplayEnd.x= // calc new ends\r
1583 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
1584 PSXDisplay.DisplayEnd.y=\r
1585 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
1586 PreviousPSXDisplay.DisplayEnd.x=\r
1587 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
1588 PreviousPSXDisplay.DisplayEnd.y=\r
1589 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
1590\r
1591 ChangeDispOffsetsX();\r
1592\r
1593 if(iFrameLimit==2) SetAutoFrameCap(); // set new fps limit vals (depends on interlace)\r
1594\r
1595 if(bUp) updateDisplay(); // yeah, real update (swap buffer)\r
1596}\r
1597\r
1598////////////////////////////////////////////////////////////////////////\r
1599// swap update check (called by psx vsync function)\r
1600////////////////////////////////////////////////////////////////////////\r
1601\r
1602BOOL bSwapCheck(void)\r
1603{\r
1604 static int iPosCheck=0;\r
1605 static PSXPoint_t pO;\r
1606 static PSXPoint_t pD;\r
1607 static int iDoAgain=0;\r
1608\r
1609 if(PSXDisplay.DisplayPosition.x==pO.x &&\r
1610 PSXDisplay.DisplayPosition.y==pO.y &&\r
1611 PSXDisplay.DisplayEnd.x==pD.x &&\r
1612 PSXDisplay.DisplayEnd.y==pD.y)\r
1613 iPosCheck++;\r
1614 else iPosCheck=0;\r
1615\r
1616 pO=PSXDisplay.DisplayPosition;\r
1617 pD=PSXDisplay.DisplayEnd;\r
1618\r
1619 if(iPosCheck<=4) return FALSE;\r
1620\r
1621 iPosCheck=4;\r
1622\r
1623 if(PSXDisplay.Interlaced) return FALSE;\r
1624\r
1625 if (bNeedInterlaceUpdate||\r
1626 bNeedRGB24Update ||\r
1627 bNeedUploadAfter|| \r
1628 bNeedUploadTest || \r
1629 iDoAgain\r
1630 )\r
1631 {\r
1632 iDoAgain=0;\r
1633 if(bNeedUploadAfter) \r
1634 iDoAgain=1;\r
1635 if(bNeedUploadTest && PSXDisplay.InterlacedTest)\r
1636 iDoAgain=1;\r
1637\r
1638 bDisplayNotSet = TRUE;\r
1639 updateDisplay();\r
1640\r
1641 PreviousPSXDisplay.DisplayPosition.x=PSXDisplay.DisplayPosition.x;\r
1642 PreviousPSXDisplay.DisplayPosition.y=PSXDisplay.DisplayPosition.y;\r
1643 PreviousPSXDisplay.DisplayEnd.x=PSXDisplay.DisplayEnd.x;\r
1644 PreviousPSXDisplay.DisplayEnd.y=PSXDisplay.DisplayEnd.y;\r
1645 pO=PSXDisplay.DisplayPosition;\r
1646 pD=PSXDisplay.DisplayEnd;\r
1647\r
1648 return TRUE;\r
1649 }\r
1650\r
1651 return FALSE;\r
1652} \r
1653\r
1654////////////////////////////////////////////////////////////////////////\r
1655// gun cursor func: player=0-7, x=0-511, y=0-255\r
1656////////////////////////////////////////////////////////////////////////\r
1657\r
1658void CALLBACK GPUcursor(int iPlayer,int x,int y)\r
1659{\r
1660 if(iPlayer<0) return;\r
1661 if(iPlayer>7) return;\r
1662\r
1663 usCursorActive|=(1<<iPlayer);\r
1664\r
1665 if(x<0) x=0;\r
1666 if(x>iGPUHeightMask) x=iGPUHeightMask;\r
1667 if(y<0) y=0;\r
1668 if(y>255) y=255;\r
1669\r
1670 ptCursorPoint[iPlayer].x=x;\r
1671 ptCursorPoint[iPlayer].y=y;\r
1672}\r
1673\r
1674////////////////////////////////////////////////////////////////////////\r
1675// update lace is called every VSync. Basically we limit frame rate \r
1676// here, and in interlaced mode we swap ogl display buffers.\r
1677////////////////////////////////////////////////////////////////////////\r
1678\r
1679static unsigned short usFirstPos=2;\r
1680\r
1681void CALLBACK GPUupdateLace(void)\r
1682{\r
1683 if(!(dwActFixes&0x1000)) \r
1684 STATUSREG^=0x80000000; // interlaced bit toggle, if the CC game fix is not active (see gpuReadStatus)\r
1685\r
1686 if(!(dwActFixes&128)) // normal frame limit func\r
1687 CheckFrameRate();\r
1688\r
1689 if(iOffscreenDrawing==4) // special check if high offscreen drawing is on\r
1690 {\r
1691 if(bSwapCheck()) return;\r
1692 }\r
1693\r
1694 if(PSXDisplay.Interlaced) // interlaced mode?\r
1695 {\r
1696 if(PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)\r
1697 {\r
1698 updateDisplay(); // -> swap buffers (new frame)\r
1699 }\r
1700 }\r
1701 else if(bRenderFrontBuffer) // no interlace mode? and some stuff in front has changed?\r
1702 {\r
1703 updateFrontDisplay(); // -> update front buffer\r
1704 }\r
1705 else if(usFirstPos==1) // initial updates (after startup)\r
1706 {\r
1707 updateDisplay();\r
1708 }\r
1709}\r
1710\r
1711////////////////////////////////////////////////////////////////////////\r
1712// process read request from GPU status register\r
1713////////////////////////////////////////////////////////////////////////\r
1714\r
1715uint32_t CALLBACK GPUreadStatus(void)\r
1716{\r
1717 if(dwActFixes&0x1000) // CC game fix\r
1718 {\r
1719 static int iNumRead=0;\r
1720 if((iNumRead++)==2)\r
1721 {\r
1722 iNumRead=0;\r
1723 STATUSREG^=0x80000000; // interlaced bit toggle... we do it on every second read status... needed by some games (like ChronoCross)\r
1724 }\r
1725 }\r
1726\r
1727 if(iFakePrimBusy) // 27.10.2007 - emulating some 'busy' while drawing... pfff... not perfect, but since our emulated dma is not done in an extra thread...\r
1728 {\r
1729 iFakePrimBusy--;\r
1730\r
1731 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims\r
1732 {\r
1733 GPUIsBusy;\r
1734 GPUIsNotReadyForCommands;\r
1735 }\r
1736 else\r
1737 {\r
1738 GPUIsIdle;\r
1739 GPUIsReadyForCommands;\r
1740 }\r
1741 }\r
1742\r
1743 return STATUSREG;\r
1744}\r
1745\r
1746////////////////////////////////////////////////////////////////////////\r
1747// processes data send to GPU status register\r
1748// these are always single packet commands.\r
1749////////////////////////////////////////////////////////////////////////\r
1750\r
1751void CALLBACK GPUwriteStatus(uint32_t gdata)\r
1752{\r
1753 uint32_t lCommand=(gdata>>24)&0xff;\r
1754 \r
1755 ulStatusControl[lCommand]=gdata;\r
1756\r
1757 switch(lCommand)\r
1758 {\r
1759 //--------------------------------------------------//\r
1760 // reset gpu\r
1761 case 0x00:\r
1762 memset(ulGPUInfoVals, 0x00, 16 * sizeof(uint32_t));\r
1763 lGPUstatusRet = 0x14802000;\r
1764 PSXDisplay.Disabled=1;\r
1765 iDataWriteMode=iDataReadMode=DR_NORMAL;\r
1766 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;\r
1767 drawX=drawY=0;drawW=drawH=0;\r
1768 sSetMask=0;lSetMask=0;bCheckMask=FALSE;iSetMask=0;\r
1769 usMirror=0;\r
1770 GlobalTextAddrX=0;GlobalTextAddrY=0;\r
1771 GlobalTextTP=0;GlobalTextABR=0;\r
1772 PSXDisplay.RGB24=FALSE;\r
1773 PSXDisplay.Interlaced=FALSE;\r
1774 bUsingTWin = FALSE;\r
1775 return;\r
1776\r
1777 // dis/enable display\r
1778 case 0x03: \r
1779 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;\r
1780 PSXDisplay.Disabled = (gdata & 1);\r
1781\r
1782 if(PSXDisplay.Disabled) \r
1783 STATUSREG|=GPUSTATUS_DISPLAYDISABLED;\r
1784 else STATUSREG&=~GPUSTATUS_DISPLAYDISABLED;\r
1785\r
1786 if (iOffscreenDrawing==4 &&\r
1787 PreviousPSXDisplay.Disabled && \r
1788 !(PSXDisplay.Disabled))\r
1789 {\r
1790\r
1791 if(!PSXDisplay.RGB24)\r
1792 {\r
1793 PrepareFullScreenUpload(TRUE);\r
1794 UploadScreen(TRUE); \r
1795 updateDisplay();\r
1796 }\r
1797 }\r
1798\r
1799 return;\r
1800\r
1801 // setting transfer mode\r
1802 case 0x04:\r
1803 gdata &= 0x03; // only want the lower two bits\r
1804\r
1805 iDataWriteMode=iDataReadMode=DR_NORMAL;\r
1806 if(gdata==0x02) iDataWriteMode=DR_VRAMTRANSFER;\r
1807 if(gdata==0x03) iDataReadMode =DR_VRAMTRANSFER;\r
1808\r
1809 STATUSREG&=~GPUSTATUS_DMABITS; // clear the current settings of the DMA bits\r
1810 STATUSREG|=(gdata << 29); // set the DMA bits according to the received data\r
1811\r
1812 return;\r
1813\r
1814 // setting display position\r
1815 case 0x05: \r
1816 {\r
1817 short sx=(short)(gdata & 0x3ff);\r
1818 short sy;\r
1819\r
1820 if(iGPUHeight==1024)\r
1821 {\r
1822 if(dwGPUVersion==2) \r
1823 sy = (short)((gdata>>12)&0x3ff);\r
1824 else sy = (short)((gdata>>10)&0x3ff);\r
1825 }\r
1826 else sy = (short)((gdata>>10)&0x3ff); // really: 0x1ff, but we adjust it later\r
1827\r
1828 if (sy & 0x200) \r
1829 {\r
1830 sy|=0xfc00;\r
1831 PreviousPSXDisplay.DisplayModeNew.y=sy/PSXDisplay.Double;\r
1832 sy=0;\r
1833 }\r
1834 else PreviousPSXDisplay.DisplayModeNew.y=0;\r
1835\r
1836 if(sx>1000) sx=0;\r
1837\r
1838 if(usFirstPos)\r
1839 {\r
1840 usFirstPos--;\r
1841 if(usFirstPos)\r
1842 {\r
1843 PreviousPSXDisplay.DisplayPosition.x = sx;\r
1844 PreviousPSXDisplay.DisplayPosition.y = sy;\r
1845 PSXDisplay.DisplayPosition.x = sx;\r
1846 PSXDisplay.DisplayPosition.y = sy;\r
1847 }\r
1848 }\r
1849\r
1850 if(dwActFixes&8) \r
1851 {\r
1852 if((!PSXDisplay.Interlaced) &&\r
1853 PreviousPSXDisplay.DisplayPosition.x == sx &&\r
1854 PreviousPSXDisplay.DisplayPosition.y == sy)\r
1855 return;\r
1856\r
1857 PSXDisplay.DisplayPosition.x = PreviousPSXDisplay.DisplayPosition.x;\r
1858 PSXDisplay.DisplayPosition.y = PreviousPSXDisplay.DisplayPosition.y;\r
1859 PreviousPSXDisplay.DisplayPosition.x = sx;\r
1860 PreviousPSXDisplay.DisplayPosition.y = sy;\r
1861 }\r
1862 else\r
1863 {\r
1864 if((!PSXDisplay.Interlaced) &&\r
1865 PSXDisplay.DisplayPosition.x == sx &&\r
1866 PSXDisplay.DisplayPosition.y == sy)\r
1867 return;\r
1868 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;\r
1869 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;\r
1870 PSXDisplay.DisplayPosition.x = sx;\r
1871 PSXDisplay.DisplayPosition.y = sy;\r
1872 }\r
1873\r
1874 PSXDisplay.DisplayEnd.x=\r
1875 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
1876 PSXDisplay.DisplayEnd.y=\r
1877 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
1878\r
1879 PreviousPSXDisplay.DisplayEnd.x=\r
1880 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
1881 PreviousPSXDisplay.DisplayEnd.y=\r
1882 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
1883\r
1884 bDisplayNotSet = TRUE;\r
1885\r
1886 if (!(PSXDisplay.Interlaced))\r
1887 {\r
1888 updateDisplay();\r
1889 }\r
1890 else\r
1891 if(PSXDisplay.InterlacedTest && \r
1892 ((PreviousPSXDisplay.DisplayPosition.x != PSXDisplay.DisplayPosition.x)||\r
1893 (PreviousPSXDisplay.DisplayPosition.y != PSXDisplay.DisplayPosition.y)))\r
1894 PSXDisplay.InterlacedTest--;\r
1895 \r
1896 return;\r
1897 }\r
1898\r
1899 // setting width\r
1900 case 0x06:\r
1901\r
1902 PSXDisplay.Range.x0=gdata & 0x7ff; //0x3ff;\r
1903 PSXDisplay.Range.x1=(gdata>>12) & 0xfff;//0x7ff;\r
1904\r
1905 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;\r
1906\r
1907 ChangeDispOffsetsX();\r
1908\r
1909 return;\r
1910\r
1911 // setting height\r
1912 case 0x07:\r
1913\r
1914 PreviousPSXDisplay.Height = PSXDisplay.Height;\r
1915\r
1916 PSXDisplay.Range.y0=gdata & 0x3ff;\r
1917 PSXDisplay.Range.y1=(gdata>>10) & 0x3ff;\r
1918\r
1919 PSXDisplay.Height = PSXDisplay.Range.y1 - \r
1920 PSXDisplay.Range.y0 +\r
1921 PreviousPSXDisplay.DisplayModeNew.y;\r
1922\r
1923 if (PreviousPSXDisplay.Height != PSXDisplay.Height)\r
1924 {\r
1925 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;\r
1926 ChangeDispOffsetsY();\r
1927 updateDisplayIfChanged();\r
1928 }\r
1929 return;\r
1930 \r
1931 // setting display infos\r
1932 case 0x08:\r
1933\r
1934 PSXDisplay.DisplayModeNew.x = dispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];\r
1935\r
1936 if (gdata&0x04) PSXDisplay.Double=2;\r
1937 else PSXDisplay.Double=1;\r
1938 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;\r
1939\r
1940 ChangeDispOffsetsY();\r
1941 \r
1942 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC\r
1943 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor\r
1944 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace\r
1945\r
1946 STATUSREG&=~GPUSTATUS_WIDTHBITS; // clear the width bits\r
1947\r
1948 STATUSREG|=\r
1949 (((gdata & 0x03) << 17) | \r
1950 ((gdata & 0x40) << 10)); // set the width bits\r
1951\r
1952 PreviousPSXDisplay.InterlacedNew=FALSE;\r
1953 if (PSXDisplay.InterlacedNew)\r
1954 {\r
1955 if(!PSXDisplay.Interlaced)\r
1956 {\r
1957 PSXDisplay.InterlacedTest=2;\r
1958 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;\r
1959 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;\r
1960 PreviousPSXDisplay.InterlacedNew=TRUE;\r
1961 }\r
1962\r
1963 STATUSREG|=GPUSTATUS_INTERLACED;\r
1964 }\r
1965 else \r
1966 {\r
1967 PSXDisplay.InterlacedTest=0;\r
1968 STATUSREG&=~GPUSTATUS_INTERLACED;\r
1969 }\r
1970\r
1971 if (PSXDisplay.PAL)\r
1972 STATUSREG|=GPUSTATUS_PAL;\r
1973 else STATUSREG&=~GPUSTATUS_PAL;\r
1974\r
1975 if (PSXDisplay.Double==2)\r
1976 STATUSREG|=GPUSTATUS_DOUBLEHEIGHT;\r
1977 else STATUSREG&=~GPUSTATUS_DOUBLEHEIGHT;\r
1978\r
1979 if (PSXDisplay.RGB24New)\r
1980 STATUSREG|=GPUSTATUS_RGB24;\r
1981 else STATUSREG&=~GPUSTATUS_RGB24;\r
1982\r
1983 updateDisplayIfChanged();\r
1984\r
1985 return;\r
1986\r
1987 //--------------------------------------------------//\r
1988 // ask about GPU version and other stuff\r
1989 case 0x10: \r
1990\r
1991 gdata&=0xff;\r
1992\r
1993 switch(gdata) \r
1994 {\r
1995 case 0x02:\r
1996 GPUdataRet=ulGPUInfoVals[INFO_TW]; // tw infos\r
1997 return;\r
1998 case 0x03:\r
1999 GPUdataRet=ulGPUInfoVals[INFO_DRAWSTART]; // draw start\r
2000 return;\r
2001 case 0x04:\r
2002 GPUdataRet=ulGPUInfoVals[INFO_DRAWEND]; // draw end\r
2003 return;\r
2004 case 0x05:\r
2005 case 0x06:\r
2006 GPUdataRet=ulGPUInfoVals[INFO_DRAWOFF]; // draw offset\r
2007 return;\r
2008 case 0x07:\r
2009 if(dwGPUVersion==2)\r
2010 GPUdataRet=0x01;\r
2011 else GPUdataRet=0x02; // gpu type\r
2012 return;\r
2013 case 0x08:\r
2014 case 0x0F: // some bios addr?\r
2015 GPUdataRet=0xBFC03720;\r
2016 return;\r
2017 }\r
2018 return;\r
2019 //--------------------------------------------------//\r
2020 }\r
2021}\r
2022\r
2023////////////////////////////////////////////////////////////////////////\r
2024// vram read/write helpers\r
2025////////////////////////////////////////////////////////////////////////\r
2026\r
2027BOOL bNeedWriteUpload=FALSE;\r
2028\r
2029__inline void FinishedVRAMWrite(void)\r
2030{\r
2031 if(bNeedWriteUpload)\r
2032 {\r
2033 bNeedWriteUpload=FALSE;\r
2034 CheckWriteUpdate();\r
2035 }\r
2036\r
2037 // set register to NORMAL operation\r
2038 iDataWriteMode = DR_NORMAL;\r
2039\r
2040 // reset transfer values, to prevent mis-transfer of data\r
2041 VRAMWrite.ColsRemaining = 0;\r
2042 VRAMWrite.RowsRemaining = 0;\r
2043}\r
2044\r
2045__inline void FinishedVRAMRead(void)\r
2046{\r
2047 // set register to NORMAL operation\r
2048 iDataReadMode = DR_NORMAL;\r
2049 // reset transfer values, to prevent mis-transfer of data\r
2050 VRAMRead.x = 0;\r
2051 VRAMRead.y = 0;\r
2052 VRAMRead.Width = 0;\r
2053 VRAMRead.Height = 0;\r
2054 VRAMRead.ColsRemaining = 0;\r
2055 VRAMRead.RowsRemaining = 0;\r
2056\r
2057 // indicate GPU is no longer ready for VRAM data in the STATUS REGISTER\r
2058 STATUSREG&=~GPUSTATUS_READYFORVRAM;\r
2059}\r
2060\r
2061////////////////////////////////////////////////////////////////////////\r
2062// vram read check ex (reading from card's back/frontbuffer if needed...\r
2063// slow!)\r
2064////////////////////////////////////////////////////////////////////////\r
2065\r
2066void CheckVRamReadEx(int x, int y, int dx, int dy)\r
2067{\r
2068 unsigned short sArea;\r
2069 int ux,uy,udx,udy,wx,wy;\r
2070 unsigned short * p1, *p2;\r
2071 float XS,YS;\r
2072 unsigned char * ps;\r
2073 unsigned char * px;\r
2074 unsigned short s,sx;\r
2075\r
2076 if(STATUSREG&GPUSTATUS_RGB24) return;\r
2077\r
2078 if(((dx > PSXDisplay.DisplayPosition.x) &&\r
2079 (x < PSXDisplay.DisplayEnd.x) &&\r
2080 (dy > PSXDisplay.DisplayPosition.y) &&\r
2081 (y < PSXDisplay.DisplayEnd.y)))\r
2082 sArea=0;\r
2083 else\r
2084 if((!(PSXDisplay.InterlacedTest) &&\r
2085 (dx > PreviousPSXDisplay.DisplayPosition.x) &&\r
2086 (x < PreviousPSXDisplay.DisplayEnd.x) &&\r
2087 (dy > PreviousPSXDisplay.DisplayPosition.y) &&\r
2088 (y < PreviousPSXDisplay.DisplayEnd.y)))\r
2089 sArea=1;\r
2090 else \r
2091 {\r
2092 return;\r
2093 }\r
2094\r
2095 //////////////\r
2096\r
2097 if(iRenderFVR)\r
2098 {\r
2099 bFullVRam=TRUE;iRenderFVR=2;return;\r
2100 }\r
2101 bFullVRam=TRUE;iRenderFVR=2;\r
2102\r
2103 //////////////\r
2104\r
2105 p2=0;\r
2106\r
2107 if(sArea==0)\r
2108 {\r
2109 ux=PSXDisplay.DisplayPosition.x;\r
2110 uy=PSXDisplay.DisplayPosition.y;\r
2111 udx=PSXDisplay.DisplayEnd.x-ux;\r
2112 udy=PSXDisplay.DisplayEnd.y-uy;\r
2113 if((PreviousPSXDisplay.DisplayEnd.x-\r
2114 PreviousPSXDisplay.DisplayPosition.x)==udx &&\r
2115 (PreviousPSXDisplay.DisplayEnd.y-\r
2116 PreviousPSXDisplay.DisplayPosition.y)==udy)\r
2117 p2=(psxVuw + (1024*PreviousPSXDisplay.DisplayPosition.y) + \r
2118 PreviousPSXDisplay.DisplayPosition.x);\r
2119 }\r
2120 else\r
2121 {\r
2122 ux=PreviousPSXDisplay.DisplayPosition.x;\r
2123 uy=PreviousPSXDisplay.DisplayPosition.y;\r
2124 udx=PreviousPSXDisplay.DisplayEnd.x-ux;\r
2125 udy=PreviousPSXDisplay.DisplayEnd.y-uy;\r
2126 if((PSXDisplay.DisplayEnd.x-\r
2127 PSXDisplay.DisplayPosition.x)==udx &&\r
2128 (PSXDisplay.DisplayEnd.y-\r
2129 PSXDisplay.DisplayPosition.y)==udy)\r
2130 p2=(psxVuw + (1024*PSXDisplay.DisplayPosition.y) + \r
2131 PSXDisplay.DisplayPosition.x);\r
2132 }\r
2133\r
2134 p1=(psxVuw + (1024*uy) + ux);\r
2135 if(p1==p2) p2=0;\r
2136\r
2137 x=0;y=0;\r
2138 wx=dx=udx;wy=dy=udy;\r
2139\r
2140 if(udx<=0) return;\r
2141 if(udy<=0) return;\r
2142 if(dx<=0) return;\r
2143 if(dy<=0) return;\r
2144 if(wx<=0) return;\r
2145 if(wy<=0) return;\r
2146\r
2147 XS=(float)rRatioRect.right/(float)wx;\r
2148 YS=(float)rRatioRect.bottom/(float)wy;\r
2149\r
2150 dx=(int)((float)(dx)*XS);\r
2151 dy=(int)((float)(dy)*YS);\r
2152\r
2153 if(dx>iResX) dx=iResX;\r
2154 if(dy>iResY) dy=iResY;\r
2155\r
2156 if(dx<=0) return;\r
2157 if(dy<=0) return;\r
2158\r
2159 // ogl y adjust\r
2160 y=iResY-y-dy;\r
2161\r
2162 x+=rRatioRect.left;\r
2163 y-=rRatioRect.top;\r
2164\r
2165 if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;\r
2166\r
2167 if(!pGfxCardScreen)\r
2168 {\r
2169 glPixelStorei(GL_PACK_ALIGNMENT,1);\r
2170 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);\r
2171 }\r
2172\r
2173 ps=pGfxCardScreen;\r
2174 \r
2175 if(!sArea) glReadBuffer(GL_FRONT);\r
2176\r
2177 glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
2178 \r
2179 if(!sArea) glReadBuffer(GL_BACK);\r
2180\r
2181 s=0;\r
2182\r
2183 XS=(float)dx/(float)(udx);\r
2184 YS=(float)dy/(float)(udy+1);\r
2185 \r
2186 for(y=udy;y>0;y--)\r
2187 {\r
2188 for(x=0;x<udx;x++)\r
2189 {\r
2190 if(p1>=psxVuw && p1<psxVuw_eom)\r
2191 {\r
2192 px=ps+(3*((int)((float)x * XS))+\r
2193 (3*dx)*((int)((float)y*YS)));\r
2194 sx=(*px)>>3;px++;\r
2195 s=sx;\r
2196 sx=(*px)>>3;px++;\r
2197 s|=sx<<5;\r
2198 sx=(*px)>>3;\r
2199 s|=sx<<10;\r
2200 s&=~0x8000;\r
2201 *p1=s;\r
2202 }\r
2203 if(p2>=psxVuw && p2<psxVuw_eom) *p2=s;\r
2204\r
2205 p1++;\r
2206 if(p2) p2++;\r
2207 }\r
2208\r
2209 p1 += 1024 - udx;\r
2210 if(p2) p2 += 1024 - udx;\r
2211 }\r
2212}\r
2213\r
2214////////////////////////////////////////////////////////////////////////\r
2215// vram read check (reading from card's back/frontbuffer if needed... \r
2216// slow!)\r
2217////////////////////////////////////////////////////////////////////////\r
2218\r
2219void CheckVRamRead(int x, int y, int dx, int dy,BOOL bFront)\r
2220{\r
2221 unsigned short sArea;unsigned short * p;\r
2222 int ux,uy,udx,udy,wx,wy;float XS,YS;\r
2223 unsigned char * ps, * px;\r
2224 unsigned short s=0,sx;\r
2225\r
2226 if(STATUSREG&GPUSTATUS_RGB24) return;\r
2227\r
2228 if(((dx > PSXDisplay.DisplayPosition.x) &&\r
2229 (x < PSXDisplay.DisplayEnd.x) &&\r
2230 (dy > PSXDisplay.DisplayPosition.y) &&\r
2231 (y < PSXDisplay.DisplayEnd.y)))\r
2232 sArea=0;\r
2233 else\r
2234 if((!(PSXDisplay.InterlacedTest) &&\r
2235 (dx > PreviousPSXDisplay.DisplayPosition.x) &&\r
2236 (x < PreviousPSXDisplay.DisplayEnd.x) &&\r
2237 (dy > PreviousPSXDisplay.DisplayPosition.y) &&\r
2238 (y < PreviousPSXDisplay.DisplayEnd.y)))\r
2239 sArea=1;\r
2240 else \r
2241 {\r
2242 return;\r
2243 }\r
2244\r
2245 if(dwActFixes&0x40)\r
2246 {\r
2247 if(iRenderFVR)\r
2248 {\r
2249 bFullVRam=TRUE;iRenderFVR=2;return;\r
2250 }\r
2251 bFullVRam=TRUE;iRenderFVR=2;\r
2252 }\r
2253\r
2254 ux=x;uy=y;udx=dx;udy=dy;\r
2255\r
2256 if(sArea==0)\r
2257 {\r
2258 x -=PSXDisplay.DisplayPosition.x;\r
2259 dx-=PSXDisplay.DisplayPosition.x;\r
2260 y -=PSXDisplay.DisplayPosition.y;\r
2261 dy-=PSXDisplay.DisplayPosition.y;\r
2262 wx=PSXDisplay.DisplayEnd.x-PSXDisplay.DisplayPosition.x;\r
2263 wy=PSXDisplay.DisplayEnd.y-PSXDisplay.DisplayPosition.y;\r
2264 }\r
2265 else\r
2266 {\r
2267 x -=PreviousPSXDisplay.DisplayPosition.x;\r
2268 dx-=PreviousPSXDisplay.DisplayPosition.x;\r
2269 y -=PreviousPSXDisplay.DisplayPosition.y;\r
2270 dy-=PreviousPSXDisplay.DisplayPosition.y;\r
2271 wx=PreviousPSXDisplay.DisplayEnd.x-PreviousPSXDisplay.DisplayPosition.x;\r
2272 wy=PreviousPSXDisplay.DisplayEnd.y-PreviousPSXDisplay.DisplayPosition.y;\r
2273 }\r
2274 if(x<0) {ux-=x;x=0;}\r
2275 if(y<0) {uy-=y;y=0;}\r
2276 if(dx>wx) {udx-=(dx-wx);dx=wx;}\r
2277 if(dy>wy) {udy-=(dy-wy);dy=wy;}\r
2278 udx-=ux;\r
2279 udy-=uy;\r
2280 \r
2281 p=(psxVuw + (1024*uy) + ux);\r
2282\r
2283 if(udx<=0) return;\r
2284 if(udy<=0) return;\r
2285 if(dx<=0) return;\r
2286 if(dy<=0) return;\r
2287 if(wx<=0) return;\r
2288 if(wy<=0) return;\r
2289\r
2290 XS=(float)rRatioRect.right/(float)wx;\r
2291 YS=(float)rRatioRect.bottom/(float)wy;\r
2292\r
2293 dx=(int)((float)(dx)*XS);\r
2294 dy=(int)((float)(dy)*YS);\r
2295 x=(int)((float)x*XS);\r
2296 y=(int)((float)y*YS);\r
2297\r
2298 dx-=x;\r
2299 dy-=y;\r
2300\r
2301 if(dx>iResX) dx=iResX;\r
2302 if(dy>iResY) dy=iResY;\r
2303\r
2304 if(dx<=0) return;\r
2305 if(dy<=0) return;\r
2306\r
2307 // ogl y adjust\r
2308 y=iResY-y-dy;\r
2309\r
2310 x+=rRatioRect.left;\r
2311 y-=rRatioRect.top;\r
2312\r
2313 if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;\r
2314\r
2315 if(!pGfxCardScreen)\r
2316 {\r
2317 glPixelStorei(GL_PACK_ALIGNMENT,1);\r
2318 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);\r
2319 }\r
2320\r
2321 ps=pGfxCardScreen;\r
2322 \r
2323 if(bFront) glReadBuffer(GL_FRONT);\r
2324\r
2325 glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
2326 \r
2327 if(bFront) glReadBuffer(GL_BACK);\r
2328\r
2329 XS=(float)dx/(float)(udx);\r
2330 YS=(float)dy/(float)(udy+1);\r
2331 \r
2332 for(y=udy;y>0;y--)\r
2333 {\r
2334 for(x=0;x<udx;x++)\r
2335 {\r
2336 if(p>=psxVuw && p<psxVuw_eom)\r
2337 {\r
2338 px=ps+(3*((int)((float)x * XS))+\r
2339 (3*dx)*((int)((float)y*YS)));\r
2340 sx=(*px)>>3;px++;\r
2341 s=sx;\r
2342 sx=(*px)>>3;px++;\r
2343 s|=sx<<5;\r
2344 sx=(*px)>>3;\r
2345 s|=sx<<10;\r
2346 s&=~0x8000;\r
2347 *p=s;\r
2348 }\r
2349 p++;\r
2350 }\r
2351 p += 1024 - udx;\r
2352 }\r
2353}\r
2354\r
2355////////////////////////////////////////////////////////////////////////\r
2356// core read from vram\r
2357////////////////////////////////////////////////////////////////////////\r
2358\r
2359void CALLBACK GPUreadDataMem(uint32_t *pMem, int iSize)\r
2360{\r
2361 int i;\r
2362\r
2363 if(iDataReadMode!=DR_VRAMTRANSFER) return;\r
2364\r
2365 GPUIsBusy;\r
2366\r
2367 // adjust read ptr, if necessary\r
2368 while(VRAMRead.ImagePtr>=psxVuw_eom)\r
2369 VRAMRead.ImagePtr-=iGPUHeight*1024;\r
2370 while(VRAMRead.ImagePtr<psxVuw)\r
2371 VRAMRead.ImagePtr+=iGPUHeight*1024;\r
2372\r
2373 if((iFrameReadType&1 && iSize>1) &&\r
2374 !(iDrawnSomething==2 &&\r
2375 VRAMRead.x == VRAMWrite.x &&\r
2376 VRAMRead.y == VRAMWrite.y &&\r
2377 VRAMRead.Width == VRAMWrite.Width &&\r
2378 VRAMRead.Height == VRAMWrite.Height))\r
2379 CheckVRamRead(VRAMRead.x,VRAMRead.y,\r
2380 VRAMRead.x+VRAMRead.RowsRemaining,\r
2381 VRAMRead.y+VRAMRead.ColsRemaining,\r
2382 TRUE);\r
2383\r
2384 for(i=0;i<iSize;i++)\r
2385 {\r
2386 // do 2 seperate 16bit reads for compatibility (wrap issues)\r
2387 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))\r
2388 {\r
2389 // lower 16 bit\r
2390 GPUdataRet=(uint32_t)*VRAMRead.ImagePtr;\r
2391\r
2392 VRAMRead.ImagePtr++;\r
2393 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
2394 VRAMRead.RowsRemaining --;\r
2395\r
2396 if(VRAMRead.RowsRemaining<=0)\r
2397 {\r
2398 VRAMRead.RowsRemaining = VRAMRead.Width;\r
2399 VRAMRead.ColsRemaining--;\r
2400 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;\r
2401 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
2402 }\r
2403\r
2404 // higher 16 bit (always, even if it's an odd width)\r
2405 GPUdataRet|=(uint32_t)(*VRAMRead.ImagePtr)<<16;\r
2406 *pMem++=GPUdataRet;\r
2407\r
2408 if(VRAMRead.ColsRemaining <= 0)\r
2409 {FinishedVRAMRead();goto ENDREAD;}\r
2410\r
2411 VRAMRead.ImagePtr++;\r
2412 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
2413 VRAMRead.RowsRemaining--;\r
2414 if(VRAMRead.RowsRemaining<=0)\r
2415 {\r
2416 VRAMRead.RowsRemaining = VRAMRead.Width;\r
2417 VRAMRead.ColsRemaining--;\r
2418 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;\r
2419 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
2420 }\r
2421 if(VRAMRead.ColsRemaining <= 0)\r
2422 {FinishedVRAMRead();goto ENDREAD;}\r
2423 }\r
2424 else {FinishedVRAMRead();goto ENDREAD;}\r
2425 }\r
2426\r
2427ENDREAD:\r
2428 GPUIsIdle;\r
2429}\r
2430\r
2431uint32_t CALLBACK GPUreadData(void)\r
2432{\r
2433 uint32_t l;\r
2434 GPUreadDataMem(&l,1);\r
2435 return GPUdataRet;\r
2436}\r
2437\r
2438////////////////////////////////////////////////////////////////////////\r
2439// helper table to know how much data is used by drawing commands\r
2440////////////////////////////////////////////////////////////////////////\r
2441\r
2442const unsigned char primTableCX[256] =\r
2443{\r
2444 // 00\r
2445 0,0,3,0,0,0,0,0,\r
2446 // 08\r
2447 0,0,0,0,0,0,0,0,\r
2448 // 10\r
2449 0,0,0,0,0,0,0,0,\r
2450 // 18\r
2451 0,0,0,0,0,0,0,0,\r
2452 // 20\r
2453 4,4,4,4,7,7,7,7,\r
2454 // 28\r
2455 5,5,5,5,9,9,9,9,\r
2456 // 30\r
2457 6,6,6,6,9,9,9,9,\r
2458 // 38\r
2459 8,8,8,8,12,12,12,12,\r
2460 // 40\r
2461 3,3,3,3,0,0,0,0,\r
2462 // 48\r
2463// 5,5,5,5,6,6,6,6, //FLINE\r
2464 254,254,254,254,254,254,254,254,\r
2465 // 50\r
2466 4,4,4,4,0,0,0,0,\r
2467 // 58\r
2468// 7,7,7,7,9,9,9,9, // LINEG3 LINEG4\r
2469 255,255,255,255,255,255,255,255,\r
2470 // 60\r
2471 3,3,3,3,4,4,4,4, // TILE SPRT\r
2472 // 68\r
2473 2,2,2,2,3,3,3,3, // TILE1\r
2474 // 70\r
2475 2,2,2,2,3,3,3,3,\r
2476 // 78\r
2477 2,2,2,2,3,3,3,3,\r
2478 // 80\r
2479 4,0,0,0,0,0,0,0,\r
2480 // 88\r
2481 0,0,0,0,0,0,0,0,\r
2482 // 90\r
2483 0,0,0,0,0,0,0,0,\r
2484 // 98\r
2485 0,0,0,0,0,0,0,0,\r
2486 // a0\r
2487 3,0,0,0,0,0,0,0,\r
2488 // a8\r
2489 0,0,0,0,0,0,0,0,\r
2490 // b0\r
2491 0,0,0,0,0,0,0,0,\r
2492 // b8\r
2493 0,0,0,0,0,0,0,0,\r
2494 // c0\r
2495 3,0,0,0,0,0,0,0,\r
2496 // c8\r
2497 0,0,0,0,0,0,0,0,\r
2498 // d0\r
2499 0,0,0,0,0,0,0,0,\r
2500 // d8\r
2501 0,0,0,0,0,0,0,0,\r
2502 // e0\r
2503 0,1,1,1,1,1,1,0,\r
2504 // e8\r
2505 0,0,0,0,0,0,0,0,\r
2506 // f0\r
2507 0,0,0,0,0,0,0,0,\r
2508 // f8\r
2509 0,0,0,0,0,0,0,0\r
2510};\r
2511\r
2512////////////////////////////////////////////////////////////////////////\r
2513// processes data send to GPU data register\r
2514////////////////////////////////////////////////////////////////////////\r
2515\r
2516void CALLBACK GPUwriteDataMem(uint32_t *pMem, int iSize)\r
2517{\r
2518 unsigned char command;\r
2519 uint32_t gdata=0;\r
2520 int i=0;\r
2521 GPUIsBusy;\r
2522 GPUIsNotReadyForCommands;\r
2523\r
2524STARTVRAM:\r
2525\r
2526 if(iDataWriteMode==DR_VRAMTRANSFER)\r
2527 {\r
2528 // make sure we are in vram\r
2529 while(VRAMWrite.ImagePtr>=psxVuw_eom)\r
2530 VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
2531 while(VRAMWrite.ImagePtr<psxVuw)\r
2532 VRAMWrite.ImagePtr+=iGPUHeight*1024;\r
2533\r
2534 // now do the loop\r
2535 while(VRAMWrite.ColsRemaining>0)\r
2536 {\r
2537 while(VRAMWrite.RowsRemaining>0)\r
2538 {\r
2539 if(i>=iSize) {goto ENDVRAM;}\r
2540 i++;\r
2541\r
2542 gdata=*pMem++;\r
2543\r
2544 *VRAMWrite.ImagePtr++ = (unsigned short)gdata;\r
2545 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
2546 VRAMWrite.RowsRemaining --;\r
2547\r
2548 if(VRAMWrite.RowsRemaining <= 0)\r
2549 {\r
2550 VRAMWrite.ColsRemaining--;\r
2551 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width\r
2552 {\r
2553 gdata=(gdata&0xFFFF)|(((uint32_t)(*VRAMWrite.ImagePtr))<<16);\r
2554 FinishedVRAMWrite();\r
2555 goto ENDVRAM;\r
2556 }\r
2557 VRAMWrite.RowsRemaining = VRAMWrite.Width;\r
2558 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;\r
2559 }\r
2560\r
2561 *VRAMWrite.ImagePtr++ = (unsigned short)(gdata>>16);\r
2562 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
2563 VRAMWrite.RowsRemaining --;\r
2564 }\r
2565\r
2566 VRAMWrite.RowsRemaining = VRAMWrite.Width;\r
2567 VRAMWrite.ColsRemaining--;\r
2568 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;\r
2569 }\r
2570\r
2571 FinishedVRAMWrite();\r
2572 }\r
2573\r
2574ENDVRAM:\r
2575\r
2576 if(iDataWriteMode==DR_NORMAL)\r
2577 {\r
2578 void (* *primFunc)(unsigned char *);\r
2579 if(bSkipNextFrame) primFunc=primTableSkip;\r
2580 else primFunc=primTableJ;\r
2581\r
2582 for(;i<iSize;)\r
2583 {\r
2584 if(iDataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;\r
2585\r
2586 gdata=*pMem++;i++;\r
2587 \r
2588 if(gpuDataC == 0)\r
2589 {\r
2590 command = (unsigned char)((gdata>>24) & 0xff);\r
2591 \r
2592 if(primTableCX[command])\r
2593 {\r
2594 gpuDataC = primTableCX[command];\r
2595 gpuCommand = command;\r
2596 gpuDataM[0] = gdata;\r
2597 gpuDataP = 1;\r
2598 }\r
2599 else continue;\r
2600 }\r
2601 else\r
2602 {\r
2603 gpuDataM[gpuDataP] = gdata;\r
2604 if(gpuDataC>128)\r
2605 {\r
2606 if((gpuDataC==254 && gpuDataP>=3) ||\r
2607 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))\r
2608 {\r
2609 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)\r
2610 gpuDataP=gpuDataC-1;\r
2611 }\r
2612 }\r
2613 gpuDataP++;\r
2614 }\r
2615 \r
2616 if(gpuDataP == gpuDataC)\r
2617 {\r
2618 gpuDataC=gpuDataP=0;\r
2619 primFunc[gpuCommand]((unsigned char *)gpuDataM);\r
2620\r
2621 if(dwEmuFixes&0x0001 || dwActFixes&0x20000) // hack for emulating "gpu busy" in some games\r
2622 iFakePrimBusy=4;\r
2623 }\r
2624 } \r
2625 }\r
2626\r
2627 GPUdataRet=gdata;\r
2628\r
2629 GPUIsReadyForCommands;\r
2630 GPUIsIdle; \r
2631}\r
2632\r
2633////////////////////////////////////////////////////////////////////////\r
2634\r
2635void CALLBACK GPUwriteData(uint32_t gdata)\r
2636{\r
2637 GPUwriteDataMem(&gdata,1);\r
2638}\r
2639\r
2640////////////////////////////////////////////////////////////////////////\r
2641// call config dlg\r
2642////////////////////////////////////////////////////////////////////////\r
2643\r
2644void StartCfgTool(char *arg) // linux: start external cfg tool\r
2645{\r
2646 char cfg[256];\r
2647 struct stat buf;\r
2648\r
2649 strcpy(cfg, "./cfgpeopsxgl");\r
2650 if (stat(cfg, &buf) != -1) {\r
2651 if (fork() == 0) {\r
2652 execl(cfg, "cfgpeopsxgl", arg, NULL);\r
2653 exit(0);\r
2654 }\r
2655 return;\r
2656 }\r
2657\r
2658 strcpy(cfg, "./cfg/cfgpeopsxgl");\r
2659 if (stat(cfg, &buf) != -1) {\r
2660 if (fork() == 0) {\r
2661 execl(cfg, "cfgpeopsxgl", arg, NULL);\r
2662 exit(0);\r
2663 }\r
2664 return;\r
2665 }\r
2666\r
2667 sprintf(cfg, "%s/.pcsx/plugins/cfg/cfgpeopsxgl", getenv("HOME"));\r
2668 if (stat(cfg, &buf) != -1) {\r
2669 if (fork() == 0) {\r
2670 execl(cfg, "cfgpeopsxgl", arg, NULL);\r
2671 exit(0);\r
2672 }\r
2673 return;\r
2674 }\r
2675\r
2676 printf("ERROR: cfgpeopsxgl file not found!\n");\r
2677}\r
2678\r
2679long CALLBACK GPUconfigure(void)\r
2680{\r
2681 StartCfgTool("CFG");\r
2682 return 0;\r
2683}\r
2684\r
2685////////////////////////////////////////////////////////////////////////\r
2686// sets all kind of act fixes\r
2687////////////////////////////////////////////////////////////////////////\r
2688\r
2689void SetFixes(void)\r
2690{\r
2691 ReInitFrameCap();\r
2692\r
2693 if(dwActFixes & 0x2000) \r
2694 dispWidths[4]=384;\r
2695 else dispWidths[4]=368;\r
2696}\r
2697\r
2698////////////////////////////////////////////////////////////////////////\r
2699// Pete Special: make an 'intelligent' dma chain check (<-Tekken3)\r
2700////////////////////////////////////////////////////////////////////////\r
2701\r
2702uint32_t lUsedAddr[3];\r
2703\r
2704__inline BOOL CheckForEndlessLoop(uint32_t laddr)\r
2705{\r
2706 if(laddr==lUsedAddr[1]) return TRUE;\r
2707 if(laddr==lUsedAddr[2]) return TRUE;\r
2708\r
2709 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;\r
2710 else lUsedAddr[2]=laddr;\r
2711 lUsedAddr[0]=laddr;\r
2712 return FALSE;\r
2713}\r
2714\r
2715////////////////////////////////////////////////////////////////////////\r
2716// core gives a dma chain to gpu: same as the gpuwrite interface funcs\r
2717////////////////////////////////////////////////////////////////////////\r
2718\r
2719long CALLBACK GPUdmaChain(uint32_t *baseAddrL, uint32_t addr)\r
2720{\r
2721 uint32_t dmaMem;\r
2722 unsigned char * baseAddrB;\r
2723 short count;unsigned int DMACommandCounter = 0;\r
2724\r
2725 if(bIsFirstFrame) GLinitialize();\r
2726\r
2727 GPUIsBusy;\r
2728\r
2729 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;\r
2730\r
2731 baseAddrB = (unsigned char*) baseAddrL;\r
2732\r
2733 do\r
2734 {\r
2735 if(iGPUHeight==512) addr&=0x1FFFFC;\r
2736\r
2737 if(DMACommandCounter++ > 2000000) break;\r
2738 if(CheckForEndlessLoop(addr)) break;\r
2739\r
2740 count = baseAddrB[addr+3];\r
2741\r
2742 dmaMem=addr+4;\r
2743\r
2744 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);\r
2745\r
2746 addr = baseAddrL[addr>>2]&0xffffff;\r
2747 }\r
2748 while (addr != 0xffffff);\r
2749\r
2750 GPUIsIdle;\r
2751\r
2752 return 0;\r
2753}\r
2754 \r
2755////////////////////////////////////////////////////////////////////////\r
2756// show about dlg\r
2757////////////////////////////////////////////////////////////////////////\r
2758\r
2759void CALLBACK GPUabout(void)\r
2760{\r
2761 StartCfgTool("ABOUT");\r
2762}\r
2763\r
2764////////////////////////////////////////////////////////////////////////\r
2765// We are ever fine ;)\r
2766////////////////////////////////////////////////////////////////////////\r
2767\r
2768long CALLBACK GPUtest(void)\r
2769{\r
2770 // if test fails this function should return negative value for error (unable to continue)\r
2771 // and positive value for warning (can continue but output might be crappy)\r
2772\r
2773 return 0;\r
2774}\r
2775\r
2776////////////////////////////////////////////////////////////////////////\r
2777// save state funcs\r
2778////////////////////////////////////////////////////////////////////////\r
2779\r
2780typedef struct GPUFREEZETAG\r
2781{\r
2782 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)\r
2783 uint32_t ulStatus; // current gpu status\r
2784 uint32_t ulControl[256]; // latest control register values\r
2785 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)\r
2786} GPUFreeze_t;\r
2787\r
2788////////////////////////////////////////////////////////////////////////\r
2789\r
2790long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)\r
2791{\r
2792 if(ulGetFreezeData==2) \r
2793 {\r
2794 int lSlotNum=*((int *)pF);\r
2795 if(lSlotNum<0) return 0;\r
2796 if(lSlotNum>8) return 0;\r
2797 lSelectedSlot=lSlotNum+1;\r
2798 return 1;\r
2799 }\r
2800\r
2801 if(!pF) return 0; \r
2802 if(pF->ulFreezeVersion!=1) return 0;\r
2803\r
2804 if(ulGetFreezeData==1)\r
2805 {\r
2806 pF->ulStatus=STATUSREG;\r
2807 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));\r
2808 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);\r
2809\r
2810 return 1;\r
2811 }\r
2812\r
2813 if(ulGetFreezeData!=0) return 0;\r
2814\r
2815 STATUSREG=pF->ulStatus;\r
2816 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));\r
2817 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);\r
2818\r
2819 ResetTextureArea(TRUE);\r
2820\r
2821 GPUwriteStatus(ulStatusControl[0]);\r
2822 GPUwriteStatus(ulStatusControl[1]);\r
2823 GPUwriteStatus(ulStatusControl[2]);\r
2824 GPUwriteStatus(ulStatusControl[3]);\r
2825 GPUwriteStatus(ulStatusControl[8]);\r
2826 GPUwriteStatus(ulStatusControl[6]);\r
2827 GPUwriteStatus(ulStatusControl[7]);\r
2828 GPUwriteStatus(ulStatusControl[5]);\r
2829 GPUwriteStatus(ulStatusControl[4]);\r
2830\r
2831 return 1;\r
2832}\r
2833\r
2834////////////////////////////////////////////////////////////////////////\r
2835// special "emu infos" / "emu effects" functions\r
2836////////////////////////////////////////////////////////////////////////\r
2837\r
2838//00 = black\r
2839//01 = white\r
2840//10 = red\r
2841//11 = transparent\r
2842\r
2843unsigned char cFont[10][120]=\r
2844{\r
2845// 0\r
2846{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2847 0x80,0x00,0x00,0x00,0x00,0x00,\r
2848 0x80,0x00,0x00,0x00,0x00,0x00,\r
2849 0x80,0x00,0x00,0x00,0x00,0x00,\r
2850 0x80,0x00,0x00,0x00,0x00,0x00,\r
2851 0x80,0x00,0x05,0x54,0x00,0x00,\r
2852 0x80,0x00,0x14,0x05,0x00,0x00,\r
2853 0x80,0x00,0x14,0x05,0x00,0x00,\r
2854 0x80,0x00,0x14,0x05,0x00,0x00,\r
2855 0x80,0x00,0x14,0x05,0x00,0x00,\r
2856 0x80,0x00,0x14,0x05,0x00,0x00,\r
2857 0x80,0x00,0x14,0x05,0x00,0x00,\r
2858 0x80,0x00,0x14,0x05,0x00,0x00,\r
2859 0x80,0x00,0x14,0x05,0x00,0x00,\r
2860 0x80,0x00,0x05,0x54,0x00,0x00,\r
2861 0x80,0x00,0x00,0x00,0x00,0x00,\r
2862 0x80,0x00,0x00,0x00,0x00,0x00,\r
2863 0x80,0x00,0x00,0x00,0x00,0x00,\r
2864 0x80,0x00,0x00,0x00,0x00,0x00,\r
2865 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2866},\r
2867// 1\r
2868{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2869 0x80,0x00,0x00,0x00,0x00,0x00,\r
2870 0x80,0x00,0x00,0x00,0x00,0x00,\r
2871 0x80,0x00,0x00,0x00,0x00,0x00,\r
2872 0x80,0x00,0x00,0x00,0x00,0x00,\r
2873 0x80,0x00,0x00,0x50,0x00,0x00,\r
2874 0x80,0x00,0x05,0x50,0x00,0x00,\r
2875 0x80,0x00,0x00,0x50,0x00,0x00,\r
2876 0x80,0x00,0x00,0x50,0x00,0x00,\r
2877 0x80,0x00,0x00,0x50,0x00,0x00,\r
2878 0x80,0x00,0x00,0x50,0x00,0x00,\r
2879 0x80,0x00,0x00,0x50,0x00,0x00,\r
2880 0x80,0x00,0x00,0x50,0x00,0x00,\r
2881 0x80,0x00,0x00,0x50,0x00,0x00,\r
2882 0x80,0x00,0x05,0x55,0x00,0x00,\r
2883 0x80,0x00,0x00,0x00,0x00,0x00,\r
2884 0x80,0x00,0x00,0x00,0x00,0x00,\r
2885 0x80,0x00,0x00,0x00,0x00,0x00,\r
2886 0x80,0x00,0x00,0x00,0x00,0x00,\r
2887 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2888},\r
2889// 2\r
2890{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2891 0x80,0x00,0x00,0x00,0x00,0x00,\r
2892 0x80,0x00,0x00,0x00,0x00,0x00,\r
2893 0x80,0x00,0x00,0x00,0x00,0x00,\r
2894 0x80,0x00,0x00,0x00,0x00,0x00,\r
2895 0x80,0x00,0x05,0x54,0x00,0x00,\r
2896 0x80,0x00,0x14,0x05,0x00,0x00,\r
2897 0x80,0x00,0x00,0x05,0x00,0x00,\r
2898 0x80,0x00,0x00,0x05,0x00,0x00,\r
2899 0x80,0x00,0x00,0x14,0x00,0x00,\r
2900 0x80,0x00,0x00,0x50,0x00,0x00,\r
2901 0x80,0x00,0x01,0x40,0x00,0x00,\r
2902 0x80,0x00,0x05,0x00,0x00,0x00,\r
2903 0x80,0x00,0x14,0x00,0x00,0x00,\r
2904 0x80,0x00,0x15,0x55,0x00,0x00,\r
2905 0x80,0x00,0x00,0x00,0x00,0x00,\r
2906 0x80,0x00,0x00,0x00,0x00,0x00,\r
2907 0x80,0x00,0x00,0x00,0x00,0x00,\r
2908 0x80,0x00,0x00,0x00,0x00,0x00,\r
2909 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2910},\r
2911// 3\r
2912{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2913 0x80,0x00,0x00,0x00,0x00,0x00,\r
2914 0x80,0x00,0x00,0x00,0x00,0x00,\r
2915 0x80,0x00,0x00,0x00,0x00,0x00,\r
2916 0x80,0x00,0x00,0x00,0x00,0x00,\r
2917 0x80,0x00,0x05,0x54,0x00,0x00,\r
2918 0x80,0x00,0x14,0x05,0x00,0x00,\r
2919 0x80,0x00,0x00,0x05,0x00,0x00,\r
2920 0x80,0x00,0x00,0x05,0x00,0x00,\r
2921 0x80,0x00,0x01,0x54,0x00,0x00,\r
2922 0x80,0x00,0x00,0x05,0x00,0x00,\r
2923 0x80,0x00,0x00,0x05,0x00,0x00,\r
2924 0x80,0x00,0x00,0x05,0x00,0x00,\r
2925 0x80,0x00,0x14,0x05,0x00,0x00,\r
2926 0x80,0x00,0x05,0x54,0x00,0x00,\r
2927 0x80,0x00,0x00,0x00,0x00,0x00,\r
2928 0x80,0x00,0x00,0x00,0x00,0x00,\r
2929 0x80,0x00,0x00,0x00,0x00,0x00,\r
2930 0x80,0x00,0x00,0x00,0x00,0x00,\r
2931 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2932},\r
2933// 4\r
2934{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2935 0x80,0x00,0x00,0x00,0x00,0x00,\r
2936 0x80,0x00,0x00,0x00,0x00,0x00,\r
2937 0x80,0x00,0x00,0x00,0x00,0x00,\r
2938 0x80,0x00,0x00,0x00,0x00,0x00,\r
2939 0x80,0x00,0x00,0x14,0x00,0x00,\r
2940 0x80,0x00,0x00,0x54,0x00,0x00,\r
2941 0x80,0x00,0x01,0x54,0x00,0x00,\r
2942 0x80,0x00,0x01,0x54,0x00,0x00,\r
2943 0x80,0x00,0x05,0x14,0x00,0x00,\r
2944 0x80,0x00,0x14,0x14,0x00,0x00,\r
2945 0x80,0x00,0x15,0x55,0x00,0x00,\r
2946 0x80,0x00,0x00,0x14,0x00,0x00,\r
2947 0x80,0x00,0x00,0x14,0x00,0x00,\r
2948 0x80,0x00,0x00,0x55,0x00,0x00,\r
2949 0x80,0x00,0x00,0x00,0x00,0x00,\r
2950 0x80,0x00,0x00,0x00,0x00,0x00,\r
2951 0x80,0x00,0x00,0x00,0x00,0x00,\r
2952 0x80,0x00,0x00,0x00,0x00,0x00,\r
2953 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2954},\r
2955// 5\r
2956{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2957 0x80,0x00,0x00,0x00,0x00,0x00,\r
2958 0x80,0x00,0x00,0x00,0x00,0x00,\r
2959 0x80,0x00,0x00,0x00,0x00,0x00,\r
2960 0x80,0x00,0x00,0x00,0x00,0x00,\r
2961 0x80,0x00,0x15,0x55,0x00,0x00,\r
2962 0x80,0x00,0x14,0x00,0x00,0x00,\r
2963 0x80,0x00,0x14,0x00,0x00,0x00,\r
2964 0x80,0x00,0x14,0x00,0x00,0x00,\r
2965 0x80,0x00,0x15,0x54,0x00,0x00,\r
2966 0x80,0x00,0x00,0x05,0x00,0x00,\r
2967 0x80,0x00,0x00,0x05,0x00,0x00,\r
2968 0x80,0x00,0x00,0x05,0x00,0x00,\r
2969 0x80,0x00,0x14,0x05,0x00,0x00,\r
2970 0x80,0x00,0x05,0x54,0x00,0x00,\r
2971 0x80,0x00,0x00,0x00,0x00,0x00,\r
2972 0x80,0x00,0x00,0x00,0x00,0x00,\r
2973 0x80,0x00,0x00,0x00,0x00,0x00,\r
2974 0x80,0x00,0x00,0x00,0x00,0x00,\r
2975 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2976},\r
2977// 6\r
2978{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
2979 0x80,0x00,0x00,0x00,0x00,0x00,\r
2980 0x80,0x00,0x00,0x00,0x00,0x00,\r
2981 0x80,0x00,0x00,0x00,0x00,0x00,\r
2982 0x80,0x00,0x00,0x00,0x00,0x00,\r
2983 0x80,0x00,0x01,0x54,0x00,0x00,\r
2984 0x80,0x00,0x05,0x00,0x00,0x00,\r
2985 0x80,0x00,0x14,0x00,0x00,0x00,\r
2986 0x80,0x00,0x14,0x00,0x00,0x00,\r
2987 0x80,0x00,0x15,0x54,0x00,0x00,\r
2988 0x80,0x00,0x15,0x05,0x00,0x00,\r
2989 0x80,0x00,0x14,0x05,0x00,0x00,\r
2990 0x80,0x00,0x14,0x05,0x00,0x00,\r
2991 0x80,0x00,0x14,0x05,0x00,0x00,\r
2992 0x80,0x00,0x05,0x54,0x00,0x00,\r
2993 0x80,0x00,0x00,0x00,0x00,0x00,\r
2994 0x80,0x00,0x00,0x00,0x00,0x00,\r
2995 0x80,0x00,0x00,0x00,0x00,0x00,\r
2996 0x80,0x00,0x00,0x00,0x00,0x00,\r
2997 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
2998},\r
2999// 7\r
3000{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
3001 0x80,0x00,0x00,0x00,0x00,0x00,\r
3002 0x80,0x00,0x00,0x00,0x00,0x00,\r
3003 0x80,0x00,0x00,0x00,0x00,0x00,\r
3004 0x80,0x00,0x00,0x00,0x00,0x00,\r
3005 0x80,0x00,0x15,0x55,0x00,0x00,\r
3006 0x80,0x00,0x14,0x05,0x00,0x00,\r
3007 0x80,0x00,0x00,0x14,0x00,0x00,\r
3008 0x80,0x00,0x00,0x14,0x00,0x00,\r
3009 0x80,0x00,0x00,0x50,0x00,0x00,\r
3010 0x80,0x00,0x00,0x50,0x00,0x00,\r
3011 0x80,0x00,0x01,0x40,0x00,0x00,\r
3012 0x80,0x00,0x01,0x40,0x00,0x00,\r
3013 0x80,0x00,0x05,0x00,0x00,0x00,\r
3014 0x80,0x00,0x05,0x00,0x00,0x00,\r
3015 0x80,0x00,0x00,0x00,0x00,0x00,\r
3016 0x80,0x00,0x00,0x00,0x00,0x00,\r
3017 0x80,0x00,0x00,0x00,0x00,0x00,\r
3018 0x80,0x00,0x00,0x00,0x00,0x00,\r
3019 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
3020},\r
3021// 8\r
3022{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
3023 0x80,0x00,0x00,0x00,0x00,0x00,\r
3024 0x80,0x00,0x00,0x00,0x00,0x00,\r
3025 0x80,0x00,0x00,0x00,0x00,0x00,\r
3026 0x80,0x00,0x00,0x00,0x00,0x00,\r
3027 0x80,0x00,0x05,0x54,0x00,0x00,\r
3028 0x80,0x00,0x14,0x05,0x00,0x00,\r
3029 0x80,0x00,0x14,0x05,0x00,0x00,\r
3030 0x80,0x00,0x14,0x05,0x00,0x00,\r
3031 0x80,0x00,0x05,0x54,0x00,0x00,\r
3032 0x80,0x00,0x14,0x05,0x00,0x00,\r
3033 0x80,0x00,0x14,0x05,0x00,0x00,\r
3034 0x80,0x00,0x14,0x05,0x00,0x00,\r
3035 0x80,0x00,0x14,0x05,0x00,0x00,\r
3036 0x80,0x00,0x05,0x54,0x00,0x00,\r
3037 0x80,0x00,0x00,0x00,0x00,0x00,\r
3038 0x80,0x00,0x00,0x00,0x00,0x00,\r
3039 0x80,0x00,0x00,0x00,0x00,0x00,\r
3040 0x80,0x00,0x00,0x00,0x00,0x00,\r
3041 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
3042},\r
3043// 9\r
3044{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
3045 0x80,0x00,0x00,0x00,0x00,0x00,\r
3046 0x80,0x00,0x00,0x00,0x00,0x00,\r
3047 0x80,0x00,0x00,0x00,0x00,0x00,\r
3048 0x80,0x00,0x00,0x00,0x00,0x00,\r
3049 0x80,0x00,0x05,0x54,0x00,0x00,\r
3050 0x80,0x00,0x14,0x05,0x00,0x00,\r
3051 0x80,0x00,0x14,0x05,0x00,0x00,\r
3052 0x80,0x00,0x14,0x05,0x00,0x00,\r
3053 0x80,0x00,0x14,0x15,0x00,0x00,\r
3054 0x80,0x00,0x05,0x55,0x00,0x00,\r
3055 0x80,0x00,0x00,0x05,0x00,0x00,\r
3056 0x80,0x00,0x00,0x05,0x00,0x00,\r
3057 0x80,0x00,0x00,0x14,0x00,0x00,\r
3058 0x80,0x00,0x05,0x50,0x00,0x00,\r
3059 0x80,0x00,0x00,0x00,0x00,0x00,\r
3060 0x80,0x00,0x00,0x00,0x00,0x00,\r
3061 0x80,0x00,0x00,0x00,0x00,0x00,\r
3062 0x80,0x00,0x00,0x00,0x00,0x00,\r
3063 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
3064}\r
3065};\r
3066\r
3067////////////////////////////////////////////////////////////////////////\r
3068\r
3069void PaintPicDot(unsigned char * p,unsigned char c)\r
3070{\r
3071 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}\r
3072 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}\r
3073 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}\r
3074}\r
3075\r
3076////////////////////////////////////////////////////////////////////////\r
3077\r
3078void CALLBACK GPUgetScreenPic(unsigned char * pMem)\r
3079{\r
3080 float XS,YS;int x,y,v;\r
3081 unsigned char * ps, * px, * pf;\r
3082 unsigned char c;\r
3083\r
3084 if(!pGfxCardScreen)\r
3085 {\r
3086 glPixelStorei(GL_PACK_ALIGNMENT,1);\r
3087 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);\r
3088 }\r
3089\r
3090 ps=pGfxCardScreen;\r
3091\r
3092 glReadBuffer(GL_FRONT);\r
3093\r
3094 glReadPixels(0,0,iResX,iResY,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
3095 \r
3096 glReadBuffer(GL_BACK);\r
3097\r
3098 XS=(float)iResX/128;\r
3099 YS=(float)iResY/96;\r
3100 pf=pMem;\r
3101\r
3102 for(y=96;y>0;y--)\r
3103 {\r
3104 for(x=0;x<128;x++)\r
3105 {\r
3106 px=ps+(3*((int)((float)x * XS))+\r
3107 (3*iResX)*((int)((float)y*YS)));\r
3108 *(pf+0)=*(px+2);\r
3109 *(pf+1)=*(px+1);\r
3110 *(pf+2)=*(px+0);\r
3111 pf+=3;\r
3112 }\r
3113 }\r
3114\r
3115 /////////////////////////////////////////////////////////////////////\r
3116 // generic number/border painter\r
3117\r
3118 pf=pMem+(103*3);\r
3119\r
3120 for(y=0;y<20;y++)\r
3121 {\r
3122 for(x=0;x<6;x++)\r
3123 {\r
3124 c=cFont[lSelectedSlot][x+y*6];\r
3125 v=(c&0xc0)>>6;\r
3126 PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect\r
3127 v=(c&0x30)>>4;\r
3128 PaintPicDot(pf,(unsigned char)v);pf+=3;\r
3129 v=(c&0x0c)>>2;\r
3130 PaintPicDot(pf,(unsigned char)v);pf+=3;\r
3131 v=c&0x03;\r
3132 PaintPicDot(pf,(unsigned char)v);pf+=3;\r
3133 }\r
3134 pf+=104*3;\r
3135 }\r
3136\r
3137 pf=pMem;\r
3138 for(x=0;x<128;x++)\r
3139 {\r
3140 *(pf+(95*128*3))=0x00;*pf++=0x00;\r
3141 *(pf+(95*128*3))=0x00;*pf++=0x00;\r
3142 *(pf+(95*128*3))=0xff;*pf++=0xff;\r
3143 }\r
3144 pf=pMem;\r
3145 for(y=0;y<96;y++)\r
3146 {\r
3147 *(pf+(127*3))=0x00;*pf++=0x00;\r
3148 *(pf+(127*3))=0x00;*pf++=0x00;\r
3149 *(pf+(127*3))=0xff;*pf++=0xff;\r
3150 pf+=127*3;\r
3151 }\r
3152\r
3153}\r
3154\r
3155////////////////////////////////////////////////////////////////////////\r
3156\r
3157void CALLBACK GPUshowScreenPic(unsigned char * pMem)\r
3158{\r
3159 DestroyPic();\r
3160 if(pMem==0) return;\r
3161 CreatePic(pMem);\r
3162}\r
3163\r
3164////////////////////////////////////////////////////////////////////////\r
3165\r
3166void CALLBACK GPUsetfix(uint32_t dwFixBits)\r
3167{\r
3168 dwEmuFixes=dwFixBits;\r
3169}\r
3170\r
3171////////////////////////////////////////////////////////////////////////\r
3172 \r
3173void CALLBACK GPUvisualVibration(uint32_t iSmall, uint32_t iBig)\r
3174{\r
3175 int iVibVal;\r
3176\r
3177 if(PSXDisplay.DisplayModeNew.x) // calc min "shake pixel" from screen width\r
3178 iVibVal=max(1,iResX/PSXDisplay.DisplayModeNew.x);\r
3179 else iVibVal=1;\r
3180 // big rumble: 4...15 sp ; small rumble 1...3 sp\r
3181 if(iBig) iRumbleVal=max(4*iVibVal,min(15*iVibVal,((int)iBig *iVibVal)/10));\r
3182 else iRumbleVal=max(1*iVibVal,min( 3*iVibVal,((int)iSmall*iVibVal)/10));\r
3183\r
3184 srand(timeGetTime()); // init rand (will be used in BufferSwap)\r
3185\r
3186 iRumbleTime=15; // let the rumble last 16 buffer swaps\r
3187}\r
3188 \r
3189////////////////////////////////////////////////////////////////////////\r
3190// main emu can set display infos (A/M/G/D) \r
3191////////////////////////////////////////////////////////////////////////\r
3192\r
3193void CALLBACK GPUdisplayFlags(uint32_t dwFlags)\r
3194{\r
3195 dwCoreFlags=dwFlags;\r
3196}\r