gpu-gles from psx4m
[pcsx_rearmed.git] / plugins / gpu-gles / gpuPlugin.c
diff --git a/plugins/gpu-gles/gpuPlugin.c b/plugins/gpu-gles/gpuPlugin.c
new file mode 100644 (file)
index 0000000..07f158c
--- /dev/null
@@ -0,0 +1,2960 @@
+/***************************************************************************\r
+                           gpu.c  -  description\r
+                             -------------------\r
+    begin                : Sun Mar 08 2009\r
+    copyright            : (C) 1999-2009 by Pete Bernert\r
+    email                : BlackDove@addcom.de\r
+ ***************************************************************************/\r
+\r
+/***************************************************************************\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version. See also the license.txt file for *\r
+ *   additional informations.                                              *\r
+ *                                                                         *\r
+ ***************************************************************************/\r
+\r
+//*************************************************************************// \r
+// History of changes:\r
+//\r
+// 2009/03/08 - Pete  \r
+// - generic cleanup for the Peops release\r
+//\r
+//*************************************************************************// \r
+\r
+//#include "gpuStdafx.h"\r
+\r
+//#include <mmsystem.h>\r
+\r
+#define _IN_GPU\r
+\r
+#ifdef _WINDOWS\r
+#include "stdafx.h"\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <mmsystem.h>\r
+\r
+#include "externals.h"\r
+#include "gpu.h"\r
+#include "draw.h"\r
+#include "prim.h"\r
+#include "texture.h"\r
+#include "fps.h"\r
+#include "resource.h"\r
+#else\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include "gpuExternals.h"\r
+#include "gpuPlugin.h"\r
+#include "gpuDraw.h"\r
+#include "gpuTexture.h"\r
+#include "gpuFps.h"\r
+#include "gpuPrim.h"\r
+\r
+//#include "NoPic.h"\r
+\r
+#include "gpuStdafx.h"\r
+#endif\r
+\r
+extern void ProcessEvents();\r
+               \r
+short g_m1=255,g_m2=255,g_m3=255;\r
+short DrawSemiTrans=FALSE;\r
+short Ymin;\r
+short Ymax;\r
+\r
+short          ly0,lx0,ly1,lx1,ly2,lx2,ly3,lx3;        // global psx vertex coords\r
+long           GlobalTextAddrX,GlobalTextAddrY,GlobalTextTP;\r
+long           GlobalTextREST,GlobalTextABR,GlobalTextPAGE;\r
+\r
+unsigned long dwGPUVersion=0;\r
+int           iGPUHeight=512;\r
+int           iGPUHeightMask=511;\r
+int           GlobalTextIL=0;\r
+int           iTileCheat=0;\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// memory image of the PSX vram\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+u8  *psxVSecure;\r
+u8  *psxVub;\r
+signed   char  *psxVsb;\r
+unsigned short *psxVuw;\r
+unsigned short *psxVuw_eom;\r
+signed   short *psxVsw;\r
+unsigned long  *psxVul;\r
+signed   long  *psxVsl;\r
+\r
+// macro for easy access to packet information\r
+#define GPUCOMMAND(x) ((x>>24) & 0xff)\r
+\r
+GLfloat         gl_z=0.0f;\r
+BOOL            bNeedInterlaceUpdate=FALSE;\r
+BOOL            bNeedRGB24Update=FALSE;\r
+BOOL            bChangeWinMode=FALSE;\r
+\r
+#ifdef _WINDOWS\r
+extern HGLRC    GLCONTEXT;\r
+#endif\r
+\r
+unsigned long   ulStatusControl[256];\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// global GPU vars\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+static long     GPUdataRet;\r
+long            lGPUstatusRet;\r
+s8            szDispBuf[64];\r
+\r
+static unsigned long gpuDataM[256];\r
+static u8 gpuCommand = 0;\r
+static long          gpuDataC = 0;\r
+static long          gpuDataP = 0;\r
+\r
+VRAMLoad_t      VRAMWrite;\r
+VRAMLoad_t      VRAMRead;\r
+int             iDataWriteMode;\r
+int             iDataReadMode;\r
+\r
+long            lClearOnSwap;\r
+long            lClearOnSwapColor;\r
+BOOL            bSkipNextFrame = FALSE;\r
+int             iColDepth;\r
+BOOL            bChangeRes;\r
+BOOL            bWindowMode;\r
+int             iWinSize;\r
+\r
+// possible psx display widths\r
+short dispWidths[8] = {256,320,512,640,368,384,512,640};\r
+\r
+PSXDisplay_t    PSXDisplay;\r
+PSXDisplay_t    PreviousPSXDisplay;\r
+TWin_t          TWin;\r
+short           imageX0,imageX1;\r
+short           imageY0,imageY1;\r
+BOOL            bDisplayNotSet = TRUE;\r
+GLuint          uiScanLine=0;\r
+int             iUseScanLines=0;\r
+long            lSelectedSlot=0;\r
+u8 * pGfxCardScreen=0;\r
+int             iBlurBuffer=0;\r
+int             iScanBlend=0;\r
+int             iRenderFVR=0;\r
+int             iNoScreenSaver=0;\r
+unsigned long   ulGPUInfoVals[16];\r
+int             iFakePrimBusy = 0;\r
+int             iRumbleVal    = 0;\r
+int             iRumbleTime   = 0;\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// stuff to make this a true PDK module\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+s8 * CALLBACK PSEgetLibName(void)\r
+{\r
+ return "name";\r
+}\r
+\r
+unsigned long CALLBACK PSEgetLibType(void)\r
+{\r
+ return  1;\r
+}\r
+\r
+unsigned long CALLBACK PSEgetLibVersion(void)\r
+{\r
+ return 1<<16|1<<8|1;\r
+}\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// snapshot funcs (saves screen to bitmap / text infos into file)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void ResizeWindow()\r
+{\r
+ rRatioRect.left   = rRatioRect.top=0;\r
+ rRatioRect.right  = iResX;\r
+ rRatioRect.bottom = iResY;\r
+ glViewport(rRatioRect.left,                           // init viewport by ratio rect\r
+            iResY-(rRatioRect.top+rRatioRect.bottom),\r
+            rRatioRect.right, \r
+            rRatioRect.bottom);         \r
+                                                      \r
+ glScissor(0, 0, iResX, iResY);                        // init clipping (fullscreen)\r
+ glEnable(GL_SCISSOR_TEST);                       \r
+\r
+#ifndef OWNSCALE\r
+ glMatrixMode(GL_TEXTURE);                             // init psx tex sow and tow if not "ownscale"\r
+ glLoadIdentity();\r
+ glScalef(1.0f/255.99f,1.0f/255.99f,1.0f);             // geforce precision hack\r
+#endif \r
+\r
+ glMatrixMode(GL_PROJECTION);                          // init projection with psx resolution\r
+ glLoadIdentity();\r
+ glOrtho(0,PSXDisplay.DisplayMode.x,\r
+         PSXDisplay.DisplayMode.y, 0, -1, 1);\r
+ if (bKeepRatio)\r
+ SetAspectRatio();\r
+}\r
+\r
+s8 * GetConfigInfos(int hW)\r
+{\r
+#ifdef _WINDOWS\r
+ HDC hdc;HGLRC hglrc;\r
+#endif\r
+ s8 szO[2][4]={"off","on "};\r
+ s8 szTxt[256];\r
+ s8 * pB=(s8 *)malloc(32767);\r
+/*\r
+ if(!pB) return NULL;\r
+ *pB=0;\r
+ //----------------------------------------------------//\r
+ strcat(pB,szTxt);\r
+ strcat(pB,szTxt);\r
+#ifdef _WINDOWS\r
+ if(hW)\r
+  {\r
+   hdc = GetDC(hW);\r
+   bSetupPixelFormat(hdc);\r
+   hglrc = wglCreateContext(hdc);\r
+   wglMakeCurrent(hdc, hglrc);\r
+  }\r
+#endif\r
+ sprintf(szTxt,"Card vendor: %s\r\n",(char *)glGetString(GL_VENDOR));\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"GFX card: %s\r\n",(char *)glGetString(GL_RENDERER));\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"OGL version: %s\r\n\r\n",(char *)glGetString(GL_VERSION));\r
+ strcat(pB,szTxt);\r
+ //strcat(pB,(s8 *)glGetString(GL_EXTENSIONS));\r
+ //strcat(pB,"\r\n\r\n");\r
+\r
+#ifdef _WINDOWS\r
+ if(hW)\r
+  {\r
+   wglMakeCurrent(NULL, NULL);\r
+   wglDeleteContext(hglrc);\r
+   ReleaseDC(hW,hdc);\r
+  }\r
+ //----------------------------------------------------//\r
+#endif\r
+ if(hW && bWindowMode)\r
+  sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));\r
+ else\r
+  sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);\r
+ strcat(pB,szTxt);\r
+ if(bWindowMode) sprintf(szTxt,"Window mode\r\n");\r
+ else\r
+  {\r
+   sprintf(szTxt,"Fullscreen ");\r
+   strcat(pB,szTxt);\r
+   if(bChangeRes) sprintf(szTxt,"- Desktop changing [%d Bit]\r\n",iColDepth);\r
+   else           sprintf(szTxt,"- NO desktop changing\r\n");\r
+  }                                                                                   \r
+ strcat(pB,szTxt);\r
+\r
+// if(iForceVSync>=0) sprintf(szTxt,"- V-Sync: %s\r\n",szO[iForceVSync]);\r
+// else               strcpy(szTxt,"- V-Sync: Driver\r\n");\r
+ strcat(pB,szTxt); \r
+ sprintf(szTxt,"- Keep psx aspect ratio: %s\r\n\r\n",szO[bKeepRatio]);\r
+ strcat(pB,szTxt);\r
+ //----------------------------------------------------//\r
+ strcpy(szTxt,"Textures:\r\n- ");\r
+/*! if(iTexQuality==0)      strcat(szTxt,"Default");\r
+ else if(iTexQuality==1) strcat(szTxt,"R4G4B4A4");\r
+ else if(iTexQuality==2) strcat(szTxt,"R5G5B5A1");\r
+ else if(iTexQuality==3) strcat(szTxt,"R8G8A8A8");\r
+ else if(iTexQuality==4) strcat(szTxt,"B8G8R8A8");\r
+ if(!hW && bGLExt) strcat(szTxt," (packed pixels)\r\n");\r
+ else              strcat(szTxt,"\r\n");\r
+ strcat(pB,szTxt);\r
+ if(!hW)\r
+  {\r
+   sprintf(szTxt,"- Filtering: %d - edge clamping ",iFilterType);\r
+   if(iClampType==GL_TO_EDGE_CLAMP) strcat(szTxt,"supported\r\n");\r
+   else                             strcat(szTxt,"NOT supported\r\n");\r
+  }\r
+ else sprintf(szTxt,"- iFiltering: %d\r\n",iFilterType);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Hi-Res textures: %d\r\n",iHiResTextures);\r
+ strcat(pB,szTxt); \r
+ if(!hW)\r
+  {\r
+   sprintf(szTxt,"- Palettized tex windows: %s\r\n",szO[iUsePalTextures]);\r
+   strcat(pB,szTxt); \r
+  }\r
+ !*/\r
+ /*sprintf(szTxt,"- VRam size: %d MBytes",iVRamSize);\r
+ if(!hW)\r
+      sprintf(szTxt+strlen(szTxt)," - %d textures usable\r\n\r\n",iSortTexCnt);\r
+ else strcat(szTxt,"\r\n\r\n");\r
+ strcat(pB,szTxt);\r
+ //----------------------------------------------------//\r
+ sprintf(szTxt,"Framerate:\r\n- FPS limitation: %s\r\n",szO[bUseFrameLimit]);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Frame skipping: %s\r\n",szO[bUseFrameSkip]);\r
+ strcat(pB,szTxt);\r
+ if(iFrameLimit==2)\r
+      strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");\r
+ else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);\r
+ strcat(pB,szTxt);\r
+ //----------------------------------------------------//\r
+ sprintf(szTxt,"Compatibility:\r\n- Offscreen drawing: %d\r\n",iOffscreenDrawing);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Framebuffer texture: %d",iFrameTexType);\r
+ if(!hW && iFrameTexType==2)\r
+  {\r
+   if(gTexFrameName) strcat(szTxt," - texture created\r\n");\r
+   else              strcat(szTxt," - not used yet\r\n");\r
+  }\r
+ else strcat(szTxt,"\r\n");\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Framebuffer access: %d\r\n",iFrameReadType);\r
+ strcat(pB,szTxt);\r
+// sprintf(szTxt,"- Alpha multipass: %s\r\n",szO[bOpaquePass]);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Mask bit: %s\r\n",szO[iUseMask]);\r
+ strcat(pB,szTxt);\r
+ //sprintf(szTxt,"- Advanced blending: %s",szO[bAdvancedBlend]);\r
+ //if(!hW && bAdvancedBlend)\r
+//  {\r
+//   if(bGLBlend) strcat(szTxt," (hardware)\r\n");\r
+//   else         strcat(szTxt," (software)\r\n");\r
+//  }\r
+ strcat(szTxt,"\r\n");\r
+ strcat(pB,szTxt);\r
+\r
+ if(!hW)\r
+  {\r
+   strcpy(szTxt,"- Subtractive blending: ");\r
+//   if(glBlendEquationEXTEx)\r
+//    {\r
+//     if(bUseMultiPass) strcat(szTxt,"supported, but not used!");\r
+//     else              strcat(szTxt,"activated");\r
+//    }\r
+   strcat(szTxt," NOT supported!");\r
+   strcat(szTxt,"\r\n\r\n");\r
+  }\r
+ else strcpy(szTxt,"\r\n");\r
\r
+ strcat(pB,szTxt);             \r
+ //----------------------------------------------------//\r
+ sprintf(szTxt,"Misc:\r\n- Scanlines: %s",szO[iUseScanLines]);\r
+ strcat(pB,szTxt);\r
+ if(iUseScanLines) sprintf(szTxt," [%d]\r\n",iScanBlend);\r
+ else strcpy(szTxt,"\r\n");\r
+ strcat(pB,szTxt);\r
+// sprintf(szTxt,"- Line mode: %s\r\n",szO[bUseLines]);\r
+ strcat(pB,szTxt);\r
+// sprintf(szTxt,"- Line AA: %s\r\n",szO[bUseAntiAlias]);\r
+// fwrite(szTxt,lstrlen(szTxt),1,txtfile);\r
+ sprintf(szTxt,"- Unfiltered FB: %s\r\n",szO[bUseFastMdec]);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- 15 bit FB: %s\r\n",szO[bUse15bitMdec]);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Dithering: %s\r\n",szO[bDrawDither]);\r
+ strcat(pB,szTxt);\r
+ sprintf(szTxt,"- Screen smoothing: %s",szO[iBlurBuffer]);\r
+ strcat(pB,szTxt);\r
+ if(!hW && iBlurBuffer) \r
+  {\r
+   if(gTexBlurName) strcat(pB," - supported\r\n");\r
+   else             strcat(pB," - not supported\r\n");\r
+  }\r
+ else strcat(pB,"\r\n");\r
+ sprintf(szTxt,"- Game fixes: %s [%08lx]\r\n",szO[bUseFixes],dwCfgFixes);\r
+ strcat(pB,szTxt);\r
+ //----------------------------------------------------//\r
+*/ return pB;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// save text infos to file\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void DoTextSnapShot(int iNum)\r
+{\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// saves screen bitmap to file\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void DoSnapShot(void)\r
+{\r
+}       \r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUmakeSnapshot(void)\r
+#else\r
+void CALLBACK GPU_makeSnapshot(void)\r
+#endif\r
+{\r
+ //bSnapShot = TRUE;\r
+}        \r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// GPU INIT... here starts it all (first func called by emu)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUinit()\r
+#else\r
+long CALLBACK GPU_init()\r
+#endif\r
+{\r
+memset(ulStatusControl,0,256*sizeof(unsigned long));\r
+\r
+#ifdef _WINDOWS\r
+iResX=240;iResY=320;\r
+#endif\r
+bChangeRes=FALSE;\r
+#ifdef _WINDOWS\r
+bWindowMode=TRUE;\r
+#else\r
+bWindowMode=FALSE;\r
+#endif \r
+#ifdef _WINDOWS\r
+iWinSize=MAKELONG(iResX,iResY);\r
+#endif\r
+\r
+bKeepRatio = TRUE;\r
+// different ways of accessing PSX VRAM\r
+\r
+psxVSecure=(u8 *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security\r
+if(!psxVSecure) return -1;\r
+\r
+psxVub=psxVSecure+512*1024;                           // security offset into double sized psx vram!\r
+psxVsb=(signed char *)psxVub;\r
+psxVsw=(signed short *)psxVub;\r
+psxVsl=(signed long *)psxVub;\r
+psxVuw=(unsigned short *)psxVub;\r
+psxVul=(unsigned long *)psxVub;\r
+\r
+psxVuw_eom=psxVuw+1024*iGPUHeight;                    // pre-calc of end of vram\r
+\r
+memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));\r
+memset(ulGPUInfoVals,0x00,16*sizeof(unsigned long));\r
+\r
+InitFrameCap();                                       // init frame rate stuff\r
+\r
+PSXDisplay.RGB24        = 0;                          // init vars\r
+PreviousPSXDisplay.RGB24= 0;\r
+PSXDisplay.Interlaced   = 0;\r
+PSXDisplay.InterlacedTest=0;\r
+PSXDisplay.DrawOffset.x = 0;\r
+PSXDisplay.DrawOffset.y = 0;\r
+PSXDisplay.DrawArea.x0  = 0;\r
+PSXDisplay.DrawArea.y0  = 0;\r
+PSXDisplay.DrawArea.x1  = 320;\r
+PSXDisplay.DrawArea.y1  = 240;\r
+PSXDisplay.DisplayMode.x= 320;\r
+PSXDisplay.DisplayMode.y= 240;\r
+PSXDisplay.Disabled     = FALSE;\r
+PreviousPSXDisplay.Range.x0 =0;\r
+PreviousPSXDisplay.Range.x1 =0;\r
+PreviousPSXDisplay.Range.y0 =0;\r
+PreviousPSXDisplay.Range.y1 =0;\r
+PSXDisplay.Range.x0=0;\r
+PSXDisplay.Range.x1=0;\r
+PSXDisplay.Range.y0=0;\r
+PSXDisplay.Range.y1=0;\r
+PreviousPSXDisplay.DisplayPosition.x = 1;\r
+PreviousPSXDisplay.DisplayPosition.y = 1;\r
+PSXDisplay.DisplayPosition.x = 1;\r
+PSXDisplay.DisplayPosition.y = 1;\r
+PreviousPSXDisplay.DisplayModeNew.y=0;\r
+PSXDisplay.Double=1;\r
+GPUdataRet=0x400;\r
+\r
+PSXDisplay.DisplayModeNew.x=0;\r
+PSXDisplay.DisplayModeNew.y=0;\r
+\r
+//PreviousPSXDisplay.Height = PSXDisplay.Height = 239;\r
+\r
+iDataWriteMode = DR_NORMAL;\r
+\r
+// Reset transfer values, to prevent mis-transfer of data\r
+memset(&VRAMWrite,0,sizeof(VRAMLoad_t));\r
+memset(&VRAMRead,0,sizeof(VRAMLoad_t));\r
+\r
+// device initialised already !\r
+//lGPUstatusRet = 0x74000000;\r
+\r
+STATUSREG = 0x14802000;\r
+GPUIsIdle;\r
+GPUIsReadyForCommands;\r
+\r
+return 0;\r
+}                             \r
+\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// GPU OPEN: funcs to open up the gpu display (Windows)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+\r
+void ChangeDesktop()                                   // change destop resolution\r
+{\r
+ DEVMODE dv;long lRes,iTry=0;                       \r
+\r
+ while(iTry<10)                                        // keep on hammering...\r
+  {\r
+   memset(&dv,0,sizeof(DEVMODE));\r
+   dv.dmSize=sizeof(DEVMODE);\r
+   dv.dmBitsPerPel=iColDepth;\r
+   dv.dmPelsWidth=iResX;\r
+   dv.dmPelsHeight=iResY;\r
+\r
+   dv.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;\r
+\r
+   lRes=ChangeDisplaySettings(&dv,0);                  // ...hammering the anvil\r
+\r
+   if(lRes==DISP_CHANGE_SUCCESSFUL) return;\r
+   iTry++;Sleep(10);\r
+  }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// OPEN interface func: attention! \r
+// some emus are calling this func in their main Window thread,\r
+// but all other interface funcs (to draw stuff) in a different thread!\r
+// that's a problem, since OGL is thread safe! Therefore we cannot \r
+// initialize the OGL stuff right here, we simply set a "bIsFirstFrame = TRUE"\r
+// flag, to initialize OGL on the first real draw call.\r
+// btw, we also call this open func ourselfes, each time when the user \r
+// is changing between fullscreen/window mode (ENTER key)\r
+// btw part 2: in windows the plugin gets the window handle from the\r
+// main emu, and doesn't create it's own window (if it would do it,\r
+// some PAD or SPU plugins would not work anymore)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+HMENU hPSEMenu=NULL;\r
+\r
+long CALLBACK GPUopen(HWND hwndGPU)                    \r
+#else\r
+long CALLBACK GPU_open(int hwndGPU)                    \r
+#endif\r
+{\r
+       #ifdef _WINDOWS\r
+       HDC hdc;RECT r;DEVMODE dv;\r
+\r
+        hWWindow = hwndGPU;                                   // store hwnd globally\r
+       #endif\r
+       // InitKeyHandler();                                     // init key handler (subclass window)\r
+\r
+\r
+\r
+                \r
+                \r
+       #ifdef _WINDOWS\r
+        iResX=240;iResY=320;\r
+       #endif\r
+        iColDepth=32;\r
+        bChangeRes=FALSE;\r
+       #ifdef _WINDOWS\r
+        bWindowMode=TRUE;\r
+       #else\r
+        bWindowMode=FALSE;\r
+       #endif \r
+        bFullVRam=FALSE;\r
+        iFilterType=0;\r
+       // bAdvancedBlend=FALSE;\r
+        bDrawDither=FALSE;\r
+       // bUseLines=FALSE;\r
+        bUseFrameLimit=FALSE;\r
+        bUseFrameSkip=FALSE;\r
+        iFrameLimit=0;\r
+        fFrameRate=50.0f;\r
+        iOffscreenDrawing=0;\r
+        //bOpaquePass=FALSE;\r
+        //bUseAntiAlias=FALSE;\r
+        //iTexQuality=0;\r
+       #ifdef _WINDOWS\r
+        iWinSize=MAKELONG(iResX,iResY);\r
+       #endif\r
+        iUseMask=0;\r
+        iZBufferDepth=0;\r
+        bUseFastMdec=FALSE;\r
+        bUse15bitMdec=FALSE;\r
+        dwCfgFixes=0;\r
+        bUseFixes=FALSE;\r
+       // iUseScanLines=0;\r
+        iFrameTexType=0;\r
+        iFrameReadType=0;\r
+        //iShowFPS=0;\r
+        bKeepRatio=TRUE;\r
+        iScanBlend=0;\r
+        iVRamSize=0;\r
+        iTexGarbageCollection=0;\r
+        iBlurBuffer=0; \r
+        //iHiResTextures=0;\r
+        iNoScreenSaver=0;\r
+ //iForceVSync=0;\r
+\r
+\r
+\r
+#ifdef _WINDOWS\r
+ memset(&dv,0,sizeof(DEVMODE));\r
+ dv.dmSize=sizeof(DEVMODE);\r
+ EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dv);\r
+#endif\r
+ bIsFirstFrame = TRUE;                                 // flag: we have to init OGL later in windows!\r
+\r
+#ifdef _WINDOWS\r
+ if(bWindowMode)                                       // win mode?\r
+  {\r
+   DWORD dw=GetWindowLong(hWWindow, GWL_STYLE);        // -> adjust wnd style (owndc needed by some stupid ogl drivers)\r
+   dw&=~WS_THICKFRAME;\r
+   dw|=WS_BORDER|WS_CAPTION|CS_OWNDC;\r
+   SetWindowLong(hWWindow, GWL_STYLE, dw);\r
+\r
+   hPSEMenu=GetMenu(hWWindow);                         // -> hide emu menu (if any)\r
+   if(hPSEMenu!=NULL) SetMenu(hWWindow,NULL);\r
+\r
+   iResX=LOWORD(iWinSize);iResY=HIWORD(iWinSize);\r
+   ShowWindow(hWWindow,SW_SHOWNORMAL);\r
+\r
+   MoveWindow(hWWindow,                                // -> center wnd\r
+      GetSystemMetrics(SM_CXFULLSCREEN)/2-iResX/2,\r
+      GetSystemMetrics(SM_CYFULLSCREEN)/2-iResY/2,\r
+      iResX+GetSystemMetrics(SM_CXFIXEDFRAME)+3,\r
+      iResY+GetSystemMetrics(SM_CYFIXEDFRAME)+GetSystemMetrics(SM_CYCAPTION)+3,\r
+      TRUE);\r
+   UpdateWindow(hWWindow);                             // -> let windows do some update\r
+\r
+   if(dv.dmBitsPerPel==16 || dv.dmBitsPerPel==32)      // -> overwrite user color info with desktop color info\r
+    iColDepth=dv.dmBitsPerPel;\r
+  }\r
+ else                                                  // fullscreen mode:\r
+  {\r
+   if(dv.dmBitsPerPel!=(unsigned int)iColDepth ||      // -> check, if we have to change resolution\r
+      dv.dmPelsWidth !=(unsigned int)iResX ||\r
+      dv.dmPelsHeight!=(unsigned int)iResY)\r
+    bChangeRes=TRUE; else bChangeRes=FALSE;\r
+\r
+   if(bChangeRes) ChangeDesktop();                     // -> change the res (had to do an own func because of some MS 'optimizations')\r
+\r
+   SetWindowLong(hWWindow, GWL_STYLE, CS_OWNDC);       // -> adjust wnd style as well (to be sure)\r
+                \r
+   hPSEMenu=GetMenu(hWWindow);                         // -> hide menu\r
+   if(hPSEMenu!=NULL) SetMenu(hWWindow,NULL);\r
+   ShowWindow(hWWindow,SW_SHOWMAXIMIZED);              // -> max mode\r
+  }\r
+#endif\r
+ rRatioRect.left   = rRatioRect.top=0;\r
+ rRatioRect.right  = iResX;\r
+ rRatioRect.bottom = iResY;\r
+\r
+#ifdef _WINDOWS\r
+ r.left=r.top=0;r.right=iResX;r.bottom=iResY;          // hack for getting a clean black window until OGL gets initialized\r
+ hdc = GetDC(hWWindow);\r
+ FillRect(hdc,&r,(HBRUSH)GetStockObject(BLACK_BRUSH));\r
+ bSetupPixelFormat(hdc);\r
+ ReleaseDC(hWWindow,hdc);\r
+#endif\r
+ bDisplayNotSet = TRUE; \r
+ bSetClip=TRUE;\r
+\r
+ SetFixes();                                           // setup game fixes\r
+\r
+ InitializeTextureStore();                             // init texture mem\r
+\r
+// lGPUstatusRet = 0x74000000;\r
+\r
+// with some emus, we could do the OGL init right here... oh my\r
+// if(bIsFirstFrame) GLinitialize();\r
+\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// close\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUclose()                               // WINDOWS CLOSE\r
+{\r
+// ExitKeyHandler();\r
+\r
+ GLcleanup();                                          // close OGL\r
+\r
+ if(bChangeRes)                                        // change res back\r
+  ChangeDisplaySettings(NULL,0);\r
+\r
+ if(hPSEMenu)                                          // set menu again\r
+  SetMenu(hWWindow,hPSEMenu);\r
+\r
+ if(pGfxCardScreen) free(pGfxCardScreen);              // free helper memory\r
+ pGfxCardScreen=0;\r
+\r
+// if(iNoScreenSaver) EnableScreenSaver(TRUE);           // enable screen saver again\r
+\r
+ return 0;\r
+}\r
+\r
+#else\r
+\r
+long GPU_close()                                        // LINUX CLOSE\r
+{\r
+ GLcleanup();                                          // close OGL\r
+\r
+ if(pGfxCardScreen) free(pGfxCardScreen);              // free helper memory\r
+ pGfxCardScreen=0;\r
+\r
+// osd_close_display();                                  // destroy display\r
+\r
+ return 0;\r
+}\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// I shot the sheriff... last function called from emu \r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUshutdown()\r
+#else\r
+long CALLBACK GPU_shutdown()\r
+#endif\r
+{\r
+ if(psxVSecure) free(psxVSecure);                      // kill emulated vram memory\r
+ psxVSecure=0;\r
+\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// paint it black: simple func to clean up optical border garbage\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void PaintBlackBorders(void)\r
+{\r
+ short s;\r
+\r
+ glDisable(GL_SCISSOR_TEST);\r
+ if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}\r
+ if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}\r
+ if(bBlendEnable)     {glDisable(GL_BLEND);bBlendEnable=FALSE;}\r
+ glDisable(GL_ALPHA_TEST);\r
+\r
+ glEnable(GL_ALPHA_TEST);\r
+ glEnable(GL_SCISSOR_TEST);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// helper to draw scanlines\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+__inline void XPRIMdrawTexturedQuad(OGLVertex* vertex1, OGLVertex* vertex2, \r
+                                    OGLVertex* vertex3, OGLVertex* vertex4) \r
+{\r
+\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// scanlines\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetScanLines(void)\r
+{\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// blur, babe, blur (heavy performance hit for a so-so fullscreen effect)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// Update display (swap buffers)... called in interlaced mode on \r
+// every emulated vsync, otherwise whenever the displayed screen region\r
+// has been changed\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+int iLastRGB24=0;                                      // special vars for checking when to skip two display updates\r
+int iSkipTwo=0;\r
+void GPU_vSinc(void){\r
+updateDisplay();\r
+}\r
+void updateDisplay(void)                               // UPDATE DISPLAY\r
+{\r
+BOOL bBlur=FALSE;\r
+\r
+#ifdef _WINDOWS\r
+HDC hdc=GetDC(hWWindow);                              // windows:\r
+wglMakeCurrent(hdc,GLCONTEXT);                        // -> make context current again\r
+#endif\r
+\r
+bFakeFrontBuffer=FALSE;\r
+bRenderFrontBuffer=FALSE;\r
+\r
+if(iRenderFVR)                                        // frame buffer read fix mode still active?\r
+ {\r
+  iRenderFVR--;                                       // -> if some frames in a row without read access: turn off mode\r
+  if(!iRenderFVR) bFullVRam=FALSE;\r
+ }\r
+\r
+if(iLastRGB24 && iLastRGB24!=PSXDisplay.RGB24+1)      // (mdec) garbage check\r
+ {\r
+  iSkipTwo=2;                                         // -> skip two frames to avoid garbage if color mode changes\r
+ }\r
+iLastRGB24=0;\r
+\r
+if(PSXDisplay.RGB24)// && !bNeedUploadAfter)          // (mdec) upload wanted?\r
+ {\r
+  PrepareFullScreenUpload(-1);\r
+  UploadScreen(PSXDisplay.Interlaced);                // -> upload whole screen from psx vram\r
+  bNeedUploadTest=FALSE;\r
+  bNeedInterlaceUpdate=FALSE;\r
+  bNeedUploadAfter=FALSE;\r
+  bNeedRGB24Update=FALSE;\r
+ }\r
+else\r
+if(bNeedInterlaceUpdate)                              // smaller upload?\r
+ {\r
+  bNeedInterlaceUpdate=FALSE;\r
+  xrUploadArea=xrUploadAreaIL;                        // -> upload this rect\r
+  UploadScreen(TRUE);\r
+ }\r
+\r
+if(dwActFixes&512) bCheckFF9G4(NULL);                 // special game fix for FF9 \r
+\r
+if(PreviousPSXDisplay.Range.x0||                      // paint black borders around display area, if needed\r
+   PreviousPSXDisplay.Range.y0)\r
+ PaintBlackBorders();\r
+\r
+if(PSXDisplay.Disabled)                               // display disabled?\r
+ {\r
+  // moved here\r
+  glDisable(GL_SCISSOR_TEST);                       \r
+  glClearColor(0,0,0,128);                            // -> clear whole backbuffer\r
+  glClear(uiBufferBits);\r
+  glEnable(GL_SCISSOR_TEST);                       \r
+  gl_z=0.0f;\r
+  bDisplayNotSet = TRUE;\r
+ }\r
+\r
+if(iSkipTwo)                                          // we are in skipping mood?\r
+ {\r
+  iSkipTwo--;\r
+  iDrawnSomething=0;                                  // -> simply lie about something drawn\r
+ }\r
+\r
+//if(iBlurBuffer && !bSkipNextFrame)                    // "blur display" activated?\r
+// {BlurBackBuffer();bBlur=TRUE;}                       // -> blur it\r
+\r
+// if(iUseScanLines) SetScanLines();                     // "scan lines" activated? do it\r
+\r
+// if(usCursorActive) ShowGunCursor();                   // "gun cursor" wanted? show 'em\r
+\r
+if(dwActFixes&128)                                    // special FPS limitation mode?\r
+ {\r
+  if(bUseFrameLimit) PCFrameCap();                    // -> ok, do it\r
+//   if(bUseFrameSkip || ulKeybits&KEY_SHOWFPS)  \r
+   PCcalcfps();         \r
+ }\r
+\r
+// if(gTexPicName) DisplayPic();                         // some gpu info picture active? display it\r
+\r
+// if(bSnapShot) DoSnapShot();                           // snapshot key pressed? cheeeese :)\r
+\r
+// if(ulKeybits&KEY_SHOWFPS)                             // wanna see FPS?\r
+ {\r
+//   sprintf(szDispBuf,"%06.1f",fps_cur);\r
+//   DisplayText();                                      // -> show it\r
+ }\r
+\r
+//----------------------------------------------------//\r
+// main buffer swapping (well, or skip it)\r
+\r
+if(bUseFrameSkip)                                     // frame skipping active ?\r
+ {\r
+  if(!bSkipNextFrame) \r
+   {\r
+    if(iDrawnSomething)\r
+#ifdef _WINDOWS\r
+     SwapBuffers(wglGetCurrentDC());                  // -> to skip or not to skip\r
+#else\r
+     eglSwapBuffers(display,surface);\r
+#endif\r
+   }\r
+  if(dwActFixes&0x180)                                // -> special old frame skipping: skip max one in a row\r
+   {\r
+    if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) \r
+     {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}\r
+    else bSkipNextFrame = FALSE;\r
+   }\r
+  else FrameSkip();\r
+ }\r
+else                                                  // no skip ?\r
+ {\r
+  if(iDrawnSomething)\r
+#ifdef _WINDOWS\r
+   SwapBuffers(wglGetCurrentDC());                    // -> swap\r
+#else\r
+  eglSwapBuffers(display,surface);\r
+#endif\r
+ }\r
+\r
+iDrawnSomething=0;\r
+\r
+//----------------------------------------------------//\r
+\r
+if(lClearOnSwap)                                      // clear buffer after swap?\r
+ {\r
+  GLclampf g,b,r;\r
+\r
+  if(bDisplayNotSet)                                  // -> set new vals\r
+   SetOGLDisplaySettings(1);\r
+\r
+  g=((GLclampf)GREEN(lClearOnSwapColor))/255.0f;      // -> get col\r
+  b=((GLclampf)BLUE(lClearOnSwapColor))/255.0f;\r
+  r=((GLclampf)RED(lClearOnSwapColor))/255.0f;\r
+  \r
+  glDisable(GL_SCISSOR_TEST);                       \r
+  glClearColor(r,g,b,128);                            // -> clear \r
+  glClear(uiBufferBits);\r
+  glEnable(GL_SCISSOR_TEST);                       \r
+  lClearOnSwap=0;                                     // -> done\r
+ }\r
+else \r
+ {\r
+//  if(bBlur) UnBlurBackBuffer();                       // unblur buff, if blurred before\r
+\r
+  if(iZBufferDepth)                                   // clear zbuffer as well (if activated)\r
+   {\r
+    glDisable(GL_SCISSOR_TEST);                       \r
+    glClear(GL_DEPTH_BUFFER_BIT);\r
+    glEnable(GL_SCISSOR_TEST);                       \r
+   }\r
+ }\r
+gl_z=0.0f;\r
+\r
+//----------------------------------------------------//\r
+// additional uploads immediatly after swapping\r
+\r
+if(bNeedUploadAfter)                                  // upload wanted?\r
+ {\r
+  bNeedUploadAfter=FALSE;                           \r
+  bNeedUploadTest=FALSE;\r
+  UploadScreen(-1);                                   // -> upload\r
+ }\r
+\r
+if(bNeedUploadTest)\r
+ {\r
+  bNeedUploadTest=FALSE;\r
+  if(PSXDisplay.InterlacedTest &&\r
+     //iOffscreenDrawing>2 &&\r
+     PreviousPSXDisplay.DisplayPosition.x==PSXDisplay.DisplayPosition.x &&\r
+     PreviousPSXDisplay.DisplayEnd.x==PSXDisplay.DisplayEnd.x &&\r
+     PreviousPSXDisplay.DisplayPosition.y==PSXDisplay.DisplayPosition.y &&\r
+     PreviousPSXDisplay.DisplayEnd.y==PSXDisplay.DisplayEnd.y)\r
+   {\r
+    PrepareFullScreenUpload(TRUE);\r
+    UploadScreen(TRUE);\r
+   }\r
+ }\r
+\r
+//----------------------------------------------------//\r
+// rumbling (main emu pad effect)\r
+\r
+if(iRumbleTime)                                       // shake screen by modifying view port\r
+ {\r
+  int i1=0,i2=0,i3=0,i4=0;\r
+\r
+  iRumbleTime--;\r
+  if(iRumbleTime) \r
+   {\r
+    i1=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
+    i2=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
+    i3=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
+    i4=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); \r
+   }\r
+\r
+  glViewport(rRatioRect.left+i1,                      \r
+             iResY-(rRatioRect.top+rRatioRect.bottom)+i2,\r
+             rRatioRect.right+i3, \r
+             rRatioRect.bottom+i4);            \r
+ }\r
+\r
+//----------------------------------------------------//\r
+\r
+\r
+\r
+// if(ulKeybits&KEY_RESETTEXSTORE) ResetStuff();         // reset on gpu mode changes? do it before next frame is filled\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// update front display: smaller update func, if something has changed \r
+// in the frontbuffer... dirty, but hey... real men know no pain\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void updateFrontDisplay(void)\r
+{\r
+if(PreviousPSXDisplay.Range.x0||\r
+   PreviousPSXDisplay.Range.y0)\r
+ PaintBlackBorders();\r
+\r
+//if(iBlurBuffer) BlurBackBuffer();\r
+\r
+//if(iUseScanLines) SetScanLines();\r
+\r
+// if(usCursorActive) ShowGunCursor();\r
+\r
+bFakeFrontBuffer=FALSE;\r
+bRenderFrontBuffer=FALSE;\r
+\r
+// if(gTexPicName) DisplayPic();\r
+// if(ulKeybits&KEY_SHOWFPS) DisplayText();\r
+\r
+#ifdef _WINDOWS\r
+ {                                                    // windows: \r
+  HDC hdc=GetDC(hWWindow);\r
+  wglMakeCurrent(hdc,GLCONTEXT);                      // -> make current again\r
+  if(iDrawnSomething)\r
+   SwapBuffers(wglGetCurrentDC());                    // -> swap\r
+  ReleaseDC(hWWindow,hdc);                            // -> ! important !\r
+ }\r
+#else\r
+if(iDrawnSomething)                                   // linux:\r
+ eglSwapBuffers(display,surface);\r
+#endif\r
+\r
+//if(iBlurBuffer) UnBlurBackBuffer();\r
+}\r
+                                             \r
+////////////////////////////////////////////////////////////////////////\r
+// check if update needed\r
+////////////////////////////////////////////////////////////////////////\r
+void ChangeDispOffsetsX(void)                          // CENTER X\r
+{\r
+long lx,l;short sO;\r
+\r
+if(!PSXDisplay.Range.x1) return;                      // some range given?\r
+\r
+l=PSXDisplay.DisplayMode.x;\r
+\r
+l*=(long)PSXDisplay.Range.x1;                         // some funky calculation\r
+l/=2560;lx=l;l&=0xfffffff8;\r
+\r
+if(l==PreviousPSXDisplay.Range.x1) return;            // some change?\r
+\r
+sO=PreviousPSXDisplay.Range.x0;                       // store old\r
+\r
+if(lx>=PSXDisplay.DisplayMode.x)                      // range bigger?\r
+ {\r
+  PreviousPSXDisplay.Range.x1=                        // -> take display width\r
+   PSXDisplay.DisplayMode.x;\r
+  PreviousPSXDisplay.Range.x0=0;                      // -> start pos is 0\r
+ }\r
+else                                                  // range smaller? center it\r
+ {\r
+  PreviousPSXDisplay.Range.x1=l;                      // -> store width (8 pixel aligned)\r
+   PreviousPSXDisplay.Range.x0=                       // -> calc start pos\r
+   (PSXDisplay.Range.x0-500)/8;\r
+  if(PreviousPSXDisplay.Range.x0<0)                   // -> we don't support neg. values yet\r
+   PreviousPSXDisplay.Range.x0=0;\r
+\r
+  if((PreviousPSXDisplay.Range.x0+lx)>                // -> uhuu... that's too much\r
+     PSXDisplay.DisplayMode.x)\r
+   {\r
+    PreviousPSXDisplay.Range.x0=                      // -> adjust start\r
+     PSXDisplay.DisplayMode.x-lx;\r
+    PreviousPSXDisplay.Range.x1+=lx-l;                // -> adjust width\r
+   }                   \r
+ }\r
+\r
+if(sO!=PreviousPSXDisplay.Range.x0)                   // something changed?\r
+ {\r
+  bDisplayNotSet=TRUE;                                // -> recalc display stuff\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void ChangeDispOffsetsY(void)                          // CENTER Y\r
+{\r
+int iT;short sO;                                      // store previous y size\r
+\r
+if(PSXDisplay.PAL) iT=48; else iT=28;                 // different offsets on PAL/NTSC\r
+\r
+if(PSXDisplay.Range.y0>=iT)                           // crossed the security line? :)\r
+ {\r
+  PreviousPSXDisplay.Range.y1=                        // -> store width\r
+   PSXDisplay.DisplayModeNew.y;\r
+  \r
+  sO=(PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double;    // -> calc offset\r
+  if(sO<0) sO=0;\r
+\r
+  PSXDisplay.DisplayModeNew.y+=sO;                    // -> add offset to y size, too\r
+ }\r
+else sO=0;                                            // else no offset\r
+\r
+if(sO!=PreviousPSXDisplay.Range.y0)                   // something changed?\r
+ {\r
+  PreviousPSXDisplay.Range.y0=sO;\r
+  bDisplayNotSet=TRUE;                                // -> recalc display stuff\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// Aspect ratio of ogl screen: simply adjusting ogl view port\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetAspectRatio(void)\r
+{\r
+float xs,ys,s;RECT r;\r
+\r
+if(!PSXDisplay.DisplayModeNew.x) return;\r
+if(!PSXDisplay.DisplayModeNew.y) return;\r
+\r
+xs=(float)iResX/(float)PSXDisplay.DisplayModeNew.x;\r
+ys=(float)iResY/(float)PSXDisplay.DisplayModeNew.y;\r
+\r
+s=min(xs,ys);\r
+r.right =(int)((float)PSXDisplay.DisplayModeNew.x*s);\r
+r.bottom=(int)((float)PSXDisplay.DisplayModeNew.y*s);\r
+if(r.right  > iResX) r.right  = iResX;\r
+if(r.bottom > iResY) r.bottom = iResY;\r
+if(r.right  < 1)     r.right  = 1;\r
+if(r.bottom < 1)     r.bottom = 1;\r
+\r
+r.left = (iResX-r.right)/2;\r
+r.top  = (iResY-r.bottom)/2;\r
+\r
+if(r.bottom<rRatioRect.bottom ||\r
+   r.right <rRatioRect.right)\r
+ {\r
+  RECT rC;\r
+  glClearColor(0,0,0,128);                         \r
+\r
+  if(r.right <rRatioRect.right)\r
+   {\r
+    rC.left=0;\r
+    rC.top=0;\r
+    rC.right=r.left;\r
+    rC.bottom=iResY;\r
+    glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
+    glClear(uiBufferBits);\r
+    rC.left=iResX-rC.right;\r
+    glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
+    glClear(uiBufferBits);\r
+   }\r
+\r
+  if(r.bottom <rRatioRect.bottom)\r
+   {\r
+    rC.left=0;\r
+    rC.top=0;\r
+    rC.right=iResX;\r
+    rC.bottom=r.top;\r
+    glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
+    glClear(uiBufferBits);\r
+    rC.top=iResY-rC.bottom;\r
+    glScissor(rC.left,rC.top,rC.right,rC.bottom);\r
+    glClear(uiBufferBits);\r
+   }\r
+  \r
+  bSetClip=TRUE;\r
+  bDisplayNotSet=TRUE;\r
+ }\r
+\r
+rRatioRect=r;\r
+\r
+\r
+glViewport(rRatioRect.left,\r
+           iResY-(rRatioRect.top+rRatioRect.bottom),\r
+           rRatioRect.right,\r
+           rRatioRect.bottom);                         // init viewport\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// big ass check, if an ogl swap buffer is needed\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void updateDisplayIfChanged(void)\r
+{\r
+BOOL bUp;\r
+\r
+if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) && \r
+    (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))\r
+ {\r
+  if((PSXDisplay.RGB24      == PSXDisplay.RGB24New) && \r
+     (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) \r
+     return;                                          // nothing has changed? fine, no swap buffer needed\r
+ }\r
+else                                                  // some res change?\r
+ {\r
+  glLoadIdentity();\r
+  glOrtho(0,PSXDisplay.DisplayModeNew.x,              // -> new psx resolution\r
+            PSXDisplay.DisplayModeNew.y, 0, -1, 1);\r
+  if(bKeepRatio) SetAspectRatio();\r
+ }\r
+\r
+bDisplayNotSet = TRUE;                                // re-calc offsets/display area\r
+\r
+bUp=FALSE;\r
+if(PSXDisplay.RGB24!=PSXDisplay.RGB24New)             // clean up textures, if rgb mode change (usually mdec on/off)\r
+ {\r
+  PreviousPSXDisplay.RGB24=0;                         // no full 24 frame uploaded yet\r
+  ResetTextureArea(FALSE);\r
+  bUp=TRUE;\r
+ }\r
+\r
+PSXDisplay.RGB24         = PSXDisplay.RGB24New;       // get new infos\r
+PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;\r
+PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;\r
+PSXDisplay.Interlaced    = PSXDisplay.InterlacedNew;\r
+   \r
+PSXDisplay.DisplayEnd.x=                              // calc new ends\r
+ PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
+PSXDisplay.DisplayEnd.y=\r
+ PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
+PreviousPSXDisplay.DisplayEnd.x=\r
+ PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
+PreviousPSXDisplay.DisplayEnd.y=\r
+ PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
+\r
+ChangeDispOffsetsX();\r
+\r
+if(iFrameLimit==2) SetAutoFrameCap();                 // set new fps limit vals (depends on interlace)\r
+\r
+if(bUp) updateDisplay();                              // yeah, real update (swap buffer)\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// window mode <-> fullscreen mode (windows)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void ChangeWindowMode(void)\r
+{\r
+ GPUclose();\r
+ bWindowMode=!bWindowMode;\r
+ GPUopen(hWWindow);\r
+ bChangeWinMode=FALSE;\r
+}\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// swap update check (called by psx vsync function)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+BOOL bSwapCheck(void)\r
+{\r
+static int iPosCheck=0;\r
+static PSXPoint_t pO;\r
+static PSXPoint_t pD;\r
+static int iDoAgain=0;\r
+\r
+if(PSXDisplay.DisplayPosition.x==pO.x &&\r
+   PSXDisplay.DisplayPosition.y==pO.y &&\r
+   PSXDisplay.DisplayEnd.x==pD.x &&\r
+   PSXDisplay.DisplayEnd.y==pD.y)\r
+     iPosCheck++;\r
+else iPosCheck=0;\r
+\r
+pO=PSXDisplay.DisplayPosition;\r
+pD=PSXDisplay.DisplayEnd;\r
+\r
+if(iPosCheck<=4) return FALSE;\r
+\r
+iPosCheck=4;\r
+\r
+if(PSXDisplay.Interlaced) return FALSE;\r
+\r
+if (bNeedInterlaceUpdate||\r
+    bNeedRGB24Update ||\r
+    bNeedUploadAfter|| \r
+    bNeedUploadTest || \r
+    iDoAgain\r
+   )\r
+ {\r
+  iDoAgain=0;\r
+  if(bNeedUploadAfter) \r
+   iDoAgain=1;\r
+  if(bNeedUploadTest && PSXDisplay.InterlacedTest)\r
+   iDoAgain=1;\r
+\r
+  bDisplayNotSet = TRUE;\r
+  updateDisplay();\r
+\r
+  PreviousPSXDisplay.DisplayPosition.x=PSXDisplay.DisplayPosition.x;\r
+  PreviousPSXDisplay.DisplayPosition.y=PSXDisplay.DisplayPosition.y;\r
+  PreviousPSXDisplay.DisplayEnd.x=PSXDisplay.DisplayEnd.x;\r
+  PreviousPSXDisplay.DisplayEnd.y=PSXDisplay.DisplayEnd.y;\r
+  pO=PSXDisplay.DisplayPosition;\r
+  pD=PSXDisplay.DisplayEnd;\r
+\r
+  return TRUE;\r
+ }\r
+\r
+return FALSE;\r
+} \r
+////////////////////////////////////////////////////////////////////////\r
+// gun cursor func: player=0-7, x=0-511, y=0-255\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// update lace is called every VSync. Basically we limit frame rate \r
+// here, and in interlaced mode we swap ogl display buffers.\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+static unsigned short usFirstPos=2;\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUupdateLace(void)\r
+#else\r
+void CALLBACK GPU_updateLace(void)\r
+#endif\r
+{\r
+if(!(dwActFixes&0x1000))                               \r
+ STATUSREG^=0x80000000;                               // interlaced bit toggle, if the CC game fix is not active (see gpuReadStatus)\r
+\r
+if(!(dwActFixes&128))                                 // normal frame limit func\r
+ CheckFrameRate();\r
+\r
+if(iOffscreenDrawing==4)                              // special check if high offscreen drawing is on\r
+ {\r
+  if(bSwapCheck()) return;\r
+ }\r
+\r
+if(PSXDisplay.Interlaced)                             // interlaced mode?\r
+ {\r
+  if(PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)\r
+   {\r
+    updateDisplay();                                  // -> swap buffers (new frame)\r
+   }\r
+ }\r
+else if(bRenderFrontBuffer)                           // no interlace mode? and some stuff in front has changed?\r
+ {\r
+  updateFrontDisplay();                               // -> update front buffer\r
+ }\r
+else if(usFirstPos==1)                                // initial updates (after startup)\r
+ {\r
+  updateDisplay();\r
+ }\r
+\r
+#ifdef _WINDOWS\r
+if(bChangeWinMode) ChangeWindowMode();\r
+#endif\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// process read request from GPU status register\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+unsigned long CALLBACK GPUreadStatus(void)\r
+#else\r
+unsigned long CALLBACK GPU_readStatus(void)\r
+#endif\r
+{\r
+if(dwActFixes&0x1000)                                 // CC game fix\r
+ {\r
+  static int iNumRead=0;\r
+  if((iNumRead++)==2)\r
+   {\r
+    iNumRead=0;\r
+    STATUSREG^=0x80000000;                            // interlaced bit toggle... we do it on every second read status... needed by some games (like ChronoCross)\r
+   }\r
+ }\r
+\r
+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
+ {\r
+  iFakePrimBusy--;\r
+\r
+  if(iFakePrimBusy&1)                                 // we do a busy-idle-busy-idle sequence after/while drawing prims\r
+   {\r
+    GPUIsBusy;\r
+    GPUIsNotReadyForCommands;\r
+   }\r
+  else\r
+   {\r
+    GPUIsIdle;\r
+    GPUIsReadyForCommands;\r
+   }\r
+ }\r
+\r
+return STATUSREG;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// processes data send to GPU status register\r
+// these are always single packet commands.\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUwriteStatus(unsigned long gdata)\r
+#else\r
+void CALLBACK GPU_writeStatus(unsigned long gdata)\r
+#endif\r
+{\r
+unsigned long lCommand=(gdata>>24)&0xff;\r
+\r
+#ifdef _WINDOWS\r
+if(bIsFirstFrame) GLinitialize();                     // real ogl startup (needed by some emus)\r
+#endif\r
+\r
+ulStatusControl[lCommand]=gdata;\r
+\r
+switch(lCommand)\r
+ {\r
+  //--------------------------------------------------//\r
+  // reset gpu\r
+  case 0x00:\r
+   memset(ulGPUInfoVals,0x00,16*sizeof(unsigned long));\r
+   lGPUstatusRet=0x14802000;\r
+   PSXDisplay.Disabled=1;\r
+   iDataWriteMode=iDataReadMode=DR_NORMAL;\r
+   PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;\r
+   drawX=drawY=0;drawW=drawH=0;\r
+   sSetMask=0;lSetMask=0;bCheckMask=FALSE;iSetMask=0;\r
+   usMirror=0;\r
+   GlobalTextAddrX=0;GlobalTextAddrY=0;\r
+   GlobalTextTP=0;GlobalTextABR=0;\r
+   PSXDisplay.RGB24=FALSE;\r
+   PSXDisplay.Interlaced=FALSE;\r
+   bUsingTWin = FALSE;\r
+   return;\r
+\r
+  // dis/enable display\r
+  case 0x03:  \r
+   PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;\r
+   PSXDisplay.Disabled = (gdata & 1);\r
+\r
+   if(PSXDisplay.Disabled) \r
+        STATUSREG|=GPUSTATUS_DISPLAYDISABLED;\r
+   else STATUSREG&=~GPUSTATUS_DISPLAYDISABLED;\r
+\r
+   if (iOffscreenDrawing==4 &&\r
+        PreviousPSXDisplay.Disabled && \r
+       !(PSXDisplay.Disabled))\r
+    {\r
+\r
+     if(!PSXDisplay.RGB24)\r
+      {\r
+       PrepareFullScreenUpload(TRUE);\r
+       UploadScreen(TRUE); \r
+       updateDisplay();\r
+      }\r
+    }\r
+\r
+   return;\r
+\r
+  // setting transfer mode\r
+  case 0x04:\r
+   gdata &= 0x03;                                     // only want the lower two bits\r
+\r
+   iDataWriteMode=iDataReadMode=DR_NORMAL;\r
+   if(gdata==0x02) iDataWriteMode=DR_VRAMTRANSFER;\r
+   if(gdata==0x03) iDataReadMode =DR_VRAMTRANSFER;\r
+\r
+   STATUSREG&=~GPUSTATUS_DMABITS;                     // clear the current settings of the DMA bits\r
+   STATUSREG|=(gdata << 29);                          // set the DMA bits according to the received data\r
+\r
+   return;\r
+\r
+  // setting display position\r
+  case 0x05: \r
+   {\r
+    short sx=(short)(gdata & 0x3ff);\r
+    short sy;\r
+\r
+    if(iGPUHeight==1024)\r
+     {\r
+      if(dwGPUVersion==2) \r
+           sy = (short)((gdata>>12)&0x3ff);\r
+      else sy = (short)((gdata>>10)&0x3ff);\r
+     }\r
+    else sy = (short)((gdata>>10)&0x3ff);             // really: 0x1ff, but we adjust it later\r
+\r
+    if (sy & 0x200) \r
+     {\r
+      sy|=0xfc00;\r
+      PreviousPSXDisplay.DisplayModeNew.y=sy/PSXDisplay.Double;\r
+      sy=0;\r
+     }\r
+    else PreviousPSXDisplay.DisplayModeNew.y=0;\r
+\r
+    if(sx>1000) sx=0;\r
+\r
+    if(usFirstPos)\r
+     {\r
+      usFirstPos--;\r
+      if(usFirstPos)\r
+       {\r
+        PreviousPSXDisplay.DisplayPosition.x = sx;\r
+        PreviousPSXDisplay.DisplayPosition.y = sy;\r
+        PSXDisplay.DisplayPosition.x = sx;\r
+        PSXDisplay.DisplayPosition.y = sy;\r
+       }\r
+     }\r
+\r
+    if(dwActFixes&8) \r
+     {\r
+      if((!PSXDisplay.Interlaced) &&\r
+         PreviousPSXDisplay.DisplayPosition.x == sx  &&\r
+         PreviousPSXDisplay.DisplayPosition.y == sy)\r
+       return;\r
+\r
+      PSXDisplay.DisplayPosition.x = PreviousPSXDisplay.DisplayPosition.x;\r
+      PSXDisplay.DisplayPosition.y = PreviousPSXDisplay.DisplayPosition.y;\r
+      PreviousPSXDisplay.DisplayPosition.x = sx;\r
+      PreviousPSXDisplay.DisplayPosition.y = sy;\r
+     }\r
+    else\r
+     {\r
+      if((!PSXDisplay.Interlaced) &&\r
+         PSXDisplay.DisplayPosition.x == sx  &&\r
+         PSXDisplay.DisplayPosition.y == sy)\r
+       return;\r
+      PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;\r
+      PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;\r
+      PSXDisplay.DisplayPosition.x = sx;\r
+      PSXDisplay.DisplayPosition.y = sy;\r
+     }\r
+\r
+    PSXDisplay.DisplayEnd.x=\r
+     PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
+    PSXDisplay.DisplayEnd.y=\r
+     PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
+\r
+    PreviousPSXDisplay.DisplayEnd.x=\r
+     PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;\r
+    PreviousPSXDisplay.DisplayEnd.y=\r
+     PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;\r
+\r
+    bDisplayNotSet = TRUE;\r
+\r
+    if (!(PSXDisplay.Interlaced))\r
+     {\r
+      updateDisplay();\r
+     }\r
+    else\r
+    if(PSXDisplay.InterlacedTest && \r
+       ((PreviousPSXDisplay.DisplayPosition.x != PSXDisplay.DisplayPosition.x)||\r
+        (PreviousPSXDisplay.DisplayPosition.y != PSXDisplay.DisplayPosition.y)))\r
+     PSXDisplay.InterlacedTest--;\r
+\r
+    return;\r
+   }\r
+\r
+  // setting width\r
+  case 0x06:\r
+\r
+   PSXDisplay.Range.x0=gdata & 0x7ff;      //0x3ff;\r
+   PSXDisplay.Range.x1=(gdata>>12) & 0xfff;//0x7ff;\r
+\r
+   PSXDisplay.Range.x1-=PSXDisplay.Range.x0;\r
+\r
+   ChangeDispOffsetsX();\r
+\r
+   return;\r
+\r
+  // setting height\r
+  case 0x07:\r
+\r
+   PreviousPSXDisplay.Height = PSXDisplay.Height;\r
+\r
+   PSXDisplay.Range.y0=gdata & 0x3ff;\r
+   PSXDisplay.Range.y1=(gdata>>10) & 0x3ff;\r
+\r
+   PSXDisplay.Height = PSXDisplay.Range.y1 - \r
+                       PSXDisplay.Range.y0 +\r
+                       PreviousPSXDisplay.DisplayModeNew.y;\r
+\r
+   if (PreviousPSXDisplay.Height != PSXDisplay.Height)\r
+    {\r
+     PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;\r
+     ChangeDispOffsetsY();\r
+     updateDisplayIfChanged();\r
+    }\r
+   return;\r
+\r
+  // setting display infos\r
+  case 0x08:\r
+\r
+   PSXDisplay.DisplayModeNew.x = dispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];\r
+\r
+   if (gdata&0x04) PSXDisplay.Double=2;\r
+   else            PSXDisplay.Double=1;\r
+   PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;\r
+\r
+   ChangeDispOffsetsY();\r
\r
+   PSXDisplay.PAL           = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC\r
+   PSXDisplay.RGB24New      = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor\r
+   PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace\r
+\r
+   STATUSREG&=~GPUSTATUS_WIDTHBITS;                   // clear the width bits\r
+\r
+   STATUSREG|=\r
+              (((gdata & 0x03) << 17) | \r
+              ((gdata & 0x40) << 10));                // set the width bits\r
+\r
+   PreviousPSXDisplay.InterlacedNew=FALSE;\r
+   if (PSXDisplay.InterlacedNew)\r
+    {\r
+     if(!PSXDisplay.Interlaced)\r
+      {\r
+       PSXDisplay.InterlacedTest=2;\r
+       PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;\r
+       PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;\r
+       PreviousPSXDisplay.InterlacedNew=TRUE;\r
+      }\r
+\r
+     STATUSREG|=GPUSTATUS_INTERLACED;\r
+    }\r
+   else \r
+    {\r
+     PSXDisplay.InterlacedTest=0;\r
+     STATUSREG&=~GPUSTATUS_INTERLACED;\r
+    }\r
+\r
+   if (PSXDisplay.PAL)\r
+        STATUSREG|=GPUSTATUS_PAL;\r
+   else STATUSREG&=~GPUSTATUS_PAL;\r
+\r
+   if (PSXDisplay.Double==2)\r
+        STATUSREG|=GPUSTATUS_DOUBLEHEIGHT;\r
+   else STATUSREG&=~GPUSTATUS_DOUBLEHEIGHT;\r
+\r
+   if (PSXDisplay.RGB24New)\r
+        STATUSREG|=GPUSTATUS_RGB24;\r
+   else STATUSREG&=~GPUSTATUS_RGB24;\r
+\r
+   updateDisplayIfChanged();\r
+\r
+   return;\r
+\r
+  //--------------------------------------------------//\r
+  // ask about GPU version and other stuff\r
+  case 0x10: \r
+\r
+   gdata&=0xff;\r
+\r
+   switch(gdata) \r
+    {\r
+     case 0x02:\r
+      GPUdataRet=ulGPUInfoVals[INFO_TW];              // tw infos\r
+      return;\r
+     case 0x03:\r
+      GPUdataRet=ulGPUInfoVals[INFO_DRAWSTART];       // draw start\r
+      return;\r
+     case 0x04:\r
+      GPUdataRet=ulGPUInfoVals[INFO_DRAWEND];         // draw end\r
+      return;\r
+     case 0x05:\r
+     case 0x06:\r
+      GPUdataRet=ulGPUInfoVals[INFO_DRAWOFF];         // draw offset\r
+      return;\r
+     case 0x07:\r
+      if(dwGPUVersion==2)\r
+           GPUdataRet=0x01;\r
+      else GPUdataRet=0x02;                           // gpu type\r
+      return;\r
+     case 0x08:\r
+     case 0x0F:                                       // some bios addr?\r
+      GPUdataRet=0xBFC03720;\r
+      return;\r
+    }\r
+   return;\r
+  //--------------------------------------------------//\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// vram read/write helpers\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+BOOL bNeedWriteUpload=FALSE;\r
+\r
+__inline void FinishedVRAMWrite(void)\r
+{\r
+ if(bNeedWriteUpload)\r
+  {\r
+   bNeedWriteUpload=FALSE;\r
+   CheckWriteUpdate();\r
+  }\r
+\r
+ // set register to NORMAL operation\r
+ iDataWriteMode = DR_NORMAL;\r
+\r
+ // reset transfer values, to prevent mis-transfer of data\r
+ VRAMWrite.ColsRemaining = 0;\r
+ VRAMWrite.RowsRemaining = 0;\r
+}\r
+\r
+__inline void FinishedVRAMRead(void)\r
+{\r
+ // set register to NORMAL operation\r
+ iDataReadMode = DR_NORMAL;\r
+ // reset transfer values, to prevent mis-transfer of data\r
+ VRAMRead.x = 0;\r
+ VRAMRead.y = 0;\r
+ VRAMRead.Width = 0;\r
+ VRAMRead.Height = 0;\r
+ VRAMRead.ColsRemaining = 0;\r
+ VRAMRead.RowsRemaining = 0;\r
+\r
+ // indicate GPU is no longer ready for VRAM data in the STATUS REGISTER\r
+ STATUSREG&=~GPUSTATUS_READYFORVRAM;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// vram read check ex (reading from card's back/frontbuffer if needed...\r
+// slow!)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CheckVRamReadEx(int x, int y, int dx, int dy)\r
+{\r
+ unsigned short sArea;\r
+ int ux,uy,udx,udy,wx,wy;\r
+ unsigned short * p1, *p2;\r
+ float XS,YS;\r
+ u8 * ps;\r
+ u8 * px;\r
+ unsigned short s,sx;\r
+\r
+ if(STATUSREG&GPUSTATUS_RGB24) return;\r
+\r
+ if(((dx  > PSXDisplay.DisplayPosition.x) &&\r
+     (x   < PSXDisplay.DisplayEnd.x) &&\r
+     (dy  > PSXDisplay.DisplayPosition.y) &&\r
+     (y   < PSXDisplay.DisplayEnd.y)))\r
+  sArea=0;\r
+ else\r
+ if((!(PSXDisplay.InterlacedTest) &&\r
+     (dx  > PreviousPSXDisplay.DisplayPosition.x) &&\r
+     (x   < PreviousPSXDisplay.DisplayEnd.x) &&\r
+     (dy  > PreviousPSXDisplay.DisplayPosition.y) &&\r
+     (y   < PreviousPSXDisplay.DisplayEnd.y)))\r
+  sArea=1;\r
+ else \r
+  {\r
+   return;\r
+  }\r
+\r
+ //////////////\r
+\r
+ if(iRenderFVR)\r
+  {\r
+   bFullVRam=TRUE;iRenderFVR=2;return;\r
+  }\r
+ bFullVRam=TRUE;iRenderFVR=2;\r
+\r
+ //////////////\r
+\r
+ p2=0;\r
+\r
+ if(sArea==0)\r
+  {\r
+   ux=PSXDisplay.DisplayPosition.x;\r
+   uy=PSXDisplay.DisplayPosition.y;\r
+   udx=PSXDisplay.DisplayEnd.x-ux;\r
+   udy=PSXDisplay.DisplayEnd.y-uy;\r
+   if((PreviousPSXDisplay.DisplayEnd.x-\r
+       PreviousPSXDisplay.DisplayPosition.x)==udx &&\r
+      (PreviousPSXDisplay.DisplayEnd.y-\r
+       PreviousPSXDisplay.DisplayPosition.y)==udy)\r
+    p2=(psxVuw + (1024*PreviousPSXDisplay.DisplayPosition.y) + \r
+        PreviousPSXDisplay.DisplayPosition.x);\r
+  }\r
+ else\r
+  {\r
+   ux=PreviousPSXDisplay.DisplayPosition.x;\r
+   uy=PreviousPSXDisplay.DisplayPosition.y;\r
+   udx=PreviousPSXDisplay.DisplayEnd.x-ux;\r
+   udy=PreviousPSXDisplay.DisplayEnd.y-uy;\r
+   if((PSXDisplay.DisplayEnd.x-\r
+       PSXDisplay.DisplayPosition.x)==udx &&\r
+      (PSXDisplay.DisplayEnd.y-\r
+       PSXDisplay.DisplayPosition.y)==udy)\r
+    p2=(psxVuw + (1024*PSXDisplay.DisplayPosition.y) + \r
+        PSXDisplay.DisplayPosition.x);\r
+  }\r
+\r
+ p1=(psxVuw + (1024*uy) + ux);\r
+ if(p1==p2) p2=0;\r
+\r
+ x=0;y=0;\r
+ wx=dx=udx;wy=dy=udy;\r
+\r
+ if(udx<=0) return;\r
+ if(udy<=0) return;\r
+ if(dx<=0)  return;\r
+ if(dy<=0)  return;\r
+ if(wx<=0)  return;\r
+ if(wy<=0)  return;\r
+\r
+ XS=(float)rRatioRect.right/(float)wx;\r
+ YS=(float)rRatioRect.bottom/(float)wy;\r
+\r
+ dx=(int)((float)(dx)*XS);\r
+ dy=(int)((float)(dy)*YS);\r
+\r
+ if(dx>iResX) dx=iResX;\r
+ if(dy>iResY) dy=iResY;\r
+\r
+ if(dx<=0) return;\r
+ if(dy<=0) return;\r
+\r
+ // ogl y adjust\r
+ y=iResY-y-dy;\r
+\r
+ x+=rRatioRect.left;\r
+ y-=rRatioRect.top;\r
+\r
+ if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;\r
+\r
+ if(!pGfxCardScreen)\r
+  {\r
+   glPixelStorei(GL_PACK_ALIGNMENT,1);\r
+   pGfxCardScreen=(u8 *)malloc(iResX*iResY*4);\r
+  }\r
+\r
+ ps=pGfxCardScreen;\r
\r
+ //if(!sArea) glReadBuffer(GL_FRONT);\r
+\r
+ glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
+               \r
+ //if(!sArea) glReadBuffer(GL_BACK);\r
+\r
+ s=0;\r
+\r
+ XS=(float)dx/(float)(udx);\r
+ YS=(float)dy/(float)(udy+1);\r
+    \r
+ for(y=udy;y>0;y--)\r
+  {\r
+   for(x=0;x<udx;x++)\r
+    {\r
+     if(p1>=psxVuw && p1<psxVuw_eom)\r
+      {\r
+       px=ps+(3*((int)((float)x * XS))+\r
+             (3*dx)*((int)((float)y*YS)));\r
+       sx=(*px)>>3;px++;\r
+       s=sx;\r
+       sx=(*px)>>3;px++;\r
+       s|=sx<<5;\r
+       sx=(*px)>>3;\r
+       s|=sx<<10;\r
+       s&=~0x8000;\r
+       *p1=s;\r
+      }\r
+     if(p2>=psxVuw && p2<psxVuw_eom) *p2=s;\r
+\r
+     p1++;\r
+     if(p2) p2++;\r
+    }\r
+\r
+   p1 += 1024 - udx;\r
+   if(p2) p2 += 1024 - udx;\r
+  }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// vram read check (reading from card's back/frontbuffer if needed... \r
+// slow!)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CheckVRamRead(int x, int y, int dx, int dy, bool bFront)\r
+{\r
+ unsigned short sArea;unsigned short * p;\r
+ int ux,uy,udx,udy,wx,wy;float XS,YS;\r
+ u8 * ps, * px;\r
+ unsigned short s=0,sx;\r
+\r
+ if(STATUSREG&GPUSTATUS_RGB24) return;\r
+\r
+ if(((dx  > PSXDisplay.DisplayPosition.x) &&\r
+     (x   < PSXDisplay.DisplayEnd.x) &&\r
+     (dy  > PSXDisplay.DisplayPosition.y) &&\r
+     (y   < PSXDisplay.DisplayEnd.y)))\r
+  sArea=0;\r
+ else\r
+ if((!(PSXDisplay.InterlacedTest) &&\r
+     (dx  > PreviousPSXDisplay.DisplayPosition.x) &&\r
+     (x   < PreviousPSXDisplay.DisplayEnd.x) &&\r
+     (dy  > PreviousPSXDisplay.DisplayPosition.y) &&\r
+     (y   < PreviousPSXDisplay.DisplayEnd.y)))\r
+  sArea=1;\r
+ else \r
+  {\r
+   return;\r
+  }\r
+\r
+ if(dwActFixes&0x40)\r
+  {\r
+   if(iRenderFVR)\r
+    {\r
+     bFullVRam=TRUE;iRenderFVR=2;return;\r
+    }\r
+   bFullVRam=TRUE;iRenderFVR=2;\r
+  }\r
+\r
+ ux=x;uy=y;udx=dx;udy=dy;\r
+\r
+ if(sArea==0)\r
+  {\r
+   x -=PSXDisplay.DisplayPosition.x;\r
+   dx-=PSXDisplay.DisplayPosition.x;\r
+   y -=PSXDisplay.DisplayPosition.y;\r
+   dy-=PSXDisplay.DisplayPosition.y;\r
+   wx=PSXDisplay.DisplayEnd.x-PSXDisplay.DisplayPosition.x;\r
+   wy=PSXDisplay.DisplayEnd.y-PSXDisplay.DisplayPosition.y;\r
+  }\r
+ else\r
+  {\r
+   x -=PreviousPSXDisplay.DisplayPosition.x;\r
+   dx-=PreviousPSXDisplay.DisplayPosition.x;\r
+   y -=PreviousPSXDisplay.DisplayPosition.y;\r
+   dy-=PreviousPSXDisplay.DisplayPosition.y;\r
+   wx=PreviousPSXDisplay.DisplayEnd.x-PreviousPSXDisplay.DisplayPosition.x;\r
+   wy=PreviousPSXDisplay.DisplayEnd.y-PreviousPSXDisplay.DisplayPosition.y;\r
+  }\r
+ if(x<0) {ux-=x;x=0;}\r
+ if(y<0) {uy-=y;y=0;}\r
+ if(dx>wx) {udx-=(dx-wx);dx=wx;}\r
+ if(dy>wy) {udy-=(dy-wy);dy=wy;}\r
+ udx-=ux;\r
+ udy-=uy;\r
+  \r
+ p=(psxVuw + (1024*uy) + ux);\r
+\r
+ if(udx<=0) return;\r
+ if(udy<=0) return;\r
+ if(dx<=0)  return;\r
+ if(dy<=0)  return;\r
+ if(wx<=0)  return;\r
+ if(wy<=0)  return;\r
+\r
+ XS=(float)rRatioRect.right/(float)wx;\r
+ YS=(float)rRatioRect.bottom/(float)wy;\r
+\r
+ dx=(int)((float)(dx)*XS);\r
+ dy=(int)((float)(dy)*YS);\r
+ x=(int)((float)x*XS);\r
+ y=(int)((float)y*YS);\r
+\r
+ dx-=x;\r
+ dy-=y;\r
+\r
+ if(dx>iResX) dx=iResX;\r
+ if(dy>iResY) dy=iResY;\r
+\r
+ if(dx<=0) return;\r
+ if(dy<=0) return;\r
+\r
+ // ogl y adjust\r
+ y=iResY-y-dy;\r
+\r
+ x+=rRatioRect.left;\r
+ y-=rRatioRect.top;\r
+\r
+ if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;\r
+\r
+ if(!pGfxCardScreen)\r
+  {\r
+   glPixelStorei(GL_PACK_ALIGNMENT,1);\r
+   pGfxCardScreen=(u8 *)malloc(iResX*iResY*4);\r
+  }\r
+\r
+ ps=pGfxCardScreen;\r
\r
+// if(bFront) glReadBuffer(GL_FRONT);\r
+\r
+ glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
+               \r
+// if(bFront) glReadBuffer(GL_BACK);\r
+\r
+ XS=(float)dx/(float)(udx);\r
+ YS=(float)dy/(float)(udy+1);\r
+    \r
+ for(y=udy;y>0;y--)\r
+  {\r
+   for(x=0;x<udx;x++)\r
+    {\r
+     if(p>=psxVuw && p<psxVuw_eom)\r
+      {\r
+       px=ps+(3*((int)((float)x * XS))+\r
+             (3*dx)*((int)((float)y*YS)));\r
+       sx=(*px)>>3;px++;\r
+       s=sx;\r
+       sx=(*px)>>3;px++;\r
+       s|=sx<<5;\r
+       sx=(*px)>>3;\r
+       s|=sx<<10;\r
+       s&=~0x8000;\r
+       *p=s;\r
+      }\r
+     p++;\r
+    }\r
+   p += 1024 - udx;\r
+  }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// core read from vram\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUreadDataMem(unsigned int * pMem, int iSize)\r
+#else\r
+void CALLBACK GPU_readDataMem(unsigned long * pMem, int iSize)\r
+#endif\r
+{\r
+int i;\r
+\r
+if(iDataReadMode!=DR_VRAMTRANSFER) return;\r
+\r
+GPUIsBusy;\r
+\r
+// adjust read ptr, if necessary\r
+while(VRAMRead.ImagePtr>=psxVuw_eom)\r
+ VRAMRead.ImagePtr-=iGPUHeight*1024;\r
+while(VRAMRead.ImagePtr<psxVuw)\r
+ VRAMRead.ImagePtr+=iGPUHeight*1024;\r
+\r
+if((iFrameReadType&1 && iSize>1) &&\r
+   !(iDrawnSomething==2 &&\r
+     VRAMRead.x      == VRAMWrite.x     &&\r
+     VRAMRead.y      == VRAMWrite.y     &&\r
+     VRAMRead.Width  == VRAMWrite.Width &&\r
+     VRAMRead.Height == VRAMWrite.Height))\r
+ CheckVRamRead(VRAMRead.x,VRAMRead.y,\r
+               VRAMRead.x+VRAMRead.RowsRemaining,\r
+               VRAMRead.y+VRAMRead.ColsRemaining,\r
+               TRUE);\r
+\r
+for(i=0;i<iSize;i++)\r
+ {\r
+  // do 2 seperate 16bit reads for compatibility (wrap issues)\r
+  if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))\r
+   {\r
+    // lower 16 bit\r
+    GPUdataRet=(unsigned long)*VRAMRead.ImagePtr;\r
+\r
+    VRAMRead.ImagePtr++;\r
+    if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
+    VRAMRead.RowsRemaining --;\r
+\r
+    if(VRAMRead.RowsRemaining<=0)\r
+     {\r
+      VRAMRead.RowsRemaining = VRAMRead.Width;\r
+      VRAMRead.ColsRemaining--;\r
+      VRAMRead.ImagePtr += 1024 - VRAMRead.Width;\r
+      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
+     }\r
+\r
+    // higher 16 bit (always, even if it's an odd width)\r
+    GPUdataRet|=(unsigned long)(*VRAMRead.ImagePtr)<<16;\r
+    *pMem++=GPUdataRet;\r
+\r
+    if(VRAMRead.ColsRemaining <= 0)\r
+     {FinishedVRAMRead();goto ENDREAD;}\r
+\r
+    VRAMRead.ImagePtr++;\r
+    if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
+    VRAMRead.RowsRemaining--;\r
+    if(VRAMRead.RowsRemaining<=0)\r
+     {\r
+      VRAMRead.RowsRemaining = VRAMRead.Width;\r
+      VRAMRead.ColsRemaining--;\r
+      VRAMRead.ImagePtr += 1024 - VRAMRead.Width;\r
+      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;\r
+     }\r
+    if(VRAMRead.ColsRemaining <= 0)\r
+     {FinishedVRAMRead();goto ENDREAD;}\r
+   }\r
+  else {FinishedVRAMRead();goto ENDREAD;}\r
+ }\r
+\r
+ENDREAD:\r
+GPUIsIdle;\r
+}\r
+\r
+#ifdef _WINDOWS\r
+unsigned long CALLBACK GPUreadData(void)\r
+#else\r
+unsigned long CALLBACK GPU_readData(void)\r
+#endif\r
+{\r
+ unsigned long l;\r
+#ifdef _WINDOWS\r
+ GPUreadDataMem(&l,1);\r
+#else\r
+ GPU_readDataMem(&l,1);\r
+#endif \r
+ return GPUdataRet;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// helper table to know how much data is used by drawing commands\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+const u8 primTableCX[256] =\r
+{\r
+    // 00\r
+    0,0,3,0,0,0,0,0,\r
+    // 08\r
+    0,0,0,0,0,0,0,0,\r
+    // 10\r
+    0,0,0,0,0,0,0,0,\r
+    // 18\r
+    0,0,0,0,0,0,0,0,\r
+    // 20\r
+    4,4,4,4,7,7,7,7,\r
+    // 28\r
+    5,5,5,5,9,9,9,9,\r
+    // 30\r
+    6,6,6,6,9,9,9,9,\r
+    // 38\r
+    8,8,8,8,12,12,12,12,\r
+    // 40\r
+    3,3,3,3,0,0,0,0,\r
+    // 48\r
+//    5,5,5,5,6,6,6,6,      //FLINE\r
+    254,254,254,254,254,254,254,254,\r
+    // 50\r
+    4,4,4,4,0,0,0,0,\r
+    // 58\r
+//    7,7,7,7,9,9,9,9,    //    LINEG3    LINEG4\r
+    255,255,255,255,255,255,255,255,\r
+    // 60\r
+    3,3,3,3,4,4,4,4,    //    TILE    SPRT\r
+    // 68\r
+    2,2,2,2,3,3,3,3,    //    TILE1\r
+    // 70\r
+    2,2,2,2,3,3,3,3,\r
+    // 78\r
+    2,2,2,2,3,3,3,3,\r
+    // 80\r
+    4,0,0,0,0,0,0,0,\r
+    // 88\r
+    0,0,0,0,0,0,0,0,\r
+    // 90\r
+    0,0,0,0,0,0,0,0,\r
+    // 98\r
+    0,0,0,0,0,0,0,0,\r
+    // a0\r
+    3,0,0,0,0,0,0,0,\r
+    // a8\r
+    0,0,0,0,0,0,0,0,\r
+    // b0\r
+    0,0,0,0,0,0,0,0,\r
+    // b8\r
+    0,0,0,0,0,0,0,0,\r
+    // c0\r
+    3,0,0,0,0,0,0,0,\r
+    // c8\r
+    0,0,0,0,0,0,0,0,\r
+    // d0\r
+    0,0,0,0,0,0,0,0,\r
+    // d8\r
+    0,0,0,0,0,0,0,0,\r
+    // e0\r
+    0,1,1,1,1,1,1,0,\r
+    // e8\r
+    0,0,0,0,0,0,0,0,\r
+    // f0\r
+    0,0,0,0,0,0,0,0,\r
+    // f8\r
+    0,0,0,0,0,0,0,0\r
+};\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// processes data send to GPU data register\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUwriteDataMem(unsigned long * pMem, int iSize)\r
+#else\r
+void CALLBACK GPU_writeDataMem(unsigned long * pMem, int iSize)\r
+#endif\r
+{\r
+u8 command;\r
+unsigned long gdata=0;\r
+int i=0;\r
+GPUIsBusy;\r
+GPUIsNotReadyForCommands;\r
+\r
+STARTVRAM:\r
+\r
+if(iDataWriteMode==DR_VRAMTRANSFER)\r
+ {\r
+  // make sure we are in vram\r
+  while(VRAMWrite.ImagePtr>=psxVuw_eom)\r
+   VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
+  while(VRAMWrite.ImagePtr<psxVuw)\r
+   VRAMWrite.ImagePtr+=iGPUHeight*1024;\r
+\r
+  // now do the loop\r
+  while(VRAMWrite.ColsRemaining>0)\r
+   {\r
+    while(VRAMWrite.RowsRemaining>0)\r
+     {\r
+      if(i>=iSize) {goto ENDVRAM;}\r
+      i++;\r
+\r
+      gdata=*pMem++;\r
+\r
+      *VRAMWrite.ImagePtr++ = (unsigned short)gdata;\r
+      if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
+      VRAMWrite.RowsRemaining --;\r
+\r
+      if(VRAMWrite.RowsRemaining <= 0)\r
+       {\r
+        VRAMWrite.ColsRemaining--;\r
+        if (VRAMWrite.ColsRemaining <= 0)             // last pixel is odd width\r
+         {\r
+          gdata=(gdata&0xFFFF)|(((unsigned long)(*VRAMWrite.ImagePtr))<<16);\r
+          FinishedVRAMWrite();\r
+          goto ENDVRAM;\r
+         }\r
+        VRAMWrite.RowsRemaining = VRAMWrite.Width;\r
+        VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;\r
+       }\r
+\r
+      *VRAMWrite.ImagePtr++ = (unsigned short)(gdata>>16);\r
+      if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;\r
+      VRAMWrite.RowsRemaining --;\r
+     }\r
+\r
+    VRAMWrite.RowsRemaining = VRAMWrite.Width;\r
+    VRAMWrite.ColsRemaining--;\r
+    VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;\r
+   }\r
+\r
+  FinishedVRAMWrite();\r
+ }\r
+\r
+ENDVRAM:\r
+\r
+if(iDataWriteMode==DR_NORMAL)\r
+ {\r
+  void (* *primFunc)(u8 *);\r
+  if(bSkipNextFrame) primFunc=primTableSkip;\r
+  else               primFunc=primTableJ;\r
+\r
+  for(;i<iSize;)\r
+   {\r
+    if(iDataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;\r
+\r
+    gdata=*pMem++;i++;\r
+\r
+    if(gpuDataC == 0)\r
+     {\r
+      command = (u8)((gdata>>24) & 0xff);\r
+\r
+      if(primTableCX[command])\r
+       {\r
+        gpuDataC = primTableCX[command];\r
+        gpuCommand = command;\r
+        gpuDataM[0] = gdata;\r
+        gpuDataP = 1;\r
+       }\r
+      else continue;\r
+     }\r
+    else\r
+     {\r
+      gpuDataM[gpuDataP] = gdata;\r
+      if(gpuDataC>128)\r
+       {\r
+        if((gpuDataC==254 && gpuDataP>=3) ||\r
+           (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))\r
+         {\r
+          if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)\r
+           gpuDataP=gpuDataC-1;\r
+         }\r
+       }\r
+      gpuDataP++;\r
+     }\r
+\r
+    if(gpuDataP == gpuDataC)\r
+     {\r
+      gpuDataC=gpuDataP=0;\r
+      primFunc[gpuCommand]((u8 *)gpuDataM);\r
+\r
+      if(dwEmuFixes&0x0001 || dwActFixes&0x20000)     // hack for emulating "gpu busy" in some games\r
+       iFakePrimBusy=4;\r
+     }\r
+   } \r
+ }\r
+\r
+GPUdataRet=gdata;\r
+\r
+GPUIsReadyForCommands;\r
+GPUIsIdle;                \r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUwriteData(unsigned long gdata)\r
+#else\r
+void CALLBACK GPU_writeData(unsigned long gdata)\r
+#endif\r
+{\r
+#ifdef _WINDOWS\r
+ GPUwriteDataMem(&gdata,1);\r
+#else\r
+ GPU_writeDataMem(&gdata,1);\r
+#endif \r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// this function will be removed soon (or 'soonish') (or never)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CALLBACK GPUsetMode(unsigned int gdata)\r
+{\r
+ // ignore old psemu setmode:\r
+\r
+ // imageTransfer = gdata;\r
+ // iDataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;\r
+ // iDataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;\r
+}\r
+\r
+// and this function will be removed soon as well, hehehe...\r
+long CALLBACK GPUgetMode(void)\r
+{\r
+ // ignore old psemu setmode\r
+ // return imageTransfer;\r
+\r
+long iT=0;\r
+\r
+if(iDataWriteMode==DR_VRAMTRANSFER) iT|=0x1;\r
+if(iDataReadMode ==DR_VRAMTRANSFER) iT|=0x2;\r
+\r
+return iT;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// call config dlg (Windows + Linux)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _WINDOWS\r
+\r
+/*#include <unistd.h>\r
+\r
+void StartCfgTool(s8 * pCmdLine)                     // linux: start external cfg tool\r
+{\r
+ FILE * cf;s8 filename[255],t[255];\r
+\r
+ strcpy(filename,"cfg/cfgPeopsMesaGL");                 // look in cfg sub folder first\r
+ cf=fopen(filename,"rb");\r
+ if(cf!=NULL)\r
+  {\r
+   fclose(cf);\r
+   getcwd(t,255);\r
+   chdir("cfg");\r
+   sprintf(filename,"./cfgPeopsMesaGL %s",pCmdLine);\r
+   system(filename);\r
+   chdir(t);\r
+  }\r
+ else\r
+  {\r
+   strcpy(filename,"cfgPeopsMesaGL");                   // look in current folder\r
+   cf=fopen(filename,"rb");\r
+   if(cf!=NULL)\r
+    {\r
+     fclose(cf);\r
+     sprintf(filename,"./cfgPeopsMesaGL %s",pCmdLine);\r
+     system(filename);\r
+    }\r
+   else\r
+    {\r
+     sprintf(filename,"%s/cfgPeopsMesaGL",getenv("HOME")); // look in home folder\r
+     cf=fopen(filename,"rb");\r
+     if(cf!=NULL)\r
+      {\r
+       fclose(cf);\r
+       getcwd(t,255);\r
+       chdir(getenv("HOME"));\r
+       sprintf(filename,"./cfgPeopsMesaGL %s",pCmdLine);\r
+       system(filename);\r
+       chdir(t);\r
+      }\r
+     else printf("cfgPeopsMesaGL not found!\n");\r
+    }\r
+  }\r
+}\r
+*/\r
+#endif\r
+\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUconfigure(void)\r
+#else\r
+long CALLBACK GPU_configure(void)\r
+#endif\r
+{\r
+\r
+#ifdef _WINDOWS\r
+// HWND hWP=GetActiveWindow();\r
+// DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG),\r
+//           hWP,(DLGPROC)CfgDlgProc);\r
+#else\r
+\r
+// StartCfgTool("CFG");\r
+\r
+#endif\r
+\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// sets all kind of act fixes\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void SetFixes(void)\r
+{\r
+ ReInitFrameCap();\r
+\r
+ if(dwActFixes & 0x2000) \r
+      dispWidths[4]=384;\r
+ else dispWidths[4]=368;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// Pete Special: make an 'intelligent' dma chain check (<-Tekken3)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+unsigned long lUsedAddr[3];\r
+\r
+__inline BOOL CheckForEndlessLoop(unsigned long laddr)\r
+{\r
+if(laddr==lUsedAddr[1]) return TRUE;\r
+if(laddr==lUsedAddr[2]) return TRUE;\r
+\r
+if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;\r
+else                   lUsedAddr[2]=laddr;\r
+lUsedAddr[0]=laddr;\r
+return FALSE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// core gives a dma chain to gpu: same as the gpuwrite interface funcs\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUdmaChain(unsigned long * baseAddrL, unsigned long addr)\r
+#else\r
+long CALLBACK GPU_dmaChain(unsigned long * baseAddrL, unsigned long addr)\r
+#endif\r
+{\r
+unsigned long dmaMem;\r
+u8 * baseAddrB;\r
+short count;unsigned int DMACommandCounter = 0;\r
+\r
+if(bIsFirstFrame) GLinitialize();\r
+\r
+GPUIsBusy;\r
+\r
+lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;\r
+\r
+baseAddrB = (u8*) baseAddrL;\r
+\r
+do\r
+ {\r
+  if(iGPUHeight==512) addr&=0x1FFFFC;\r
+\r
+  if(DMACommandCounter++ > 2000000) break;\r
+  if(CheckForEndlessLoop(addr)) break;\r
+\r
+  count = baseAddrB[addr+3];\r
+\r
+  dmaMem=addr+4;\r
+\r
+#ifdef _WINDOWS\r
+  if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);\r
+#else\r
+  if(count>0) GPU_writeDataMem(&baseAddrL[dmaMem>>2],count);\r
+#endif\r
+  \r
+  addr = baseAddrL[addr>>2]&0xffffff;\r
+ }\r
+while (addr != 0xffffff);\r
+\r
+GPUIsIdle;\r
+\r
+return 0;\r
+}\r
+           \r
+////////////////////////////////////////////////////////////////////////\r
+// show about dlg\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUabout(void)\r
+#else\r
+void CALLBACK GPU_about(void)\r
+#endif\r
+{\r
+\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// We are ever fine ;)\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUtest(void)\r
+#else\r
+long CALLBACK GPU_test(void)\r
+#endif\r
+{\r
+ // if test fails this function should return negative value for error (unable to continue)\r
+ // and positive value for warning (can continue but output might be crappy)\r
+\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// save state funcs\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+long CALLBACK GPUfreeze(unsigned long ulGetFreezeData,GPUFreeze_t * pF)\r
+#else\r
+long CALLBACK GPU_freeze(unsigned long ulGetFreezeData,GPUFreeze_t * pF)\r
+#endif\r
+{\r
+if(ulGetFreezeData==2) \r
+ {\r
+  long lSlotNum=*((long *)pF);\r
+  if(lSlotNum<0) return 0;\r
+  if(lSlotNum>8) return 0;\r
+  lSelectedSlot=lSlotNum+1;\r
+  return 1;\r
+ }\r
+\r
+if(!pF)                    return 0; \r
+if(pF->ulFreezeVersion!=1) return 0;\r
+\r
+if(ulGetFreezeData==1)\r
+ {\r
+  pF->ulStatus=STATUSREG;\r
+  memcpy(pF->ulControl,ulStatusControl,256*sizeof(unsigned long));\r
+  memcpy(pF->psxVRam,  psxVub,         1024*iGPUHeight*2);\r
+\r
+  return 1;\r
+ }\r
+\r
+if(ulGetFreezeData!=0) return 0;\r
+\r
+STATUSREG=pF->ulStatus;\r
+memcpy(ulStatusControl,pF->ulControl,256*sizeof(unsigned long));\r
+memcpy(psxVub,         pF->psxVRam,  1024*iGPUHeight*2);\r
+\r
+ResetTextureArea(TRUE);\r
+\r
+#ifdef _WINDOWS\r
+ GPUwriteStatus(ulStatusControl[0]);\r
+ GPUwriteStatus(ulStatusControl[1]);\r
+ GPUwriteStatus(ulStatusControl[2]);\r
+ GPUwriteStatus(ulStatusControl[3]);\r
+ GPUwriteStatus(ulStatusControl[8]);\r
+ GPUwriteStatus(ulStatusControl[6]);\r
+ GPUwriteStatus(ulStatusControl[7]);\r
+ GPUwriteStatus(ulStatusControl[5]);\r
+ GPUwriteStatus(ulStatusControl[4]);\r
+#else\r
+ GPU_writeStatus(ulStatusControl[0]);\r
+ GPU_writeStatus(ulStatusControl[1]);\r
+ GPU_writeStatus(ulStatusControl[2]);\r
+ GPU_writeStatus(ulStatusControl[3]);\r
+ GPU_writeStatus(ulStatusControl[8]);\r
+ GPU_writeStatus(ulStatusControl[6]);\r
+ GPU_writeStatus(ulStatusControl[7]);\r
+ GPU_writeStatus(ulStatusControl[5]);\r
+ GPU_writeStatus(ulStatusControl[4]);\r
+#endif\r
+ return 1;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+// special "emu infos" / "emu effects" functions\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+//00 = black\r
+//01 = white\r
+//10 = red\r
+//11 = transparent\r
+\r
+u8 cFont[10][120]=\r
+{\r
+// 0\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 1\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x05,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x05,0x55,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 2\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x01,0x40,0x00,0x00,\r
+ 0x80,0x00,0x05,0x00,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x15,0x55,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 3\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x01,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 4\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x54,0x00,0x00,\r
+ 0x80,0x00,0x01,0x54,0x00,0x00,\r
+ 0x80,0x00,0x01,0x54,0x00,0x00,\r
+ 0x80,0x00,0x05,0x14,0x00,0x00,\r
+ 0x80,0x00,0x14,0x14,0x00,0x00,\r
+ 0x80,0x00,0x15,0x55,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x55,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 5\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x15,0x55,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x15,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 6\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x01,0x54,0x00,0x00,\r
+ 0x80,0x00,0x05,0x00,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x14,0x00,0x00,0x00,\r
+ 0x80,0x00,0x15,0x54,0x00,0x00,\r
+ 0x80,0x00,0x15,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 7\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x15,0x55,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x50,0x00,0x00,\r
+ 0x80,0x00,0x01,0x40,0x00,0x00,\r
+ 0x80,0x00,0x01,0x40,0x00,0x00,\r
+ 0x80,0x00,0x05,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 8\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+},\r
+// 9\r
+{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x05,0x54,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x05,0x00,0x00,\r
+ 0x80,0x00,0x14,0x15,0x00,0x00,\r
+ 0x80,0x00,0x05,0x55,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x05,0x00,0x00,\r
+ 0x80,0x00,0x00,0x14,0x00,0x00,\r
+ 0x80,0x00,0x05,0x50,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0x80,0x00,0x00,0x00,0x00,0x00,\r
+ 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa\r
+}\r
+};\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void PaintPicDot(u8 * p,u8 c)\r
+{\r
+ if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}\r
+ if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}\r
+ if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUgetScreenPic(u8 * pMem)\r
+#else\r
+long CALLBACK GPU_getScreenPic(u8 * pMem)\r
+#endif\r
+{\r
+ float XS,YS;int x,y,v;\r
+ u8 * ps, * px, * pf;\r
+ u8 c;\r
+\r
+ if(!pGfxCardScreen)\r
+  {\r
+   glPixelStorei(GL_PACK_ALIGNMENT,1);\r
+   pGfxCardScreen=(u8 *)malloc(iResX*iResY*4);\r
+  }\r
+\r
+ ps=pGfxCardScreen;\r
+\r
+// glReadBuffer(GL_FRONT);\r
+\r
+ glReadPixels(0,0,iResX,iResY,GL_RGB,GL_UNSIGNED_BYTE,ps);\r
+               \r
+// glReadBuffer(GL_BACK);\r
+\r
+ XS=(float)iResX/128;\r
+ YS=(float)iResY/96;\r
+ pf=pMem;\r
+\r
+ for(y=96;y>0;y--)\r
+  {\r
+   for(x=0;x<128;x++)\r
+    {\r
+     px=ps+(3*((int)((float)x * XS))+\r
+           (3*iResX)*((int)((float)y*YS)));\r
+     *(pf+0)=*(px+2);\r
+     *(pf+1)=*(px+1);\r
+     *(pf+2)=*(px+0);\r
+     pf+=3;\r
+    }\r
+  }\r
+\r
+ /////////////////////////////////////////////////////////////////////\r
+ // generic number/border painter\r
+\r
+ pf=pMem+(103*3);\r
+\r
+ for(y=0;y<20;y++)\r
+  {\r
+   for(x=0;x<6;x++)\r
+    {\r
+     c=cFont[lSelectedSlot][x+y*6];\r
+     v=(c&0xc0)>>6;\r
+     PaintPicDot(pf,(u8)v);pf+=3;                // paint the dots into the rect\r
+     v=(c&0x30)>>4;\r
+     PaintPicDot(pf,(u8)v);pf+=3;\r
+     v=(c&0x0c)>>2;\r
+     PaintPicDot(pf,(u8)v);pf+=3;\r
+     v=c&0x03;\r
+     PaintPicDot(pf,(u8)v);pf+=3;\r
+    }\r
+   pf+=104*3;\r
+  }\r
+\r
+ pf=pMem;\r
+ for(x=0;x<128;x++)\r
+  {\r
+   *(pf+(95*128*3))=0x00;*pf++=0x00;\r
+   *(pf+(95*128*3))=0x00;*pf++=0x00;\r
+   *(pf+(95*128*3))=0xff;*pf++=0xff;\r
+  }\r
+ pf=pMem;\r
+ for(y=0;y<96;y++)\r
+  {\r
+   *(pf+(127*3))=0x00;*pf++=0x00;\r
+   *(pf+(127*3))=0x00;*pf++=0x00;\r
+   *(pf+(127*3))=0xff;*pf++=0xff;\r
+   pf+=127*3;\r
+  }\r
+\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _WINDOWS\r
+void CALLBACK GPUshowScreenPic(u8 * pMem)\r
+#else\r
+long CALLBACK GPU_showScreenPic(u8 * pMem)\r
+#endif\r
+{\r
+// DestroyPic();\r
+// if(pMem==0) return;\r
+// CreatePic(pMem);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CALLBACK GPUsetfix(unsigned long dwFixBits)\r
+{\r
+ dwEmuFixes=dwFixBits;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////\r
\r
+void CALLBACK GPUvisualVibration(unsigned long iSmall, unsigned long iBig)\r
+{\r
+ int iVibVal;\r
+\r
+ if(PSXDisplay.DisplayModeNew.x)                       // calc min "shake pixel" from screen width\r
+      iVibVal=max(1,iResX/PSXDisplay.DisplayModeNew.x);\r
+ else iVibVal=1;\r
+                                                       // big rumble: 4...15 sp ; small rumble 1...3 sp\r
+ if(iBig) iRumbleVal=max(4*iVibVal,min(15*iVibVal,((int)iBig  *iVibVal)/10));\r
+ else     iRumbleVal=max(1*iVibVal,min( 3*iVibVal,((int)iSmall*iVibVal)/10));\r
+\r
+ srand(timeGetTime());                                 // init rand (will be used in BufferSwap)\r
+\r
+ iRumbleTime=15;                                       // let the rumble last 16 buffer swaps\r
+}\r
+                                                       \r
+////////////////////////////////////////////////////////////////////////\r
+// main emu can set display infos (A/M/G/D) \r
+////////////////////////////////////////////////////////////////////////\r
+\r
+void CALLBACK GPUdisplayFlags(unsigned long dwFlags)\r
+{\r
+// dwCoreFlags=dwFlags;\r
+}\r