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