1 /***************************************************************************
2                           gpu.c  -  description
3                              -------------------
4     begin                : Sun Oct 28 2001
5     copyright            : (C) 2001 by Pete Bernert
6     email                : BlackDove@addcom.de
7  ***************************************************************************/
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version. See also the license.txt file for *
14  *   additional informations.                                              *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #if !defined(_MACGL) && !defined(_WINDOWS)
19 #include "config.h"
20 #endif
21 
22 #define _IN_GPU
23 
24 #include "externals.h"
25 #include "gpu.h"
26 #include "draw.h"
27 #include "cfg.h"
28 #include "prim.h"
29 #include "stdint.h"
30 #include "psemu_plugin_defs.h"
31 #include "menu.h"
32 #include "key.h"
33 #include "fps.h"
34 #include "swap.h"
35 
36 #ifdef ENABLE_NLS
37 #include <libintl.h>
38 #include <locale.h>
39 #define _(x)  gettext(x)
40 #define N_(x) (x)
41 
42 //If running under Mac OS X, use the Localizable.strings file instead.
43 #elif defined(_MACOSX)
44 #ifdef PCSXRCORE
45 __private_extern char* Pcsxr_locale_text(char* toloc);
46 #define _(String) Pcsxr_locale_text(String)
47 #define N_(String) String
48 #else
49 #ifndef PCSXRPLUG
50 #warning please define the plug being built to use Mac OS X localization!
51 #define _(msgid) msgid
52 #define N_(msgid) msgid
53 #else
54 //Kludge to get the preprocessor to accept PCSXRPLUG as a variable.
55 #define PLUGLOC_x(x,y) x ## y
56 #define PLUGLOC_y(x,y) PLUGLOC_x(x,y)
57 #define PLUGLOC PLUGLOC_y(PCSXRPLUG,_locale_text)
58 __private_extern char* PLUGLOC(char* toloc);
59 #define _(String) PLUGLOC(String)
60 #define N_(String) String
61 #endif
62 #endif
63 #else
64 #define _(x)  (x)
65 #define N_(x) (x)
66 #endif
67 
68 #ifdef _WINDOWS
69 #include "resource.h"
70 #include "record.h"
71 #endif
72 
73 ////////////////////////////////////////////////////////////////////////
74 // PPDK developer must change libraryName field and can change revision and build
75 ////////////////////////////////////////////////////////////////////////
76 
77 const  unsigned char version  = 1;    // do not touch - library for PSEmu 1.x
78 const  unsigned char revision = 1;
79 const  unsigned char build    = 17;   // increase that with each version
80 
81 #if defined (_WINDOWS)
82 static char *libraryName      = N_("Soft Driver");
83 static char *libraryInfo      = N_("P.E.Op.S. Soft Driver V1.17\nCoded by Pete Bernert and the P.E.Op.S. team\n");
84 #elif defined (_MACGL)
85 static char *libraryName      = N_("SoftGL Driver");
86 static char *libraryInfo      = N_("P.E.Op.S. SoftGL Driver V1.17\nCoded by Pete Bernert and the P.E.Op.S. team\n");
87 #else
88 static char *libraryName      = N_("XVideo Driver");
89 static char *libraryInfo      = N_("P.E.Op.S. Xvideo Driver V1.17\nCoded by Pete Bernert and the P.E.Op.S. team\n");
90 #endif
91 
92 static char *PluginAuthor     = N_("Pete Bernert and the P.E.Op.S. team");
93 
94 ////////////////////////////////////////////////////////////////////////
95 // memory image of the PSX vram
96 ////////////////////////////////////////////////////////////////////////
97 
98 unsigned char  *psxVSecure;
99 unsigned char  *psxVub;
100 signed   char  *psxVsb;
101 unsigned short *psxVuw;
102 unsigned short *psxVuw_eom;
103 signed   short *psxVsw;
104 uint32_t  *psxVul;
105 int32_t  *psxVsl;
106 
107 ////////////////////////////////////////////////////////////////////////
108 // GPU globals
109 ////////////////////////////////////////////////////////////////////////
110 
111 static long       lGPUdataRet;
112 long              lGPUstatusRet;
113 char              szDispBuf[64];
114 char              szMenuBuf[36];
115 char              szDebugText[512];
116 uint32_t     ulStatusControl[256];
117 
118 static uint32_t gpuDataM[256];
119 static unsigned   char gpuCommand = 0;
120 static long       gpuDataC = 0;
121 static long       gpuDataP = 0;
122 
123 VRAMLoad_t        VRAMWrite;
124 VRAMLoad_t        VRAMRead;
125 DATAREGISTERMODES DataWriteMode;
126 DATAREGISTERMODES DataReadMode;
127 
128 BOOL              bSkipNextFrame = FALSE;
129 DWORD             dwLaceCnt=0;
130 int               iColDepth;
131 int               iWindowMode;
132 short             sDispWidths[8] = {256,320,512,640,368,384,512,640};
133 PSXDisplay_t      PSXDisplay;
134 PSXDisplay_t      PreviousPSXDisplay;
135 long              lSelectedSlot=0;
136 BOOL              bChangeWinMode=FALSE;
137 BOOL              bDoLazyUpdate=FALSE;
138 uint32_t          lGPUInfoVals[16];
139 static int        iFakePrimBusy=0;
140 uint32_t          vBlank=0;
141 int               iRumbleVal=0;
142 int               iRumbleTime=0;
143 BOOL              oddLines;
144 
145 #ifdef _WINDOWS
146 
147 ////////////////////////////////////////////////////////////////////////
148 // screensaver stuff: dynamically load kernel32.dll to avoid export dependeny
149 ////////////////////////////////////////////////////////////////////////
150 
151 int				  iStopSaver=0;
152 HINSTANCE kernel32LibHandle = NULL;
153 
154 // A stub function, that does nothing .... but it does "nothing" well :)
STUB_SetThreadExecutionState(EXECUTION_STATE esFlags)155 EXECUTION_STATE WINAPI STUB_SetThreadExecutionState(EXECUTION_STATE esFlags)
156 {
157 	return esFlags;
158 }
159 
160 // The dynamic version of the system call is prepended with a "D_"
161 EXECUTION_STATE (WINAPI *D_SetThreadExecutionState)(EXECUTION_STATE esFlags) = STUB_SetThreadExecutionState;
162 
LoadKernel32(void)163 BOOL LoadKernel32(void)
164 {
165 	// Get a handle to the kernel32.dll (which is actually already loaded)
166 	kernel32LibHandle = LoadLibrary("kernel32.dll");
167 
168 	// If we've got a handle, then locate the entry point for the SetThreadExecutionState function
169 	if (kernel32LibHandle != NULL)
170 	{
171 		if ((D_SetThreadExecutionState = (EXECUTION_STATE (WINAPI *)(EXECUTION_STATE))GetProcAddress (kernel32LibHandle, "SetThreadExecutionState")) == NULL)
172 			D_SetThreadExecutionState = STUB_SetThreadExecutionState;
173 	}
174 
175 	return TRUE;
176 }
177 
FreeKernel32(void)178 BOOL FreeKernel32(void)
179 {
180 	// Release the handle to kernel32.dll
181 	if (kernel32LibHandle != NULL)
182 		FreeLibrary(kernel32LibHandle);
183 
184 	// Set to stub function, to avoid nasty suprises if called :)
185 	D_SetThreadExecutionState = STUB_SetThreadExecutionState;
186 
187 	return TRUE;
188 }
189 #else
190 
191 // Linux: Stub the functions
LoadKernel32(void)192 BOOL LoadKernel32(void)
193 {
194 	return TRUE;
195 }
196 
FreeKernel32(void)197 BOOL FreeKernel32(void)
198 {
199 	return TRUE;
200 }
201 
202 #endif
203 
204 ////////////////////////////////////////////////////////////////////////
205 // some misc external display funcs
206 ////////////////////////////////////////////////////////////////////////
207 
208 #include <time.h>
209 time_t tStart;
210 
GPUdisplayText(char * pText)211 void CALLBACK GPUdisplayText(char * pText)             // some debug func
212 {
213  if(!pText) {szDebugText[0]=0;return;}
214  if(strlen(pText)>511) return;
215  time(&tStart);
216  strcpy(szDebugText,pText);
217 }
218 
219 ////////////////////////////////////////////////////////////////////////
220 
GPUdisplayFlags(unsigned long dwFlags)221 void CALLBACK GPUdisplayFlags(unsigned long dwFlags)   // some info func
222 {
223  dwCoreFlags=dwFlags;
224  BuildDispMenu(0);
225 }
226 
227 ////////////////////////////////////////////////////////////////////////
228 // stuff to make this a true PDK module
229 ////////////////////////////////////////////////////////////////////////
230 
PSEgetLibName(void)231 char * CALLBACK PSEgetLibName(void)
232 {
233  return _(libraryName);
234 }
235 
PSEgetLibType(void)236 unsigned long CALLBACK PSEgetLibType(void)
237 {
238  return  PSE_LT_GPU;
239 }
240 
PSEgetLibVersion(void)241 unsigned long CALLBACK PSEgetLibVersion(void)
242 {
243  return version<<16|revision<<8|build;
244 }
245 
GPUgetLibInfos(void)246 char * GPUgetLibInfos(void)
247 {
248  return _(libraryInfo);
249 }
250 
251 ////////////////////////////////////////////////////////////////////////
252 // Snapshot func
253 ////////////////////////////////////////////////////////////////////////
254 
pGetConfigInfos(int iCfg)255 char * pGetConfigInfos(int iCfg)
256 {
257  char szO[2][4]={"off","on "};
258  char szTxt[256];
259  char * pB = (char *)malloc(32767);
260 
261  if (!pB) return NULL;
262  *pB = 0;
263  //----------------------------------------------------//
264  sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build);
265  strcat(pB,szTxt);
266  sprintf(szTxt,"Author: %s\r\n\r\n",PluginAuthor);
267  strcat(pB,szTxt);
268  //----------------------------------------------------//
269  if(iCfg && iWindowMode)
270   sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));
271  else
272   sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);
273  strcat(pB,szTxt);
274  if(iWindowMode && iCfg)
275    strcpy(szTxt,"Window mode\r\n");
276  else
277  if(iWindowMode)
278    sprintf(szTxt,"Window mode - [%d Bit]\r\n",iDesktopCol);
279  else
280    sprintf(szTxt,"Fullscreen - [%d Bit]\r\n",iColDepth);
281  strcat(pB,szTxt);
282 
283  sprintf(szTxt,"Stretch mode: %d\r\n",iUseNoStretchBlt);
284  strcat(pB,szTxt);
285  sprintf(szTxt,"Dither mode: %d\r\n\r\n",iUseDither);
286  strcat(pB,szTxt);
287  //----------------------------------------------------//
288  sprintf(szTxt,"Framerate:\r\n- FPS limit: %s\r\n",szO[UseFrameLimit]);
289  strcat(pB,szTxt);
290  sprintf(szTxt,"- Frame skipping: %s",szO[UseFrameSkip]);
291  strcat(pB,szTxt);
292  if(iFastFwd) strcat(pB," (fast forward)");
293  strcat(pB,"\r\n");
294  if(iFrameLimit==2)
295       strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");
296  else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);
297  strcat(pB,szTxt);
298  //----------------------------------------------------//
299 #if !defined (_MACGL) && !defined (_WINDOWS)
300  strcpy(szTxt,"Misc:\r\n- MaintainAspect: ");
301  if(iMaintainAspect == 0) strcat(szTxt,"disabled");
302  else
303  if(iMaintainAspect == 1) strcat(szTxt,"enabled");
304  strcat(szTxt,"\r\n");
305  strcat(pB,szTxt);
306 #endif
307  sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[iUseFixes],dwCfgFixes);
308  strcat(pB,szTxt);
309  //----------------------------------------------------//
310  return pB;
311 }
312 
DoTextSnapShot(int iNum)313 static void DoTextSnapShot(int iNum)
314 {
315  FILE *txtfile;
316  char szTxt[256];
317  char *pB;
318 
319 #ifdef _WINDOWS
320  sprintf(szTxt,"snap\\pcsxr%04d.txt",iNum);
321 #else
322  sprintf(szTxt,"%s/pcsxr%04d.txt",getenv("HOME"),iNum);
323 #endif
324 
325  if ((txtfile = fopen(szTxt, "wb")) == NULL)
326   return;
327 
328  pB = pGetConfigInfos(0);
329  if (pB)
330   {
331    fwrite(pB, strlen(pB), 1, txtfile);
332    free(pB);
333   }
334  fclose(txtfile);
335 }
336 
GPUmakeSnapshot(void)337 void CALLBACK GPUmakeSnapshot(void)
338 {
339  FILE *bmpfile;
340  char filename[256];
341  unsigned char header[0x36];
342  long size, height;
343  unsigned char line[1024 * 3];
344  short i, j;
345  unsigned char empty[2] = {0,0};
346  unsigned short color;
347  unsigned long snapshotnr = 0;
348  unsigned char *pD;
349 
350  height = PreviousPSXDisplay.DisplayMode.y;
351 
352  size = height * PreviousPSXDisplay.Range.x1 * 3 + 0x38;
353 
354  // fill in proper values for BMP
355 
356  // hardcoded BMP header
357  memset(header, 0, 0x36);
358  header[0] = 'B';
359  header[1] = 'M';
360  header[2] = size & 0xff;
361  header[3] = (size >> 8) & 0xff;
362  header[4] = (size >> 16) & 0xff;
363  header[5] = (size >> 24) & 0xff;
364  header[0x0a] = 0x36;
365  header[0x0e] = 0x28;
366  header[0x12] = PreviousPSXDisplay.Range.x1 % 256;
367  header[0x13] = PreviousPSXDisplay.Range.x1 / 256;
368  header[0x16] = height % 256;
369  header[0x17] = height / 256;
370  header[0x1a] = 0x01;
371  header[0x1c] = 0x18;
372  header[0x26] = 0x12;
373  header[0x27] = 0x0B;
374  header[0x2A] = 0x12;
375  header[0x2B] = 0x0B;
376 
377  // increment snapshot value & try to get filename
378  do
379   {
380    snapshotnr++;
381 #ifdef _WINDOWS
382    sprintf(filename,"snap\\pcsxr%04ld.bmp",snapshotnr);
383 #else
384    sprintf(filename, "%s/pcsxr%04ld.bmp", getenv("HOME"), snapshotnr);
385 #endif
386 
387    bmpfile = fopen(filename,"rb");
388    if (bmpfile == NULL)
389     break;
390 
391    fclose(bmpfile);
392   }
393  while(TRUE);
394 
395  // try opening new snapshot file
396  if ((bmpfile = fopen(filename,"wb")) == NULL)
397   return;
398 
399  fwrite(header, 0x36, 1, bmpfile);
400  for (i = height + PSXDisplay.DisplayPosition.y - 1; i >= PSXDisplay.DisplayPosition.y; i--)
401   {
402    pD = (unsigned char *)&psxVuw[i * 1024 + PSXDisplay.DisplayPosition.x];
403    for (j = 0; j < PreviousPSXDisplay.Range.x1; j++)
404     {
405      if (PSXDisplay.RGB24)
406       {
407        uint32_t lu = *(uint32_t *)pD;
408        line[j * 3 + 2] = (unsigned char)RED(lu);
409        line[j * 3 + 1] = (unsigned char)GREEN(lu);
410        line[j * 3 + 0] = (unsigned char)BLUE(lu);
411        pD += 3;
412       }
413      else
414       {
415        color = GETLE16(pD);
416        line[j * 3 + 2] = (color << 3) & 0xf1;
417        line[j * 3 + 1] = (color >> 2) & 0xf1;
418        line[j * 3 + 0] = (color >> 7) & 0xf1;
419        pD += 2;
420       }
421     }
422    fwrite(line, PreviousPSXDisplay.Range.x1 * 3, 1, bmpfile);
423   }
424  fwrite(empty, 0x2, 1, bmpfile);
425  fclose(bmpfile);
426 
427  DoTextSnapShot(snapshotnr);
428 }
429 
430 ////////////////////////////////////////////////////////////////////////
431 // INIT, will be called after lib load... well, just do some var init...
432 ////////////////////////////////////////////////////////////////////////
433 
GPUinit()434 long CALLBACK GPUinit()                                // GPU INIT
435 {
436  memset(ulStatusControl,0,256*sizeof(uint32_t));  // init save state scontrol field
437 
438  szDebugText[0] = 0;                                     // init debug text buffer
439 
440  psxVSecure = (unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
441  if (!psxVSecure)
442   return -1;
443 
444  //!!! ATTENTION !!!
445  psxVub=psxVSecure + 512 * 1024;                           // security offset into double sized psx vram!
446 
447  psxVsb=(signed char *)psxVub;                         // different ways of accessing PSX VRAM
448  psxVsw=(signed short *)psxVub;
449  psxVsl=(int32_t *)psxVub;
450  psxVuw=(unsigned short *)psxVub;
451  psxVul=(uint32_t *)psxVub;
452 
453  psxVuw_eom=psxVuw+1024*iGPUHeight;                    // pre-calc of end of vram
454 
455  memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));
456  memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
457 
458  SetFPSHandler();
459 
460  PSXDisplay.RGB24        = FALSE;                      // init some stuff
461  PSXDisplay.Interlaced   = FALSE;
462  PSXDisplay.DrawOffset.x = 0;
463  PSXDisplay.DrawOffset.y = 0;
464  PSXDisplay.DisplayMode.x= 320;
465  PSXDisplay.DisplayMode.y= 240;
466  PreviousPSXDisplay.DisplayMode.x= 320;
467  PreviousPSXDisplay.DisplayMode.y= 240;
468  PSXDisplay.Disabled     = FALSE;
469  PreviousPSXDisplay.Range.x0 =0;
470  PreviousPSXDisplay.Range.y0 =0;
471  PSXDisplay.Range.x0=0;
472  PSXDisplay.Range.x1=0;
473  PreviousPSXDisplay.DisplayModeNew.y=0;
474  PSXDisplay.Double = 1;
475  lGPUdataRet = 0x400;
476 
477  DataWriteMode = DR_NORMAL;
478 
479  // Reset transfer values, to prevent mis-transfer of data
480  memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
481  memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
482 
483  // device initialised already !
484  lGPUstatusRet = 0x14802000;
485  GPUIsIdle;
486  GPUIsReadyForCommands;
487  bDoVSyncUpdate = TRUE;
488  vBlank = 0;
489  oddLines = FALSE;
490 
491  // Get a handle for kernel32.dll, and access the required export function
492  LoadKernel32();
493 
494  return 0;
495 }
496 
497 ////////////////////////////////////////////////////////////////////////
498 // Here starts all...
499 ////////////////////////////////////////////////////////////////////////
500 
501 #ifdef _WINDOWS
GPUopen(HWND hwndGPU)502 long CALLBACK GPUopen(HWND hwndGPU)                    // GPU OPEN
503 {
504  hWGPU = hwndGPU;                                      // store hwnd
505 
506  SetKeyHandler();                                      // sub-class window
507 
508  if(bChangeWinMode) ReadWinSizeConfig();               // alt+enter toggle?
509  else                                                  // or first time startup?
510   {
511    ReadConfig();                                       // read registry
512    InitFPS();
513   }
514 
515  bIsFirstFrame  = TRUE;                                // we have to init later
516  bDoVSyncUpdate = TRUE;
517 
518  ulInitDisplay();                                      // setup direct draw
519 
520  if(iStopSaver)
521   D_SetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED|ES_CONTINUOUS);
522 
523 
524  return 0;
525 }
526 
527 #else
528 
GPUopen(unsigned long * disp,char * CapText,char * CfgFile)529 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
530 {
531  unsigned long d;
532 
533  pCaptionText=CapText;
534 
535 
536  ReadConfig();                                         // read registry
537 
538  InitFPS();
539 
540  bIsFirstFrame  = TRUE;                                // we have to init later
541  bDoVSyncUpdate = TRUE;
542 
543  d=ulInitDisplay();                                    // setup x
544 
545  if(disp)
546 	*disp=d;                                     // wanna x pointer? ok
547 
548  if(d) return 0;
549  return -1;
550 }
551 
552 #endif
553 
554 ////////////////////////////////////////////////////////////////////////
555 // time to leave...
556 ////////////////////////////////////////////////////////////////////////
557 
GPUclose()558 long CALLBACK GPUclose()                               // GPU CLOSE
559 {
560 #ifdef _WINDOWS
561  if(RECORD_RECORDING==TRUE) {RECORD_Stop();RECORD_RECORDING=FALSE;BuildDispMenu(0);}
562 #endif
563 
564  ReleaseKeyHandler();                                  // de-subclass window
565 
566  CloseDisplay();                                       // shutdown direct draw
567 
568 #ifdef _WINDOWS
569  if(iStopSaver)
570   D_SetThreadExecutionState(ES_SYSTEM_REQUIRED|ES_DISPLAY_REQUIRED);
571 #endif
572 
573  return 0;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////
577 // I shot the sheriff
578 ////////////////////////////////////////////////////////////////////////
579 
GPUshutdown()580 long CALLBACK GPUshutdown()                            // GPU SHUTDOWN
581 {
582  // screensaver: release the handle for kernel32.dll
583  FreeKernel32();
584 
585  free(psxVSecure);
586 
587  return 0;                                             // nothinh to do
588 }
589 
590 ////////////////////////////////////////////////////////////////////////
591 // Update display (swap buffers)
592 ////////////////////////////////////////////////////////////////////////
593 
updateDisplay(void)594 void updateDisplay(void)                               // UPDATE DISPLAY
595 {
596  if(PSXDisplay.Disabled)                               // disable?
597   {
598    DoClearFrontBuffer();                               // -> clear frontbuffer
599    return;                                             // -> and bye
600   }
601 
602  if(dwActFixes&32)                                     // pc fps calculation fix
603   {
604    if(UseFrameLimit) PCFrameCap();                     // -> brake
605    if(UseFrameSkip || ulKeybits&KEY_SHOWFPS)
606     PCcalcfps();
607   }
608 
609  if(ulKeybits&KEY_SHOWFPS)                             // make fps display buf
610   {
611    sprintf(szDispBuf,"FPS %06.1f",fps_cur);
612   }
613 
614  if(iFastFwd)                                          // fastfwd ?
615   {
616    static int fpscount; UseFrameSkip=1;
617 
618    if(!bSkipNextFrame) DoBufferSwap();                 // -> to skip or not to skip
619    if(fpscount%6)                                      // -> skip 6/7 frames
620         bSkipNextFrame = TRUE;
621    else bSkipNextFrame = FALSE;
622    fpscount++;
623    if(fpscount >= (int)fFrameRateHz) fpscount = 0;
624    return;
625   }
626 
627  if(UseFrameSkip)                                      // skip ?
628   {
629    if(!bSkipNextFrame) DoBufferSwap();                 // -> to skip or not to skip
630    if(dwActFixes&0xa0)                                 // -> pc fps calculation fix/old skipping fix
631     {
632      if((fps_skip < fFrameRateHz) && !(bSkipNextFrame))  // -> skip max one in a row
633          {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
634      else bSkipNextFrame = FALSE;
635     }
636    else FrameSkip();
637   }
638  else                                                  // no skip ?
639   {
640    DoBufferSwap();                                     // -> swap
641   }
642 }
643 
644 ////////////////////////////////////////////////////////////////////////
645 // roughly emulated screen centering bits... not complete !!!
646 ////////////////////////////////////////////////////////////////////////
647 
ChangeDispOffsetsX(void)648 void ChangeDispOffsetsX(void)                          // X CENTER
649 {
650  long lx,l;
651 
652  if(!PSXDisplay.Range.x1) return;
653 
654  l=PreviousPSXDisplay.DisplayMode.x;
655 
656  l*=(long)PSXDisplay.Range.x1;
657  l/=2560;lx=l;l&=0xfffffff8;
658 
659  if(l==PreviousPSXDisplay.Range.y1) return;            // abusing range.y1 for
660  PreviousPSXDisplay.Range.y1=(short)l;                 // storing last x range and test
661 
662  if(lx>=PreviousPSXDisplay.DisplayMode.x)
663   {
664    PreviousPSXDisplay.Range.x1=
665     (short)PreviousPSXDisplay.DisplayMode.x;
666    PreviousPSXDisplay.Range.x0=0;
667   }
668  else
669   {
670    PreviousPSXDisplay.Range.x1=(short)l;
671 
672    PreviousPSXDisplay.Range.x0=
673     (PSXDisplay.Range.x0-500)/8;
674 
675    if(PreviousPSXDisplay.Range.x0<0)
676     PreviousPSXDisplay.Range.x0=0;
677 
678    if((PreviousPSXDisplay.Range.x0+lx)>
679       PreviousPSXDisplay.DisplayMode.x)
680     {
681      PreviousPSXDisplay.Range.x0=
682       (short)(PreviousPSXDisplay.DisplayMode.x-lx);
683      PreviousPSXDisplay.Range.x0+=2; //???
684 
685      PreviousPSXDisplay.Range.x1+=(short)(lx-l);
686 
687 #ifndef _WINDOWS
688      PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
689 #endif
690     }
691 
692 #ifndef _WINDOWS
693    // some linux alignment security
694    PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
695    PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
696    PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
697    PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
698 #endif
699 
700    DoClearScreenBuffer();
701   }
702 
703  bDoVSyncUpdate=TRUE;
704 }
705 
706 ////////////////////////////////////////////////////////////////////////
707 
ChangeDispOffsetsY(void)708 void ChangeDispOffsetsY(void)                          // Y CENTER
709 {
710  int iT,iO=PreviousPSXDisplay.Range.y0;
711  int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
712 
713 // new
714 
715  if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight)
716   {
717    int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x;
718    int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight;
719 
720    if(dy1>=dy2)
721     {
722      PreviousPSXDisplay.DisplayModeNew.y=-dy2;
723     }
724    else
725     {
726      PSXDisplay.DisplayPosition.y=0;
727      PreviousPSXDisplay.DisplayModeNew.y=-dy1;
728     }
729   }
730  else PreviousPSXDisplay.DisplayModeNew.y=0;
731 
732 // eon
733 
734  if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
735   {
736    PSXDisplay.Height = PSXDisplay.Range.y1 -
737                        PSXDisplay.Range.y0 +
738                        PreviousPSXDisplay.DisplayModeNew.y;
739    PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
740   }
741 
742 //
743 
744  if(PSXDisplay.PAL) iT=48; else iT=28;
745 
746  if(PSXDisplay.Range.y0>=iT)
747   {
748    PreviousPSXDisplay.Range.y0=
749     (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
750    if(PreviousPSXDisplay.Range.y0<0)
751     PreviousPSXDisplay.Range.y0=0;
752    PSXDisplay.DisplayModeNew.y+=
753     PreviousPSXDisplay.Range.y0;
754   }
755  else
756   PreviousPSXDisplay.Range.y0=0;
757 
758  if(iO!=PreviousPSXDisplay.Range.y0)
759   {
760    DoClearScreenBuffer();
761  }
762 }
763 
764 ////////////////////////////////////////////////////////////////////////
765 // check if update needed
766 ////////////////////////////////////////////////////////////////////////
767 
updateDisplayIfChanged(void)768 void updateDisplayIfChanged(void)                      // UPDATE DISPLAY IF CHANGED
769 {
770  if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
771      (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
772   {
773    if((PSXDisplay.RGB24      == PSXDisplay.RGB24New) &&
774       (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
775   }
776 
777  PSXDisplay.RGB24         = PSXDisplay.RGB24New;       // get new infos
778 
779  PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
780  PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
781  PreviousPSXDisplay.DisplayMode.x=                     // previous will hold
782   min(640,PSXDisplay.DisplayMode.x);                   // max 640x512... that's
783  PreviousPSXDisplay.DisplayMode.y=                     // the size of my
784   min(512,PSXDisplay.DisplayMode.y);                   // back buffer surface
785  PSXDisplay.Interlaced    = PSXDisplay.InterlacedNew;
786 
787  PSXDisplay.DisplayEnd.x=                              // calc end of display
788   PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
789  PSXDisplay.DisplayEnd.y=
790   PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
791  PreviousPSXDisplay.DisplayEnd.x=
792   PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
793  PreviousPSXDisplay.DisplayEnd.y=
794   PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
795 
796  ChangeDispOffsetsX();
797 
798  if(iFrameLimit==2) SetAutoFrameCap();                 // -> set it
799 
800  if(UseFrameSkip) updateDisplay();                     // stupid stuff when frame skipping enabled
801 }
802 
803 ////////////////////////////////////////////////////////////////////////
804 
805 #if defined(_WINDOWS)
806 
ChangeWindowMode(void)807 void ChangeWindowMode(void)                            // TOGGLE FULLSCREEN - WINDOW
808 {
809  GPUclose();
810  iWindowMode=!iWindowMode;
811  GPUopen(hWGPU);
812  bChangeWinMode=FALSE;
813  bDoVSyncUpdate=TRUE;
814 }
815 
816 #elif !defined (_MACGL)
817 
818 #include "draw.h"
819 
ChangeWindowMode(void)820 void ChangeWindowMode(void)                            // TOGGLE FULLSCREEN - WINDOW
821 {
822  extern Display       *display;
823  extern Window        window;
824  extern int           root_window_id;
825  extern Screen        *screen;
826  XSizeHints           hints;
827  MotifWmHints         mwmhints;
828  Atom                 mwmatom;
829 
830  screen=DefaultScreenOfDisplay(display);
831  iWindowMode=!iWindowMode;
832 
833  if(!iWindowMode)                                               // fullscreen
834   {
835    mwmhints.flags=MWM_HINTS_DECORATIONS;
836    mwmhints.functions=0;
837    mwmhints.decorations=0;
838    mwmhints.input_mode=0;
839    mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
840    XChangeProperty(display,window,mwmatom,mwmatom,32,
841                    PropModeReplace,(unsigned char *)&mwmhints,5);
842 
843    XResizeWindow(display,window,screen->width,screen->height);
844 
845    hints.min_width   = hints.max_width = hints.base_width = screen->width;
846    hints.min_height= hints.max_height = hints.base_height = screen->height;
847 
848    XSetWMNormalHints(display,window,&hints);
849 
850    {
851     XEvent xev;
852 
853     memset(&xev, 0, sizeof(xev));
854     xev.xclient.type = ClientMessage;
855     xev.xclient.serial = 0;
856     xev.xclient.send_event = 1;
857     xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
858     xev.xclient.window = window;
859     xev.xclient.format = 32;
860     xev.xclient.data.l[0] = 1;
861     xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
862     xev.xclient.data.l[2] = 0;
863     xev.xclient.data.l[3] = 0;
864     xev.xclient.data.l[4] = 0;
865 
866     XSendEvent(display, root_window_id, 0,
867       SubstructureRedirectMask | SubstructureNotifyMask, &xev);
868    }
869   } else {
870    {
871     XEvent xev;
872 
873     memset(&xev, 0, sizeof(xev));
874     xev.xclient.type = ClientMessage;
875     xev.xclient.serial = 0;
876     xev.xclient.send_event = 1;
877     xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
878     xev.xclient.window = window;
879     xev.xclient.format = 32;
880     xev.xclient.data.l[0] = 0;
881     xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
882     xev.xclient.data.l[2] = 0;
883     xev.xclient.data.l[3] = 0;
884     xev.xclient.data.l[4] = 0;
885 
886     XSendEvent(display, root_window_id, 0,
887       SubstructureRedirectMask | SubstructureNotifyMask, &xev);
888    }
889 
890    mwmhints.flags=MWM_HINTS_DECORATIONS;
891    mwmhints.functions=0;
892    mwmhints.decorations=1;
893    mwmhints.input_mode=0;
894    mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
895 
896    //This shouldn't work on 64 bit longs, but it does...in fact, it breaks when I change all the mwmhints to int.
897    //I don't pretend to understand it.
898    XChangeProperty(display,window,mwmatom,mwmatom,32,
899                    PropModeReplace,(unsigned char *)&mwmhints,5);
900 
901  hints.flags=USPosition|USSize;
902  hints.base_width = iResX;
903  hints.base_height = iResY;
904    XSetWMNormalHints(display,window,&hints);
905 
906    XResizeWindow(display,window,iResX,iResY);
907 }
908 
909  DoClearScreenBuffer();
910 
911  bChangeWinMode=FALSE;
912  bDoVSyncUpdate=TRUE;
913 }
914 
915 #endif
916 
917 ////////////////////////////////////////////////////////////////////////
918 // gun cursor func: player=0-7, x=0-511, y=0-255
919 ////////////////////////////////////////////////////////////////////////
920 
GPUcursor(int iPlayer,int x,int y)921 void CALLBACK GPUcursor(int iPlayer,int x,int y)
922 {
923  if(iPlayer<0) return;
924  if(iPlayer>7) return;
925 
926  usCursorActive|=(1<<iPlayer);
927 
928  if(x<0)       x=0;
929  if(x>511)     x=511;
930  if(y<0)       y=0;
931  if(y>255)     y=255;
932 
933  ptCursorPoint[iPlayer].x=x;
934  ptCursorPoint[iPlayer].y=y;
935 }
936 
937 ////////////////////////////////////////////////////////////////////////
938 // update lace is called evry VSync
939 ////////////////////////////////////////////////////////////////////////
940 
GPUupdateLace(void)941 void CALLBACK GPUupdateLace(void)                      // VSYNC
942 {
943  if(!(dwActFixes&1))
944   lGPUstatusRet^=0x80000000;                           // odd/even bit
945 
946  if(!(dwActFixes&32))                                  // std fps limitation?
947   CheckFrameRate();
948 
949  if(PSXDisplay.Interlaced)                             // interlaced mode?
950   {
951    if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
952     {
953      updateDisplay();
954     }
955   }
956  else                                                  // non-interlaced?
957   {
958    if(dwActFixes&64)                                   // lazy screen update fix
959     {
960      if(bDoLazyUpdate && !UseFrameSkip)
961       updateDisplay();
962      bDoLazyUpdate=FALSE;
963     }
964    else
965     {
966      if(bDoVSyncUpdate && !UseFrameSkip)               // some primitives drawn?
967       updateDisplay();                                 // -> update display
968     }
969   }
970 
971 #ifdef _WINDOWS
972  if(RECORD_RECORDING)
973   if(RECORD_WriteFrame()==FALSE)
974    {RECORD_RECORDING=FALSE;RECORD_Stop();}
975 #endif
976 
977 #ifndef _MACGL
978  if(bChangeWinMode) ChangeWindowMode();                // toggle full - window mode
979 #endif
980 
981  bDoVSyncUpdate=FALSE;                                 // vsync done
982 }
983 
984 ////////////////////////////////////////////////////////////////////////
985 // process read request from GPU status register
986 ////////////////////////////////////////////////////////////////////////
987 
988 
GPUreadStatus(void)989 uint32_t CALLBACK GPUreadStatus(void)             // READ STATUS
990 {
991  if (vBlank || oddLines == FALSE)
992   { // vblank or even lines
993    lGPUstatusRet &= ~(0x80000000);
994   }
995  else
996   { // Oddlines and not vblank
997    lGPUstatusRet |= 0x80000000;
998   }
999 
1000  if(dwActFixes&1)
1001   {
1002    static int iNumRead=0;                         // odd/even hack
1003    if((iNumRead++)==2)
1004     {
1005      iNumRead=0;
1006      lGPUstatusRet^=0x80000000;                   // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older)
1007     }
1008   }
1009 
1010  if(iFakePrimBusy)                                // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
1011   {
1012    iFakePrimBusy--;
1013 
1014    if(iFakePrimBusy&1)                            // we do a busy-idle-busy-idle sequence after/while drawing prims
1015     {
1016      GPUIsBusy;
1017      GPUIsNotReadyForCommands;
1018     }
1019    else
1020     {
1021      GPUIsIdle;
1022      GPUIsReadyForCommands;
1023     }
1024   }
1025  return lGPUstatusRet;
1026 }
1027 
1028 ////////////////////////////////////////////////////////////////////////
1029 // processes data send to GPU status register
1030 // these are always single packet commands.
1031 ////////////////////////////////////////////////////////////////////////
1032 
GPUwriteStatus(uint32_t gdata)1033 void CALLBACK GPUwriteStatus(uint32_t gdata)      // WRITE STATUS
1034 {
1035  uint32_t lCommand=(gdata>>24)&0xff;
1036 
1037  ulStatusControl[lCommand]=gdata;                      // store command for freezing
1038 
1039  switch(lCommand)
1040   {
1041    //--------------------------------------------------//
1042    // reset gpu
1043    case 0x00:
1044     memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
1045     lGPUstatusRet=0x14802000;
1046     PSXDisplay.Disabled=1;
1047     DataWriteMode=DataReadMode=DR_NORMAL;
1048     PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
1049     drawX=drawY=0;drawW=drawH=0;
1050     sSetMask=0;lSetMask=0;bCheckMask=FALSE;
1051     usMirror=0;
1052     GlobalTextAddrX=0;GlobalTextAddrY=0;
1053     GlobalTextTP=0;GlobalTextABR=0;
1054     PSXDisplay.RGB24=FALSE;
1055     PSXDisplay.Interlaced=FALSE;
1056     bUsingTWin = FALSE;
1057     return;
1058    //--------------------------------------------------//
1059    // dis/enable display
1060    case 0x03:
1061 
1062     PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
1063     PSXDisplay.Disabled = (gdata & 1);
1064 
1065     if(PSXDisplay.Disabled)
1066          lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
1067     else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
1068     return;
1069 
1070    //--------------------------------------------------//
1071    // setting transfer mode
1072    case 0x04:
1073     gdata &= 0x03;                                     // Only want the lower two bits
1074 
1075     DataWriteMode=DataReadMode=DR_NORMAL;
1076     if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
1077     if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
1078     lGPUstatusRet&=~GPUSTATUS_DMABITS;                 // Clear the current settings of the DMA bits
1079     lGPUstatusRet|=(gdata << 29);                      // Set the DMA bits according to the received data
1080 
1081     return;
1082    //--------------------------------------------------//
1083    // setting display position
1084    case 0x05:
1085     {
1086      PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1087      PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1088 
1089 ////////
1090 /*
1091      PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
1092      if (PSXDisplay.DisplayPosition.y & 0x200)
1093       PSXDisplay.DisplayPosition.y |= 0xfffffc00;
1094      if(PSXDisplay.DisplayPosition.y<0)
1095       {
1096        PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
1097        PSXDisplay.DisplayPosition.y=0;
1098       }
1099      else PreviousPSXDisplay.DisplayModeNew.y=0;
1100 */
1101 
1102 // new
1103      if(iGPUHeight==1024)
1104       {
1105        if(dwGPUVersion==2)
1106             PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
1107        else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
1108       }
1109      else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
1110 
1111      // store the same val in some helper var, we need it on later compares
1112      PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
1113 
1114      if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
1115       {
1116        int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
1117        int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
1118 
1119        if(dy1>=dy2)
1120         {
1121          PreviousPSXDisplay.DisplayModeNew.y=-dy2;
1122         }
1123        else
1124         {
1125          PSXDisplay.DisplayPosition.y=0;
1126          PreviousPSXDisplay.DisplayModeNew.y=-dy1;
1127         }
1128       }
1129      else PreviousPSXDisplay.DisplayModeNew.y=0;
1130 // eon
1131 
1132      PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
1133      PSXDisplay.DisplayEnd.x=
1134       PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
1135      PSXDisplay.DisplayEnd.y=
1136       PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
1137      PreviousPSXDisplay.DisplayEnd.x=
1138       PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
1139      PreviousPSXDisplay.DisplayEnd.y=
1140       PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
1141 
1142      bDoVSyncUpdate=TRUE;
1143 
1144      if (!(PSXDisplay.Interlaced))                      // stupid frame skipping option
1145       {
1146        if(UseFrameSkip)  updateDisplay();
1147        if(dwActFixes&64) bDoLazyUpdate=TRUE;
1148       }
1149     }return;
1150    //--------------------------------------------------//
1151    // setting width
1152    case 0x06:
1153 
1154     PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
1155     PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
1156 
1157     PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
1158 
1159     ChangeDispOffsetsX();
1160 
1161     return;
1162    //--------------------------------------------------//
1163    // setting height
1164    case 0x07:
1165     {
1166 
1167      PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
1168      PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
1169 
1170      PreviousPSXDisplay.Height = PSXDisplay.Height;
1171 
1172      PSXDisplay.Height = PSXDisplay.Range.y1 -
1173                          PSXDisplay.Range.y0 +
1174                          PreviousPSXDisplay.DisplayModeNew.y;
1175 
1176      if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1177       {
1178        PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1179 
1180        ChangeDispOffsetsY();
1181 
1182        updateDisplayIfChanged();
1183       }
1184      return;
1185     }
1186    //--------------------------------------------------//
1187    // setting display infos
1188    case 0x08:
1189 
1190     PSXDisplay.DisplayModeNew.x =
1191      sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1192 
1193     if (gdata&0x04) PSXDisplay.Double=2;
1194     else            PSXDisplay.Double=1;
1195 
1196     PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1197 
1198     ChangeDispOffsetsY();
1199 
1200     PSXDisplay.PAL           = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1201     PSXDisplay.RGB24New      = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1202     PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1203 
1204     lGPUstatusRet&=~GPUSTATUS_WIDTHBITS;                   // Clear the width bits
1205     lGPUstatusRet|=
1206                (((gdata & 0x03) << 17) |
1207                ((gdata & 0x40) << 10));                // Set the width bits
1208 
1209     if(PSXDisplay.InterlacedNew)
1210      {
1211       if(!PSXDisplay.Interlaced)
1212        {
1213         PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1214         PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1215        }
1216       lGPUstatusRet|=GPUSTATUS_INTERLACED;
1217      }
1218     else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1219 
1220     if (PSXDisplay.PAL)
1221          lGPUstatusRet|=GPUSTATUS_PAL;
1222     else lGPUstatusRet&=~GPUSTATUS_PAL;
1223 
1224     if (PSXDisplay.Double==2)
1225          lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1226     else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1227 
1228     if (PSXDisplay.RGB24New)
1229          lGPUstatusRet|=GPUSTATUS_RGB24;
1230     else lGPUstatusRet&=~GPUSTATUS_RGB24;
1231 
1232     updateDisplayIfChanged();
1233 
1234     return;
1235    //--------------------------------------------------//
1236    // ask about GPU version and other stuff
1237    case 0x10:
1238 
1239     gdata&=0xff;
1240 
1241     switch(gdata)
1242      {
1243       case 0x02:
1244        lGPUdataRet=lGPUInfoVals[INFO_TW];              // tw infos
1245        return;
1246       case 0x03:
1247        lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART];       // draw start
1248        return;
1249       case 0x04:
1250        lGPUdataRet=lGPUInfoVals[INFO_DRAWEND];         // draw end
1251        return;
1252       case 0x05:
1253       case 0x06:
1254        lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF];         // draw offset
1255        return;
1256       case 0x07:
1257        if(dwGPUVersion==2)
1258             lGPUdataRet=0x01;
1259        else lGPUdataRet=0x02;                          // gpu type
1260        return;
1261       case 0x08:
1262       case 0x0F:                                       // some bios addr?
1263        lGPUdataRet=0xBFC03720;
1264        return;
1265      }
1266     return;
1267    //--------------------------------------------------//
1268   }
1269 }
1270 
1271 ////////////////////////////////////////////////////////////////////////
1272 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1273 ////////////////////////////////////////////////////////////////////////
1274 
FinishedVRAMWrite(void)1275 static __inline void FinishedVRAMWrite(void)
1276 {
1277 /*
1278 // NEWX
1279  if(!PSXDisplay.Interlaced && UseFrameSkip)            // stupid frame skipping
1280   {
1281    VRAMWrite.Width +=VRAMWrite.x;
1282    VRAMWrite.Height+=VRAMWrite.y;
1283    if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1284       VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1285       VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1286       VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1287     updateDisplay();
1288   }
1289 */
1290 
1291  // Set register to NORMAL operation
1292  DataWriteMode = DR_NORMAL;
1293  // Reset transfer values, to prevent mis-transfer of data
1294  VRAMWrite.x = 0;
1295  VRAMWrite.y = 0;
1296  VRAMWrite.Width = 0;
1297  VRAMWrite.Height = 0;
1298  VRAMWrite.ColsRemaining = 0;
1299  VRAMWrite.RowsRemaining = 0;
1300 }
1301 
FinishedVRAMRead(void)1302 static __inline void FinishedVRAMRead(void)
1303 {
1304  // Set register to NORMAL operation
1305  DataReadMode = DR_NORMAL;
1306  // Reset transfer values, to prevent mis-transfer of data
1307  VRAMRead.x = 0;
1308  VRAMRead.y = 0;
1309  VRAMRead.Width = 0;
1310  VRAMRead.Height = 0;
1311  VRAMRead.ColsRemaining = 0;
1312  VRAMRead.RowsRemaining = 0;
1313 
1314  // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1315  lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1316 }
1317 
1318 ////////////////////////////////////////////////////////////////////////
1319 // core read from vram
1320 ////////////////////////////////////////////////////////////////////////
1321 
GPUreadDataMem(uint32_t * pMem,int iSize)1322 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1323 {
1324  int i;
1325 
1326  if(DataReadMode!=DR_VRAMTRANSFER) return;
1327 
1328  GPUIsBusy;
1329 
1330  // adjust read ptr, if necessary
1331  while(VRAMRead.ImagePtr>=psxVuw_eom)
1332   VRAMRead.ImagePtr-=iGPUHeight*1024;
1333  while(VRAMRead.ImagePtr<psxVuw)
1334   VRAMRead.ImagePtr+=iGPUHeight*1024;
1335 
1336  for(i=0;i<iSize;i++)
1337   {
1338    // do 2 seperate 16bit reads for compatibility (wrap issues)
1339    if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1340     {
1341      // lower 16 bit
1342      lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1343 
1344      VRAMRead.ImagePtr++;
1345      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1346      VRAMRead.RowsRemaining --;
1347 
1348      if(VRAMRead.RowsRemaining<=0)
1349       {
1350        VRAMRead.RowsRemaining = VRAMRead.Width;
1351        VRAMRead.ColsRemaining--;
1352        VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1353        if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1354       }
1355 
1356      // higher 16 bit (always, even if it's an odd width)
1357      lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1358      PUTLE32(pMem, lGPUdataRet); pMem++;
1359 
1360      if(VRAMRead.ColsRemaining <= 0)
1361       {FinishedVRAMRead();goto ENDREAD;}
1362 
1363      VRAMRead.ImagePtr++;
1364      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1365      VRAMRead.RowsRemaining--;
1366      if(VRAMRead.RowsRemaining<=0)
1367       {
1368        VRAMRead.RowsRemaining = VRAMRead.Width;
1369        VRAMRead.ColsRemaining--;
1370        VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1371        if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1372       }
1373      if(VRAMRead.ColsRemaining <= 0)
1374       {FinishedVRAMRead();goto ENDREAD;}
1375     }
1376    else {FinishedVRAMRead();goto ENDREAD;}
1377   }
1378 
1379 ENDREAD:
1380  GPUIsIdle;
1381 }
1382 
1383 
1384 ////////////////////////////////////////////////////////////////////////
1385 
GPUreadData(void)1386 uint32_t CALLBACK GPUreadData(void)
1387 {
1388  uint32_t l;
1389  GPUreadDataMem(&l,1);
1390  return lGPUdataRet;
1391 }
1392 
1393 ////////////////////////////////////////////////////////////////////////
1394 // processes data send to GPU data register
1395 // extra table entries for fixing polyline troubles
1396 ////////////////////////////////////////////////////////////////////////
1397 
1398 const unsigned char primTableCX[256] =
1399 {
1400     // 00
1401     0,0,3,0,0,0,0,0,
1402     // 08
1403     0,0,0,0,0,0,0,0,
1404     // 10
1405     0,0,0,0,0,0,0,0,
1406     // 18
1407     0,0,0,0,0,0,0,0,
1408     // 20
1409     4,4,4,4,7,7,7,7,
1410     // 28
1411     5,5,5,5,9,9,9,9,
1412     // 30
1413     6,6,6,6,9,9,9,9,
1414     // 38
1415     8,8,8,8,12,12,12,12,
1416     // 40
1417     3,3,3,3,0,0,0,0,
1418     // 48
1419 //  5,5,5,5,6,6,6,6,    // FLINE
1420     254,254,254,254,254,254,254,254,
1421     // 50
1422     4,4,4,4,0,0,0,0,
1423     // 58
1424 //  7,7,7,7,9,9,9,9,    // GLINE
1425     255,255,255,255,255,255,255,255,
1426     // 60
1427     3,3,3,3,4,4,4,4,
1428     // 68
1429     2,2,2,2,3,3,3,3,    // 3=SPRITE1???
1430     // 70
1431     2,2,2,2,3,3,3,3,
1432     // 78
1433     2,2,2,2,3,3,3,3,
1434     // 80
1435     4,0,0,0,0,0,0,0,
1436     // 88
1437     0,0,0,0,0,0,0,0,
1438     // 90
1439     0,0,0,0,0,0,0,0,
1440     // 98
1441     0,0,0,0,0,0,0,0,
1442     // a0
1443     3,0,0,0,0,0,0,0,
1444     // a8
1445     0,0,0,0,0,0,0,0,
1446     // b0
1447     0,0,0,0,0,0,0,0,
1448     // b8
1449     0,0,0,0,0,0,0,0,
1450     // c0
1451     3,0,0,0,0,0,0,0,
1452     // c8
1453     0,0,0,0,0,0,0,0,
1454     // d0
1455     0,0,0,0,0,0,0,0,
1456     // d8
1457     0,0,0,0,0,0,0,0,
1458     // e0
1459     0,1,1,1,1,1,1,0,
1460     // e8
1461     0,0,0,0,0,0,0,0,
1462     // f0
1463     0,0,0,0,0,0,0,0,
1464     // f8
1465     0,0,0,0,0,0,0,0
1466 };
1467 
GPUwriteDataMem(uint32_t * pMem,int iSize)1468 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1469 {
1470  unsigned char command;
1471  uint32_t gdata=0;
1472  int i=0;
1473  GPUIsBusy;
1474  GPUIsNotReadyForCommands;
1475 
1476 STARTVRAM:
1477 
1478  if(DataWriteMode==DR_VRAMTRANSFER)
1479   {
1480    BOOL bFinished=FALSE;
1481 
1482    // make sure we are in vram
1483    while(VRAMWrite.ImagePtr>=psxVuw_eom)
1484     VRAMWrite.ImagePtr-=iGPUHeight*1024;
1485    while(VRAMWrite.ImagePtr<psxVuw)
1486     VRAMWrite.ImagePtr+=iGPUHeight*1024;
1487 
1488    // now do the loop
1489    while(VRAMWrite.ColsRemaining>0)
1490     {
1491      while(VRAMWrite.RowsRemaining>0)
1492       {
1493        if(i>=iSize) {goto ENDVRAM;}
1494        i++;
1495 
1496        gdata=GETLE32(pMem); pMem++;
1497 
1498        // Write odd pixel - Wrap from beginning to next index if going past GPU width
1499        if(VRAMWrite.Width+VRAMWrite.x-VRAMWrite.RowsRemaining >= 1024) {
1500          PUTLE16(VRAMWrite.ImagePtr-1024, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1501        } else { PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++; }
1502        if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;// Check if went past framebuffer
1503        VRAMWrite.RowsRemaining --;
1504 
1505        // Check if end at odd pixel drawn
1506        if(VRAMWrite.RowsRemaining <= 0)
1507         {
1508          VRAMWrite.ColsRemaining--;
1509          if (VRAMWrite.ColsRemaining <= 0)             // last pixel is odd width
1510           {
1511            gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1512            FinishedVRAMWrite();
1513            bDoVSyncUpdate=TRUE;
1514            goto ENDVRAM;
1515           }
1516          VRAMWrite.RowsRemaining = VRAMWrite.Width;
1517          VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1518         }
1519 
1520        // Write even pixel - Wrap from beginning to next index if going past GPU width
1521        if(VRAMWrite.Width+VRAMWrite.x-VRAMWrite.RowsRemaining >= 1024) {
1522          PUTLE16(VRAMWrite.ImagePtr-1024, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1523        } else { PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++; }
1524        if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;// Check if went past framebuffer
1525        VRAMWrite.RowsRemaining --;
1526       }
1527 
1528      VRAMWrite.RowsRemaining = VRAMWrite.Width;
1529      VRAMWrite.ColsRemaining--;
1530      VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1531      bFinished=TRUE;
1532     }
1533 
1534    FinishedVRAMWrite();
1535    if(bFinished) bDoVSyncUpdate=TRUE;
1536   }
1537 
1538 ENDVRAM:
1539 
1540  if(DataWriteMode==DR_NORMAL)
1541   {
1542    void (* *primFunc)(unsigned char *);
1543    if(bSkipNextFrame) primFunc=primTableSkip;
1544    else               primFunc=primTableJ;
1545 
1546    for(;i<iSize;)
1547     {
1548      if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1549 
1550      gdata=GETLE32(pMem); pMem++; i++;
1551 
1552      if(gpuDataC == 0)
1553       {
1554        command = (unsigned char)((gdata>>24) & 0xff);
1555 
1556 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1557 
1558        if(primTableCX[command])
1559         {
1560          gpuDataC = primTableCX[command];
1561          gpuCommand = command;
1562          PUTLE32(&gpuDataM[0], gdata);
1563          gpuDataP = 1;
1564         }
1565        else continue;
1566       }
1567      else
1568       {
1569        PUTLE32(&gpuDataM[gpuDataP], gdata);
1570        if(gpuDataC>128)
1571         {
1572          if((gpuDataC==254 && gpuDataP>=3) ||
1573             (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1574           {
1575            if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1576             gpuDataP=gpuDataC-1;
1577           }
1578         }
1579        gpuDataP++;
1580       }
1581 
1582      if(gpuDataP == gpuDataC)
1583       {
1584        gpuDataC=gpuDataP=0;
1585        primFunc[gpuCommand]((unsigned char *)gpuDataM);
1586        if(dwEmuFixes&0x0001 || dwActFixes&0x0400)      // hack for emulating "gpu busy" in some games
1587         iFakePrimBusy=4;
1588       }
1589     }
1590   }
1591 
1592  lGPUdataRet=gdata;
1593 
1594  GPUIsReadyForCommands;
1595  GPUIsIdle;
1596 }
1597 
1598 ////////////////////////////////////////////////////////////////////////
1599 
GPUwriteData(uint32_t gdata)1600 void CALLBACK GPUwriteData(uint32_t gdata)
1601 {
1602  PUTLE32(&gdata, gdata);
1603  GPUwriteDataMem(&gdata,1);
1604 }
1605 
1606 ////////////////////////////////////////////////////////////////////////
1607 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1608 ////////////////////////////////////////////////////////////////////////
1609 
GPUsetMode(unsigned long gdata)1610 void CALLBACK GPUsetMode(unsigned long gdata)
1611 {
1612 // Peops does nothing here...
1613 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1614 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1615 }
1616 
GPUgetMode(void)1617 long CALLBACK GPUgetMode(void)
1618 {
1619  long iT=0;
1620 
1621  if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1622  if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1623  return iT;
1624 }
1625 
1626 ////////////////////////////////////////////////////////////////////////
1627 // call config dlg
1628 ////////////////////////////////////////////////////////////////////////
1629 
GPUconfigure(void)1630 long CALLBACK GPUconfigure(void)
1631 {
1632 #ifdef _WINDOWS
1633  HWND hWP=GetActiveWindow();
1634 
1635  DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGSOFT),
1636            hWP,(DLGPROC)SoftDlgProc);
1637 #else
1638  SoftDlgProc();
1639 #endif
1640 
1641  return 0;
1642 }
1643 
1644 ////////////////////////////////////////////////////////////////////////
1645 // sets all kind of act fixes
1646 ////////////////////////////////////////////////////////////////////////
1647 
SetFixes(void)1648 void SetFixes(void)
1649  {
1650 #ifdef _WINDOWS
1651   BOOL bOldPerformanceCounter=IsPerformanceCounter;    // store curr timer mode
1652 
1653   if(dwActFixes&0x10)                                  // check fix 0x10
1654        IsPerformanceCounter=FALSE;
1655   else SetFPSHandler();
1656 
1657   if(bOldPerformanceCounter!=IsPerformanceCounter)     // we have change it?
1658    InitFPS();                                          // -> init fps again
1659 #endif
1660 
1661   if(dwActFixes&0x02) sDispWidths[4]=384;
1662   else                sDispWidths[4]=368;
1663  }
1664 
1665 ////////////////////////////////////////////////////////////////////////
1666 // process gpu commands
1667 ////////////////////////////////////////////////////////////////////////
1668 
1669 unsigned long lUsedAddr[3];
1670 
CheckForEndlessLoop(unsigned long laddr)1671 static __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1672 {
1673  if(laddr==lUsedAddr[1]) return TRUE;
1674  if(laddr==lUsedAddr[2]) return TRUE;
1675 
1676  if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1677  else                   lUsedAddr[2]=laddr;
1678  lUsedAddr[0]=laddr;
1679  return FALSE;
1680 }
1681 
GPUdmaChain(uint32_t * baseAddrL,uint32_t addr)1682 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1683 {
1684  uint32_t dmaMem;
1685  unsigned char * baseAddrB;
1686  short count;unsigned int DMACommandCounter = 0;
1687 
1688  GPUIsBusy;
1689 
1690  lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1691 
1692  baseAddrB = (unsigned char*) baseAddrL;
1693 
1694  do
1695   {
1696    if(iGPUHeight==512) addr&=0x1FFFFC;
1697    if(DMACommandCounter++ > 2000000) break;
1698    if(CheckForEndlessLoop(addr)) break;
1699 
1700    count = baseAddrB[addr+3];
1701 
1702    dmaMem=addr+4;
1703 
1704    if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1705 
1706    addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1707   }
1708  while (addr != 0xffffff);
1709 
1710  GPUIsIdle;
1711 
1712  return 0;
1713 }
1714 
1715 ////////////////////////////////////////////////////////////////////////
1716 // show about dlg
1717 ////////////////////////////////////////////////////////////////////////
1718 
1719 #ifdef _WINDOWS
AboutDlgProc(HWND hW,UINT uMsg,WPARAM wParam,LPARAM lParam)1720 BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
1721 {
1722  switch(uMsg)
1723   {
1724    case WM_COMMAND:
1725     {
1726      switch(LOWORD(wParam))
1727       {case IDOK:     EndDialog(hW,TRUE);return TRUE;}
1728     }
1729   }
1730  return FALSE;
1731 }
1732 #endif
1733 
GPUabout(void)1734 void CALLBACK GPUabout(void)                           // ABOUT
1735 {
1736 #ifdef _WINDOWS
1737  HWND hWP=GetActiveWindow();                           // to be sure
1738  DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT),
1739            hWP,(DLGPROC)AboutDlgProc);
1740 #else
1741  AboutDlgProc();
1742 #endif
1743 
1744  return;
1745 }
1746 
1747 ////////////////////////////////////////////////////////////////////////
1748 // We are ever fine ;)
1749 ////////////////////////////////////////////////////////////////////////
1750 
GPUtest(void)1751 long CALLBACK GPUtest(void)
1752 {
1753  // if test fails this function should return negative value for error (unable to continue)
1754  // and positive value for warning (can continue but output might be crappy)
1755  return 0;
1756 }
1757 
1758 ////////////////////////////////////////////////////////////////////////
1759 // Freeze
1760 ////////////////////////////////////////////////////////////////////////
1761 
1762 typedef struct GPUFREEZETAG
1763 {
1764  uint32_t ulFreezeVersion;      // should be always 1 for now (set by main emu)
1765  uint32_t ulStatus;             // current gpu status
1766  uint32_t ulControl[256];       // latest control register values
1767  unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1768 } GPUFreeze_t;
1769 
1770 ////////////////////////////////////////////////////////////////////////
1771 
GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)1772 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1773 {
1774  //----------------------------------------------------//
1775  if(ulGetFreezeData==2)                                // 2: info, which save slot is selected? (just for display)
1776   {
1777    long lSlotNum=*((long *)pF);
1778    if(lSlotNum<0) return 0;
1779    if(lSlotNum>8) return 0;
1780    lSelectedSlot=lSlotNum+1;
1781    BuildDispMenu(0);
1782    return 1;
1783   }
1784  //----------------------------------------------------//
1785  if(!pF)                    return 0;                  // some checks
1786  if(pF->ulFreezeVersion!=1) return 0;
1787 
1788  if(ulGetFreezeData==1)                                // 1: get data
1789   {
1790    pF->ulStatus=lGPUstatusRet;
1791    memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1792    memcpy(pF->psxVRam,  psxVub,         1024*iGPUHeight*2);
1793 
1794    return 1;
1795   }
1796 
1797  if(ulGetFreezeData!=0) return 0;                      // 0: set data
1798 
1799  lGPUstatusRet=pF->ulStatus;
1800  memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1801  memcpy(psxVub,         pF->psxVRam,  1024*iGPUHeight*2);
1802 
1803 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1804 
1805  GPUwriteStatus(ulStatusControl[0]);
1806  GPUwriteStatus(ulStatusControl[1]);
1807  GPUwriteStatus(ulStatusControl[2]);
1808  GPUwriteStatus(ulStatusControl[3]);
1809  GPUwriteStatus(ulStatusControl[8]);                   // try to repair things
1810  GPUwriteStatus(ulStatusControl[6]);
1811  GPUwriteStatus(ulStatusControl[7]);
1812  GPUwriteStatus(ulStatusControl[5]);
1813  GPUwriteStatus(ulStatusControl[4]);
1814 
1815  return 1;
1816 }
1817 
1818 ////////////////////////////////////////////////////////////////////////
1819 ////////////////////////////////////////////////////////////////////////
1820 ////////////////////////////////////////////////////////////////////////
1821 ////////////////////////////////////////////////////////////////////////
1822 ////////////////////////////////////////////////////////////////////////
1823 ////////////////////////////////////////////////////////////////////////
1824 
1825 ////////////////////////////////////////////////////////////////////////
1826 // SAVE STATE DISPLAY STUFF
1827 ////////////////////////////////////////////////////////////////////////
1828 
1829 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1830 // 00 = black
1831 // 01 = white
1832 // 10 = red
1833 // 11 = transparent
1834 
1835 unsigned char cFont[10][120]=
1836 {
1837 // 0
1838 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1839  0x80,0x00,0x00,0x00,0x00,0x00,
1840  0x80,0x00,0x00,0x00,0x00,0x00,
1841  0x80,0x00,0x00,0x00,0x00,0x00,
1842  0x80,0x00,0x00,0x00,0x00,0x00,
1843  0x80,0x00,0x05,0x54,0x00,0x00,
1844  0x80,0x00,0x14,0x05,0x00,0x00,
1845  0x80,0x00,0x14,0x05,0x00,0x00,
1846  0x80,0x00,0x14,0x05,0x00,0x00,
1847  0x80,0x00,0x14,0x05,0x00,0x00,
1848  0x80,0x00,0x14,0x05,0x00,0x00,
1849  0x80,0x00,0x14,0x05,0x00,0x00,
1850  0x80,0x00,0x14,0x05,0x00,0x00,
1851  0x80,0x00,0x14,0x05,0x00,0x00,
1852  0x80,0x00,0x05,0x54,0x00,0x00,
1853  0x80,0x00,0x00,0x00,0x00,0x00,
1854  0x80,0x00,0x00,0x00,0x00,0x00,
1855  0x80,0x00,0x00,0x00,0x00,0x00,
1856  0x80,0x00,0x00,0x00,0x00,0x00,
1857  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1858 },
1859 // 1
1860 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1861  0x80,0x00,0x00,0x00,0x00,0x00,
1862  0x80,0x00,0x00,0x00,0x00,0x00,
1863  0x80,0x00,0x00,0x00,0x00,0x00,
1864  0x80,0x00,0x00,0x00,0x00,0x00,
1865  0x80,0x00,0x00,0x50,0x00,0x00,
1866  0x80,0x00,0x05,0x50,0x00,0x00,
1867  0x80,0x00,0x00,0x50,0x00,0x00,
1868  0x80,0x00,0x00,0x50,0x00,0x00,
1869  0x80,0x00,0x00,0x50,0x00,0x00,
1870  0x80,0x00,0x00,0x50,0x00,0x00,
1871  0x80,0x00,0x00,0x50,0x00,0x00,
1872  0x80,0x00,0x00,0x50,0x00,0x00,
1873  0x80,0x00,0x00,0x50,0x00,0x00,
1874  0x80,0x00,0x05,0x55,0x00,0x00,
1875  0x80,0x00,0x00,0x00,0x00,0x00,
1876  0x80,0x00,0x00,0x00,0x00,0x00,
1877  0x80,0x00,0x00,0x00,0x00,0x00,
1878  0x80,0x00,0x00,0x00,0x00,0x00,
1879  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1880 },
1881 // 2
1882 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1883  0x80,0x00,0x00,0x00,0x00,0x00,
1884  0x80,0x00,0x00,0x00,0x00,0x00,
1885  0x80,0x00,0x00,0x00,0x00,0x00,
1886  0x80,0x00,0x00,0x00,0x00,0x00,
1887  0x80,0x00,0x05,0x54,0x00,0x00,
1888  0x80,0x00,0x14,0x05,0x00,0x00,
1889  0x80,0x00,0x00,0x05,0x00,0x00,
1890  0x80,0x00,0x00,0x05,0x00,0x00,
1891  0x80,0x00,0x00,0x14,0x00,0x00,
1892  0x80,0x00,0x00,0x50,0x00,0x00,
1893  0x80,0x00,0x01,0x40,0x00,0x00,
1894  0x80,0x00,0x05,0x00,0x00,0x00,
1895  0x80,0x00,0x14,0x00,0x00,0x00,
1896  0x80,0x00,0x15,0x55,0x00,0x00,
1897  0x80,0x00,0x00,0x00,0x00,0x00,
1898  0x80,0x00,0x00,0x00,0x00,0x00,
1899  0x80,0x00,0x00,0x00,0x00,0x00,
1900  0x80,0x00,0x00,0x00,0x00,0x00,
1901  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1902 },
1903 // 3
1904 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1905  0x80,0x00,0x00,0x00,0x00,0x00,
1906  0x80,0x00,0x00,0x00,0x00,0x00,
1907  0x80,0x00,0x00,0x00,0x00,0x00,
1908  0x80,0x00,0x00,0x00,0x00,0x00,
1909  0x80,0x00,0x05,0x54,0x00,0x00,
1910  0x80,0x00,0x14,0x05,0x00,0x00,
1911  0x80,0x00,0x00,0x05,0x00,0x00,
1912  0x80,0x00,0x00,0x05,0x00,0x00,
1913  0x80,0x00,0x01,0x54,0x00,0x00,
1914  0x80,0x00,0x00,0x05,0x00,0x00,
1915  0x80,0x00,0x00,0x05,0x00,0x00,
1916  0x80,0x00,0x00,0x05,0x00,0x00,
1917  0x80,0x00,0x14,0x05,0x00,0x00,
1918  0x80,0x00,0x05,0x54,0x00,0x00,
1919  0x80,0x00,0x00,0x00,0x00,0x00,
1920  0x80,0x00,0x00,0x00,0x00,0x00,
1921  0x80,0x00,0x00,0x00,0x00,0x00,
1922  0x80,0x00,0x00,0x00,0x00,0x00,
1923  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1924 },
1925 // 4
1926 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1927  0x80,0x00,0x00,0x00,0x00,0x00,
1928  0x80,0x00,0x00,0x00,0x00,0x00,
1929  0x80,0x00,0x00,0x00,0x00,0x00,
1930  0x80,0x00,0x00,0x00,0x00,0x00,
1931  0x80,0x00,0x00,0x14,0x00,0x00,
1932  0x80,0x00,0x00,0x54,0x00,0x00,
1933  0x80,0x00,0x01,0x54,0x00,0x00,
1934  0x80,0x00,0x01,0x54,0x00,0x00,
1935  0x80,0x00,0x05,0x14,0x00,0x00,
1936  0x80,0x00,0x14,0x14,0x00,0x00,
1937  0x80,0x00,0x15,0x55,0x00,0x00,
1938  0x80,0x00,0x00,0x14,0x00,0x00,
1939  0x80,0x00,0x00,0x14,0x00,0x00,
1940  0x80,0x00,0x00,0x55,0x00,0x00,
1941  0x80,0x00,0x00,0x00,0x00,0x00,
1942  0x80,0x00,0x00,0x00,0x00,0x00,
1943  0x80,0x00,0x00,0x00,0x00,0x00,
1944  0x80,0x00,0x00,0x00,0x00,0x00,
1945  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1946 },
1947 // 5
1948 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1949  0x80,0x00,0x00,0x00,0x00,0x00,
1950  0x80,0x00,0x00,0x00,0x00,0x00,
1951  0x80,0x00,0x00,0x00,0x00,0x00,
1952  0x80,0x00,0x00,0x00,0x00,0x00,
1953  0x80,0x00,0x15,0x55,0x00,0x00,
1954  0x80,0x00,0x14,0x00,0x00,0x00,
1955  0x80,0x00,0x14,0x00,0x00,0x00,
1956  0x80,0x00,0x14,0x00,0x00,0x00,
1957  0x80,0x00,0x15,0x54,0x00,0x00,
1958  0x80,0x00,0x00,0x05,0x00,0x00,
1959  0x80,0x00,0x00,0x05,0x00,0x00,
1960  0x80,0x00,0x00,0x05,0x00,0x00,
1961  0x80,0x00,0x14,0x05,0x00,0x00,
1962  0x80,0x00,0x05,0x54,0x00,0x00,
1963  0x80,0x00,0x00,0x00,0x00,0x00,
1964  0x80,0x00,0x00,0x00,0x00,0x00,
1965  0x80,0x00,0x00,0x00,0x00,0x00,
1966  0x80,0x00,0x00,0x00,0x00,0x00,
1967  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1968 },
1969 // 6
1970 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1971  0x80,0x00,0x00,0x00,0x00,0x00,
1972  0x80,0x00,0x00,0x00,0x00,0x00,
1973  0x80,0x00,0x00,0x00,0x00,0x00,
1974  0x80,0x00,0x00,0x00,0x00,0x00,
1975  0x80,0x00,0x01,0x54,0x00,0x00,
1976  0x80,0x00,0x05,0x00,0x00,0x00,
1977  0x80,0x00,0x14,0x00,0x00,0x00,
1978  0x80,0x00,0x14,0x00,0x00,0x00,
1979  0x80,0x00,0x15,0x54,0x00,0x00,
1980  0x80,0x00,0x15,0x05,0x00,0x00,
1981  0x80,0x00,0x14,0x05,0x00,0x00,
1982  0x80,0x00,0x14,0x05,0x00,0x00,
1983  0x80,0x00,0x14,0x05,0x00,0x00,
1984  0x80,0x00,0x05,0x54,0x00,0x00,
1985  0x80,0x00,0x00,0x00,0x00,0x00,
1986  0x80,0x00,0x00,0x00,0x00,0x00,
1987  0x80,0x00,0x00,0x00,0x00,0x00,
1988  0x80,0x00,0x00,0x00,0x00,0x00,
1989  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1990 },
1991 // 7
1992 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1993  0x80,0x00,0x00,0x00,0x00,0x00,
1994  0x80,0x00,0x00,0x00,0x00,0x00,
1995  0x80,0x00,0x00,0x00,0x00,0x00,
1996  0x80,0x00,0x00,0x00,0x00,0x00,
1997  0x80,0x00,0x15,0x55,0x00,0x00,
1998  0x80,0x00,0x14,0x05,0x00,0x00,
1999  0x80,0x00,0x00,0x14,0x00,0x00,
2000  0x80,0x00,0x00,0x14,0x00,0x00,
2001  0x80,0x00,0x00,0x50,0x00,0x00,
2002  0x80,0x00,0x00,0x50,0x00,0x00,
2003  0x80,0x00,0x01,0x40,0x00,0x00,
2004  0x80,0x00,0x01,0x40,0x00,0x00,
2005  0x80,0x00,0x05,0x00,0x00,0x00,
2006  0x80,0x00,0x05,0x00,0x00,0x00,
2007  0x80,0x00,0x00,0x00,0x00,0x00,
2008  0x80,0x00,0x00,0x00,0x00,0x00,
2009  0x80,0x00,0x00,0x00,0x00,0x00,
2010  0x80,0x00,0x00,0x00,0x00,0x00,
2011  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
2012 },
2013 // 8
2014 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
2015  0x80,0x00,0x00,0x00,0x00,0x00,
2016  0x80,0x00,0x00,0x00,0x00,0x00,
2017  0x80,0x00,0x00,0x00,0x00,0x00,
2018  0x80,0x00,0x00,0x00,0x00,0x00,
2019  0x80,0x00,0x05,0x54,0x00,0x00,
2020  0x80,0x00,0x14,0x05,0x00,0x00,
2021  0x80,0x00,0x14,0x05,0x00,0x00,
2022  0x80,0x00,0x14,0x05,0x00,0x00,
2023  0x80,0x00,0x05,0x54,0x00,0x00,
2024  0x80,0x00,0x14,0x05,0x00,0x00,
2025  0x80,0x00,0x14,0x05,0x00,0x00,
2026  0x80,0x00,0x14,0x05,0x00,0x00,
2027  0x80,0x00,0x14,0x05,0x00,0x00,
2028  0x80,0x00,0x05,0x54,0x00,0x00,
2029  0x80,0x00,0x00,0x00,0x00,0x00,
2030  0x80,0x00,0x00,0x00,0x00,0x00,
2031  0x80,0x00,0x00,0x00,0x00,0x00,
2032  0x80,0x00,0x00,0x00,0x00,0x00,
2033  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
2034 },
2035 // 9
2036 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
2037  0x80,0x00,0x00,0x00,0x00,0x00,
2038  0x80,0x00,0x00,0x00,0x00,0x00,
2039  0x80,0x00,0x00,0x00,0x00,0x00,
2040  0x80,0x00,0x00,0x00,0x00,0x00,
2041  0x80,0x00,0x05,0x54,0x00,0x00,
2042  0x80,0x00,0x14,0x05,0x00,0x00,
2043  0x80,0x00,0x14,0x05,0x00,0x00,
2044  0x80,0x00,0x14,0x05,0x00,0x00,
2045  0x80,0x00,0x14,0x15,0x00,0x00,
2046  0x80,0x00,0x05,0x55,0x00,0x00,
2047  0x80,0x00,0x00,0x05,0x00,0x00,
2048  0x80,0x00,0x00,0x05,0x00,0x00,
2049  0x80,0x00,0x00,0x14,0x00,0x00,
2050  0x80,0x00,0x05,0x50,0x00,0x00,
2051  0x80,0x00,0x00,0x00,0x00,0x00,
2052  0x80,0x00,0x00,0x00,0x00,0x00,
2053  0x80,0x00,0x00,0x00,0x00,0x00,
2054  0x80,0x00,0x00,0x00,0x00,0x00,
2055  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
2056 }
2057 };
2058 
2059 ////////////////////////////////////////////////////////////////////////
2060 
PaintPicDot(unsigned char * p,unsigned char c)2061 void PaintPicDot(unsigned char * p,unsigned char c)
2062 {
2063 
2064  if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}        // black
2065  if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}        // white
2066  if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}        // red
2067                                                        // transparent
2068 }
2069 
2070 ////////////////////////////////////////////////////////////////////////
2071 // the main emu allocs 128x96x3 bytes, and passes a ptr
2072 // to it in pMem... the plugin has to fill it with
2073 // 8-8-8 bit BGR screen data (Win 24 bit BMP format
2074 // without header).
2075 // Beware: the func can be called at any time,
2076 // so you have to use the frontbuffer to get a fully
2077 // rendered picture
2078 
2079 #ifdef _WINDOWS
2080 
GPUgetScreenPic(unsigned char * pMem)2081 void CALLBACK GPUgetScreenPic(unsigned char * pMem)
2082 {
2083  HRESULT ddrval;DDSURFACEDESC xddsd;unsigned char * pf;
2084  int x,y,c,v;RECT r;
2085  float XS,YS;
2086 
2087  memset(&xddsd, 0, sizeof(DDSURFACEDESC));
2088  xddsd.dwSize   = sizeof(DDSURFACEDESC);
2089  xddsd.dwFlags  = DDSD_WIDTH | DDSD_HEIGHT;
2090  xddsd.dwWidth  = iResX;
2091  xddsd.dwHeight = iResY;
2092 
2093  r.left=0; r.right =iResX;
2094  r.top=0;  r.bottom=iResY;
2095 
2096  if(iWindowMode)
2097   {
2098    POINT Point={0,0};
2099    ClientToScreen(DX.hWnd,&Point);
2100    r.left+=Point.x;r.right+=Point.x;
2101    r.top+=Point.y;r.bottom+=Point.y;
2102   }
2103 
2104  XS=(float)iResX/128;
2105  YS=(float)iResY/96;
2106 
2107  ddrval=IDirectDrawSurface_Lock(DX.DDSPrimary,NULL, &xddsd, DDLOCK_WAIT|DDLOCK_READONLY, NULL);
2108 
2109  if(ddrval==DDERR_SURFACELOST) IDirectDrawSurface_Restore(DX.DDSPrimary);
2110 
2111  pf=pMem;
2112 
2113  if(ddrval==DD_OK)
2114   {
2115    unsigned char * ps=(unsigned char *)xddsd.lpSurface;
2116 
2117    if(iDesktopCol==16)
2118     {
2119      unsigned short sx;
2120      for(y=0;y<96;y++)
2121       {
2122        for(x=0;x<128;x++)
2123         {
2124          sx=*((unsigned short *)((ps)+
2125               r.top*xddsd.lPitch+
2126               (((int)((float)y*YS))*xddsd.lPitch)+
2127                r.left*2+
2128                ((int)((float)x*XS))*2));
2129          *(pf+0)=(sx&0x1f)<<3;
2130          *(pf+1)=(sx&0x7e0)>>3;
2131          *(pf+2)=(sx&0xf800)>>8;
2132          pf+=3;
2133         }
2134       }
2135     }
2136    else
2137    if(iDesktopCol==15)
2138     {
2139      unsigned short sx;
2140      for(y=0;y<96;y++)
2141       {
2142        for(x=0;x<128;x++)
2143         {
2144          sx=*((unsigned short *)((ps)+
2145               r.top*xddsd.lPitch+
2146               (((int)((float)y*YS))*xddsd.lPitch)+
2147                r.left*2+
2148                ((int)((float)x*XS))*2));
2149          *(pf+0)=(sx&0x1f)<<3;
2150          *(pf+1)=(sx&0x3e0)>>2;
2151          *(pf+2)=(sx&0x7c00)>>7;
2152          pf+=3;
2153         }
2154       }
2155     }
2156    else
2157     {
2158      unsigned long sx;
2159      for(y=0;y<96;y++)
2160       {
2161        for(x=0;x<128;x++)
2162         {
2163          sx=*((unsigned long *)((ps)+
2164               r.top*xddsd.lPitch+
2165               (((int)((float)y*YS))*xddsd.lPitch)+
2166                r.left*4+
2167                ((int)((float)x*XS))*4));
2168          *(pf+0)=(unsigned char)((sx&0xff));
2169          *(pf+1)=(unsigned char)((sx&0xff00)>>8);
2170          *(pf+2)=(unsigned char)((sx&0xff0000)>>16);
2171          pf+=3;
2172         }
2173       }
2174     }
2175   }
2176 
2177  IDirectDrawSurface_Unlock(DX.DDSPrimary,&xddsd);
2178 
2179  /////////////////////////////////////////////////////////////////////
2180  // generic number/border painter
2181 
2182  pf=pMem+(103*3);                                      // offset to number rect
2183 
2184  for(y=0;y<20;y++)                                     // loop the number rect pixel
2185   {
2186    for(x=0;x<6;x++)
2187     {
2188      c=cFont[lSelectedSlot][x+y*6];                    // get 4 char dot infos at once (number depends on selected slot)
2189      v=(c&0xc0)>>6;
2190      PaintPicDot(pf,(unsigned char)v);pf+=3;                // paint the dots into the rect
2191      v=(c&0x30)>>4;
2192      PaintPicDot(pf,(unsigned char)v);pf+=3;
2193      v=(c&0x0c)>>2;
2194      PaintPicDot(pf,(unsigned char)v);pf+=3;
2195      v=c&0x03;
2196      PaintPicDot(pf,(unsigned char)v);pf+=3;
2197     }
2198    pf+=104*3;                                          // next rect y line
2199   }
2200 
2201  pf=pMem;                                              // ptr to first pos in 128x96 pic
2202  for(x=0;x<128;x++)                                    // loop top/bottom line
2203   {
2204    *(pf+(95*128*3))=0x00;*pf++=0x00;
2205    *(pf+(95*128*3))=0x00;*pf++=0x00;                   // paint it red
2206    *(pf+(95*128*3))=0xff;*pf++=0xff;
2207   }
2208  pf=pMem;                                              // ptr to first pos
2209  for(y=0;y<96;y++)                                     // loop left/right line
2210   {
2211    *(pf+(127*3))=0x00;*pf++=0x00;
2212    *(pf+(127*3))=0x00;*pf++=0x00;                      // paint it red
2213    *(pf+(127*3))=0xff;*pf++=0xff;
2214    pf+=127*3;                                          // offset to next line
2215   }
2216 }
2217 
2218 #else
2219 
2220 // LINUX version:
2221 
GPUgetScreenPic(unsigned char * pMem)2222 void GPUgetScreenPic(unsigned char * pMem)
2223 {
2224   unsigned char *pf=pMem;
2225   unsigned char *buf, *line, *pD;
2226 
2227   int w = PreviousPSXDisplay.Range.x1, h = PreviousPSXDisplay.DisplayMode.y;
2228   int x, y;
2229   float XS = w / 128.0, YS = h / 96.0;
2230   line = pf;
2231   for (y = 0; y < 96; ++y) {
2232     for (x = 0; x < 128; ++x) {
2233       float r = 0, g = 0, b = 0, sr, sg, sb;
2234       uint32_t cnt = 0, i, j;
2235       for (j = 0; j < (int)((y+1)*YS) - (int)(y*YS); ++j) {
2236 	for (i = 0; i < (int)((x+1)*XS) - (int)(x*XS); ++i) {
2237 	  pD = (unsigned char *)&psxVuw[(int)(y*YS +
2238 	      PSXDisplay.DisplayPosition.y - 1 + j) * 1024 +
2239 	      PSXDisplay.DisplayPosition.x] +
2240 	      (PSXDisplay.RGB24 ? 3 : 2) * (int)(x*XS + i);
2241 	  if (PSXDisplay.RGB24) {
2242 	    uint32_t lu = *(uint32_t *)pD;
2243 	    sr = RED(lu);
2244 	    sg = GREEN(lu);
2245 	    sb = BLUE(lu);
2246 	  } else {
2247 	    int32_t color = GETLE16(pD);
2248 	    sr = (color << 3) & 0xf1;
2249 	    sg = (color >> 2) & 0xf1;
2250 	    sb = (color >> 7) & 0xf1;
2251 	  }
2252 	  r += sr * sr;
2253 	  g += sg * sg;
2254 	  b += sb * sb;
2255 	  cnt += 1;
2256 	}
2257 	line[x * 3 + 2] = sqrt(r / cnt);
2258 	line[x * 3 + 1] = sqrt(g / cnt);
2259 	line[x * 3 + 0] = sqrt(b / cnt);
2260       }
2261     }
2262     line += 128 * 3;
2263   }
2264 
2265  /////////////////////////////////////////////////////////////////////
2266  // generic number/border painter
2267 
2268  unsigned short c;
2269  pf=pMem+(103*3);                                      // offset to number rect
2270 
2271  for(y=0;y<20;y++)                                     // loop the number rect pixel
2272   {
2273    for(x=0;x<6;x++)
2274     {
2275      c=cFont[lSelectedSlot][x+y*6];                    // get 4 char dot infos at once (number depends on selected slot)
2276      PaintPicDot(pf,(c&0xc0)>>6);pf+=3;                // paint the dots into the rect
2277      PaintPicDot(pf,(c&0x30)>>4);pf+=3;
2278      PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
2279      PaintPicDot(pf,(c&0x03));   pf+=3;
2280     }
2281    pf+=104*3;                                          // next rect y line
2282   }
2283 
2284  pf=pMem;                                              // ptr to first pos in 128x96 pic
2285  for(x=0;x<128;x++)                                    // loop top/bottom line
2286   {
2287    *(pf+(95*128*3))=0x00;*pf++=0x00;
2288    *(pf+(95*128*3))=0x00;*pf++=0x00;                   // paint it red
2289    *(pf+(95*128*3))=0xff;*pf++=0xff;
2290   }
2291  pf=pMem;                                              // ptr to first pos
2292  for(y=0;y<96;y++)                                     // loop left/right line
2293   {
2294    *(pf+(127*3))=0x00;*pf++=0x00;
2295    *(pf+(127*3))=0x00;*pf++=0x00;                      // paint it red
2296    *(pf+(127*3))=0xff;*pf++=0xff;
2297    pf+=127*3;                                          // offset to next line
2298   }
2299 }
2300 
2301 #endif
2302 
2303 ////////////////////////////////////////////////////////////////////////
2304 // func will be called with 128x96x3 BGR data.
2305 // the plugin has to store the data and display
2306 // it in the upper right corner.
2307 // If the func is called with a NULL ptr, you can
2308 // release your picture data and stop displaying
2309 // the screen pic
2310 
GPUshowScreenPic(unsigned char * pMem)2311 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
2312 {
2313  DestroyPic();                                         // destroy old pic data
2314  if(pMem==0) return;                                   // done
2315  CreatePic(pMem);                                      // create new pic... don't free pMem or something like that... just read from it
2316 }
2317 
GPUsetfix(uint32_t dwFixBits)2318 void CALLBACK GPUsetfix(uint32_t dwFixBits)
2319 {
2320  dwEmuFixes=dwFixBits;
2321 }
2322 
GPUvBlank(int val)2323 void CALLBACK GPUvBlank( int val )
2324 {
2325  vBlank = val;
2326  oddLines = oddLines ? FALSE : TRUE; // bit changes per frame when not interlaced
2327  //printf("VB %x (%x)\n", oddLines, vBlank);
2328 }
2329 
GPUhSync(int val)2330 void CALLBACK GPUhSync( int val ) {
2331  // Interlaced mode - update bit every scanline
2332  if (PSXDisplay.Interlaced) {
2333    oddLines = (val%2 ? FALSE : TRUE);
2334  }
2335  //printf("HS %x (%x)\n", oddLines, vBlank);
2336 }
2337 
GPUvisualVibration(uint32_t iSmall,uint32_t iBig)2338 void CALLBACK GPUvisualVibration(uint32_t iSmall, uint32_t iBig)
2339 {
2340  int iVibVal;
2341 
2342  if(PreviousPSXDisplay.DisplayMode.x)                  // calc min "shake pixel" from screen width
2343       iVibVal=max(1,iResX/PreviousPSXDisplay.DisplayMode.x);
2344  else iVibVal=1;
2345                                                        // big rumble: 4...15 sp ; small rumble 1...3 sp
2346  if(iBig) iRumbleVal=max(4*iVibVal,min(15*iVibVal,((int)iBig  *iVibVal)/10));
2347  else     iRumbleVal=max(1*iVibVal,min( 3*iVibVal,((int)iSmall*iVibVal)/10));
2348 
2349  iRumbleTime=15;                                       // let the rumble last 16 buffer swaps
2350 }
2351