pcsxr-1.9.92
[pcsx_rearmed.git] / plugins / peopsxgl / gpu.c
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
27 static XF86VidModeModeInfo **modes=0;\r
28 static 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
57 const  unsigned char version  = 1;    // do not touch - library for PSEmu 1.x\r
58 const  unsigned char revision = 1;\r
59 const  unsigned char build    = 78;\r
60 \r
61 static char *libraryName     = N_("OpenGL Driver");\r
62 \r
63 static char *PluginAuthor    = N_("Pete Bernert");\r
64 static 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
70 unsigned char  *psxVSecure;\r
71 unsigned char  *psxVub;\r
72 signed   char  *psxVsb;\r
73 unsigned short *psxVuw;\r
74 unsigned short *psxVuw_eom;\r
75 signed   short *psxVsw;\r
76 uint32_t       *psxVul;\r
77 signed   int   *psxVsl;\r
78 \r
79 // macro for easy access to packet information\r
80 #define GPUCOMMAND(x) ((x>>24) & 0xff)\r
81 \r
82 GLfloat         gl_z=0.0f;\r
83 BOOL            bNeedInterlaceUpdate=FALSE;\r
84 BOOL            bNeedRGB24Update=FALSE;\r
85 BOOL            bChangeWinMode=FALSE;\r
86 \r
87 uint32_t        ulStatusControl[256];\r
88 \r
89 ////////////////////////////////////////////////////////////////////////\r
90 // global GPU vars\r
91 ////////////////////////////////////////////////////////////////////////\r
92 \r
93 static int      GPUdataRet;\r
94 int             lGPUstatusRet;\r
95 char            szDispBuf[64];\r
96 \r
97 uint32_t        dwGPUVersion = 0;\r
98 int             iGPUHeight = 512;\r
99 int             iGPUHeightMask = 511;\r
100 int             GlobalTextIL = 0;\r
101 int             iTileCheat = 0;\r
102 \r
103 static uint32_t      gpuDataM[256];\r
104 static unsigned char gpuCommand = 0;\r
105 static int           gpuDataC = 0;\r
106 static int           gpuDataP = 0;\r
107 \r
108 VRAMLoad_t      VRAMWrite;\r
109 VRAMLoad_t      VRAMRead;\r
110 int             iDataWriteMode;\r
111 int             iDataReadMode;\r
112 \r
113 int             lClearOnSwap;\r
114 int             lClearOnSwapColor;\r
115 BOOL            bSkipNextFrame = FALSE;\r
116 int             iColDepth;\r
117 BOOL            bChangeRes;\r
118 BOOL            bWindowMode;\r
119 int             iWinSize;\r
120 \r
121 // possible psx display widths\r
122 short dispWidths[8] = {256,320,512,640,368,384,512,640};\r
123 \r
124 PSXDisplay_t    PSXDisplay;\r
125 PSXDisplay_t    PreviousPSXDisplay;\r
126 TWin_t          TWin;\r
127 short           imageX0,imageX1;\r
128 short           imageY0,imageY1;\r
129 BOOL            bDisplayNotSet = TRUE;\r
130 GLuint          uiScanLine=0;\r
131 int             iUseScanLines=0;\r
132 int             lSelectedSlot=0;\r
133 unsigned char * pGfxCardScreen=0;\r
134 int             iBlurBuffer=0;\r
135 int             iScanBlend=0;\r
136 int             iRenderFVR=0;\r
137 int             iNoScreenSaver=0;\r
138 uint32_t        ulGPUInfoVals[16];\r
139 int             iFakePrimBusy = 0;\r
140 int             iRumbleVal    = 0;\r
141 int             iRumbleTime   = 0;\r
142 \r
143 ////////////////////////////////////////////////////////////////////////\r
144 // stuff to make this a true PDK module\r
145 ////////////////////////////////////////////////////////////////////////\r
146 \r
147 char * CALLBACK PSEgetLibName(void)\r
148 {\r
149  return _(libraryName);\r
150 }\r
151 \r
152 unsigned long CALLBACK PSEgetLibType(void)\r
153 {\r
154  return  PSE_LT_GPU;\r
155 }\r
156 \r
157 unsigned long CALLBACK PSEgetLibVersion(void)\r
158 {\r
159  return version<<16|revision<<8|build;\r
160 }\r
161 \r
162 char * 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
171 char * 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
327 void 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
349 void 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
426 void 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
435 long 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
518 char * pCaptionText=0;\r
519 int    bFullScreen=0;\r
520 Display              *display;\r
521 \r
522 static Cursor        cursor;\r
523 static XVisualInfo   *myvisual;\r
524 static Colormap      colormap;\r
525 static Window        window;\r
526 \r
527 static int bModeChanged=0;\r
528 \r
529 typedef 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
538 static int dbdepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,GLX_DEPTH_SIZE,16,None};\r
539 static int dbnodepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,None};\r
540 static GLXContext cx;\r
541 \r
542 static int fx=0;\r
543 \r
544 ////////////////////////////////////////////////////////////////////////\r
545 \r
546 void 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
572 void 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
817 long 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
851 long 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
867 long 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
879 void 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
952 void 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
1044 void 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
1113 void 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
1176 int iLastRGB24=0;                                      // special vars for checking when to skip two display updates\r
1177 int iSkipTwo=0;\r
1178 \r
1179 void 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
1375 void 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
1403 void 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
1449 void 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
1478 void 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
1548 void 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
1602 BOOL 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
1658 void 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
1679 static unsigned short usFirstPos=2;\r
1680 \r
1681 void 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
1715 uint32_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
1751 void 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
2027 BOOL 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
2066 void 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
2219 void 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
2359 void 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
2427 ENDREAD:\r
2428  GPUIsIdle;\r
2429 }\r
2430 \r
2431 uint32_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
2442 const 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
2516 void 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
2524 STARTVRAM:\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
2574 ENDVRAM:\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
2635 void 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
2644 void 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
2679 long 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
2689 void 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
2702 uint32_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
2719 long 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
2759 void 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
2768 long 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
2780 typedef 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
2790 long 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
2843 unsigned 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
3069 void 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
3078 void 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
3157 void 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
3166 void CALLBACK GPUsetfix(uint32_t dwFixBits)\r
3167 {\r
3168  dwEmuFixes=dwFixBits;\r
3169 }\r
3170 \r
3171 ////////////////////////////////////////////////////////////////////////\r
3172  \r
3173 void 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
3193 void CALLBACK GPUdisplayFlags(uint32_t dwFlags)\r
3194 {\r
3195  dwCoreFlags=dwFlags;\r
3196 }\r