gpu_unai: basic frameskip
[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    bSkipNextFrame = FALSE;
498    DoBufferSwap();                                     // -> swap
499   }
500 }
501
502 ////////////////////////////////////////////////////////////////////////
503 // roughly emulated screen centering bits... not complete !!!
504 ////////////////////////////////////////////////////////////////////////
505
506 void ChangeDispOffsetsX(void)                          // X CENTER
507 {
508  long lx,l;
509
510  if(!PSXDisplay.Range.x1) return;
511
512  l=PreviousPSXDisplay.DisplayMode.x;
513
514  l*=(long)PSXDisplay.Range.x1;
515  l/=2560;lx=l;l&=0xfffffff8;
516
517  if(l==PreviousPSXDisplay.Range.y1) return;            // abusing range.y1 for
518  PreviousPSXDisplay.Range.y1=(short)l;                 // storing last x range and test
519
520  if(lx>=PreviousPSXDisplay.DisplayMode.x)
521   {
522    PreviousPSXDisplay.Range.x1=
523     (short)PreviousPSXDisplay.DisplayMode.x;
524    PreviousPSXDisplay.Range.x0=0;
525   }
526  else
527   {
528    PreviousPSXDisplay.Range.x1=(short)l;
529
530    PreviousPSXDisplay.Range.x0=
531     (PSXDisplay.Range.x0-500)/8;
532
533    if(PreviousPSXDisplay.Range.x0<0)
534     PreviousPSXDisplay.Range.x0=0;
535
536    if((PreviousPSXDisplay.Range.x0+lx)>
537       PreviousPSXDisplay.DisplayMode.x)
538     {
539      PreviousPSXDisplay.Range.x0=
540       (short)(PreviousPSXDisplay.DisplayMode.x-lx);
541      PreviousPSXDisplay.Range.x0+=2; //???
542
543      PreviousPSXDisplay.Range.x1+=(short)(lx-l);
544
545      PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
546
547     }
548
549
550    // some linux alignment security
551    PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
552    PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
553    PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
554    PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
555
556
557    DoClearScreenBuffer();
558   }
559
560  bDoVSyncUpdate=TRUE;
561 }
562
563 ////////////////////////////////////////////////////////////////////////
564
565 void ChangeDispOffsetsY(void)                          // Y CENTER
566 {
567  int iT,iO=PreviousPSXDisplay.Range.y0;
568  int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
569
570 // new
571
572  if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight)
573   {
574    int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x;
575    int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight;
576
577    if(dy1>=dy2)
578     {
579      PreviousPSXDisplay.DisplayModeNew.y=-dy2;
580     }
581    else
582     {
583      PSXDisplay.DisplayPosition.y=0;
584      PreviousPSXDisplay.DisplayModeNew.y=-dy1;
585     }
586   }
587  else PreviousPSXDisplay.DisplayModeNew.y=0;
588
589 // eon
590
591  if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
592   {
593    PSXDisplay.Height = PSXDisplay.Range.y1 - 
594                        PSXDisplay.Range.y0 +
595                        PreviousPSXDisplay.DisplayModeNew.y;
596    PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
597   }
598
599 //
600
601  if(PSXDisplay.PAL) iT=48; else iT=28;
602
603  if(PSXDisplay.Range.y0>=iT)
604   {
605    PreviousPSXDisplay.Range.y0=
606     (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
607    if(PreviousPSXDisplay.Range.y0<0)
608     PreviousPSXDisplay.Range.y0=0;
609    PSXDisplay.DisplayModeNew.y+=
610     PreviousPSXDisplay.Range.y0;
611   }
612  else 
613   PreviousPSXDisplay.Range.y0=0;
614
615  if(iO!=PreviousPSXDisplay.Range.y0)
616   {
617    DoClearScreenBuffer();
618  }
619 }
620
621 ////////////////////////////////////////////////////////////////////////
622 // check if update needed
623 ////////////////////////////////////////////////////////////////////////
624
625 void updateDisplayIfChanged(void)                      // UPDATE DISPLAY IF CHANGED
626 {
627  if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) && 
628      (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
629   {
630    if((PSXDisplay.RGB24      == PSXDisplay.RGB24New) && 
631       (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
632   }
633
634  PSXDisplay.RGB24         = PSXDisplay.RGB24New;       // get new infos
635
636  PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
637  PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
638  PreviousPSXDisplay.DisplayMode.x=                     // previous will hold
639   min(640,PSXDisplay.DisplayMode.x);                   // max 640x512... that's
640  PreviousPSXDisplay.DisplayMode.y=                     // the size of my 
641   min(512,PSXDisplay.DisplayMode.y);                   // back buffer surface
642  PSXDisplay.Interlaced    = PSXDisplay.InterlacedNew;
643     
644  PSXDisplay.DisplayEnd.x=                              // calc end of display
645   PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
646  PSXDisplay.DisplayEnd.y=
647   PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
648  PreviousPSXDisplay.DisplayEnd.x=
649   PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
650  PreviousPSXDisplay.DisplayEnd.y=
651   PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
652
653  ChangeDispOffsetsX();
654
655  if(iFrameLimit==2) SetAutoFrameCap();                 // -> set it
656
657  if(UseFrameSkip) updateDisplay();                     // stupid stuff when frame skipping enabled
658 }
659
660 ////////////////////////////////////////////////////////////////////////
661
662 #ifndef _MACGL
663
664 #include "draw.h"
665
666 void ChangeWindowMode(void)                            // TOGGLE FULLSCREEN - WINDOW
667 {
668  extern Display         *display;
669  extern Window        window;
670  extern int           root_window_id;
671  Screen                 *screen;
672  XSizeHints           hints;
673  MotifWmHints         mwmhints;
674  Atom                 mwmatom;
675
676  screen=DefaultScreenOfDisplay(display);
677  iWindowMode=!iWindowMode;
678
679  if(!iWindowMode)                                               // fullscreen
680   {
681    mwmhints.flags=MWM_HINTS_DECORATIONS;
682    mwmhints.functions=0;
683    mwmhints.decorations=0;
684    mwmhints.input_mode=0;
685    mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
686    XChangeProperty(display,window,mwmatom,mwmatom,32,
687                    PropModeReplace,(unsigned char *)&mwmhints,5);
688
689    XResizeWindow(display,window,screen->width,screen->height);
690
691    hints.min_width   = hints.max_width = hints.base_width = screen->width;
692    hints.min_height= hints.max_height = hints.base_height = screen->height;
693
694    XSetWMNormalHints(display,window,&hints);
695
696    {
697     XEvent xev;
698
699     memset(&xev, 0, sizeof(xev));
700     xev.xclient.type = ClientMessage;
701     xev.xclient.serial = 0;
702     xev.xclient.send_event = 1;
703     xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
704     xev.xclient.window = window;
705     xev.xclient.format = 32;
706     xev.xclient.data.l[0] = 1;
707     xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
708     xev.xclient.data.l[2] = 0;
709     xev.xclient.data.l[3] = 0;
710     xev.xclient.data.l[4] = 0;
711
712     XSendEvent(display, root_window_id, 0,
713       SubstructureRedirectMask | SubstructureNotifyMask, &xev);
714    }
715   } else {
716    {
717     XEvent xev;
718
719     memset(&xev, 0, sizeof(xev));
720     xev.xclient.type = ClientMessage;
721     xev.xclient.serial = 0;
722     xev.xclient.send_event = 1;
723     xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
724     xev.xclient.window = window;
725     xev.xclient.format = 32;
726     xev.xclient.data.l[0] = 0;
727     xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
728     xev.xclient.data.l[2] = 0;
729     xev.xclient.data.l[3] = 0;
730     xev.xclient.data.l[4] = 0;
731
732     XSendEvent(display, root_window_id, 0,
733       SubstructureRedirectMask | SubstructureNotifyMask, &xev);
734    }
735
736    mwmhints.flags=MWM_HINTS_DECORATIONS;
737    mwmhints.functions=0;
738    mwmhints.decorations=1;
739    mwmhints.input_mode=0;
740    mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
741
742    //This shouldn't work on 64 bit longs, but it does...in fact, it breaks when I change all the mwmhints to int.
743    //I don't pretend to understand it.
744    XChangeProperty(display,window,mwmatom,mwmatom,32,
745                    PropModeReplace,(unsigned char *)&mwmhints,5);
746
747  hints.flags=USPosition|USSize;
748  hints.base_width = iResX;
749  hints.base_height = iResY;
750    XSetWMNormalHints(display,window,&hints);
751
752    XResizeWindow(display,window,iResX,iResY);
753 }
754
755  DoClearScreenBuffer();
756
757  bChangeWinMode=FALSE;
758  bDoVSyncUpdate=TRUE;
759 }
760
761 #endif
762
763 ////////////////////////////////////////////////////////////////////////
764 // gun cursor func: player=0-7, x=0-511, y=0-255
765 ////////////////////////////////////////////////////////////////////////
766
767 void CALLBACK GPUcursor(int iPlayer,int x,int y)
768 {
769  if(iPlayer<0) return;
770  if(iPlayer>7) return;
771
772  usCursorActive|=(1<<iPlayer);
773
774  if(x<0)       x=0;
775  if(x>511)     x=511;
776  if(y<0)       y=0;
777  if(y>255)     y=255;
778
779  ptCursorPoint[iPlayer].x=x;
780  ptCursorPoint[iPlayer].y=y;
781 }
782
783 ////////////////////////////////////////////////////////////////////////
784 // update lace is called evry VSync
785 ////////////////////////////////////////////////////////////////////////
786
787 void CALLBACK GPUupdateLace(void)                      // VSYNC
788 {
789  if(!(dwActFixes&1))
790   lGPUstatusRet^=0x80000000;                           // odd/even bit
791
792  //pcsx-rearmed: removed, this is handled by core
793  //if(!(dwActFixes&32))                                  // std fps limitation?
794  // CheckFrameRate();
795
796  if(PSXDisplay.Interlaced)                             // interlaced mode?
797   {
798    if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
799     {
800      updateDisplay();
801     }
802   }
803  else                                                  // non-interlaced?
804   {
805    if(dwActFixes&64)                                   // lazy screen update fix
806     {
807      if(bDoLazyUpdate && !UseFrameSkip) 
808       updateDisplay(); 
809      bDoLazyUpdate=FALSE;
810     }
811    else
812     {
813      if(bDoVSyncUpdate && !UseFrameSkip)               // some primitives drawn?
814       updateDisplay();                                 // -> update display
815     }
816   }
817 #ifndef _MACGL
818  if(bChangeWinMode) ChangeWindowMode();                // toggle full - window mode
819 #endif
820  bDoVSyncUpdate=FALSE;                                 // vsync done
821 }
822
823 ////////////////////////////////////////////////////////////////////////
824 // process read request from GPU status register
825 ////////////////////////////////////////////////////////////////////////
826
827
828 uint32_t CALLBACK GPUreadStatus(void)             // READ STATUS
829 {
830  if(dwActFixes&1)
831   {
832    static int iNumRead=0;                         // odd/even hack
833    if((iNumRead++)==2)
834     {
835      iNumRead=0;
836      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)
837     }
838   }
839
840  if(iFakePrimBusy)                                // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
841   {
842    iFakePrimBusy--;
843
844    if(iFakePrimBusy&1)                            // we do a busy-idle-busy-idle sequence after/while drawing prims
845     {
846      GPUIsBusy;
847      GPUIsNotReadyForCommands;
848     }
849    else
850     {
851      GPUIsIdle;
852      GPUIsReadyForCommands;
853     }
854   }
855  return lGPUstatusRet;
856 }
857
858 ////////////////////////////////////////////////////////////////////////
859 // processes data send to GPU status register
860 // these are always single packet commands.
861 ////////////////////////////////////////////////////////////////////////
862
863 void CALLBACK GPUwriteStatus(uint32_t gdata)      // WRITE STATUS
864 {
865  uint32_t lCommand=(gdata>>24)&0xff;
866
867  ulStatusControl[lCommand]=gdata;                      // store command for freezing
868
869  switch(lCommand)
870   {
871    //--------------------------------------------------//
872    // reset gpu
873    case 0x00:
874     memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
875     lGPUstatusRet=0x14802000;
876     PSXDisplay.Disabled=1;
877     DataWriteMode=DataReadMode=DR_NORMAL;
878     PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
879     drawX=drawY=0;drawW=drawH=0;
880     sSetMask=0;lSetMask=0;bCheckMask=FALSE;
881     usMirror=0;
882     GlobalTextAddrX=0;GlobalTextAddrY=0;
883     GlobalTextTP=0;GlobalTextABR=0;
884     PSXDisplay.RGB24=FALSE;
885     PSXDisplay.Interlaced=FALSE;
886     bUsingTWin = FALSE;
887     return;
888    //--------------------------------------------------//
889    // dis/enable display 
890    case 0x03:  
891
892     PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
893     PSXDisplay.Disabled = (gdata & 1);
894
895     if(PSXDisplay.Disabled) 
896          lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
897     else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
898     return;
899
900    //--------------------------------------------------//
901    // setting transfer mode
902    case 0x04:
903     gdata &= 0x03;                                     // Only want the lower two bits
904
905     DataWriteMode=DataReadMode=DR_NORMAL;
906     if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
907     if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
908     lGPUstatusRet&=~GPUSTATUS_DMABITS;                 // Clear the current settings of the DMA bits
909     lGPUstatusRet|=(gdata << 29);                      // Set the DMA bits according to the received data
910
911     return;
912    //--------------------------------------------------//
913    // setting display position
914    case 0x05: 
915     {
916      PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
917      PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
918
919 ////////
920 /*
921      PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
922      if (PSXDisplay.DisplayPosition.y & 0x200) 
923       PSXDisplay.DisplayPosition.y |= 0xfffffc00;
924      if(PSXDisplay.DisplayPosition.y<0) 
925       {
926        PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
927        PSXDisplay.DisplayPosition.y=0;
928       }
929      else PreviousPSXDisplay.DisplayModeNew.y=0;
930 */
931
932 // new
933      if(iGPUHeight==1024)
934       {
935        if(dwGPUVersion==2) 
936             PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
937        else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
938       }
939      else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
940
941      // store the same val in some helper var, we need it on later compares
942      PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
943
944      if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
945       {
946        int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
947        int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
948
949        if(dy1>=dy2)
950         {
951          PreviousPSXDisplay.DisplayModeNew.y=-dy2;
952         }
953        else
954         {
955          PSXDisplay.DisplayPosition.y=0;
956          PreviousPSXDisplay.DisplayModeNew.y=-dy1;
957         }
958       }
959      else PreviousPSXDisplay.DisplayModeNew.y=0;
960 // eon
961
962      PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
963      PSXDisplay.DisplayEnd.x=
964       PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
965      PSXDisplay.DisplayEnd.y=
966       PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
967      PreviousPSXDisplay.DisplayEnd.x=
968       PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
969      PreviousPSXDisplay.DisplayEnd.y=
970       PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
971  
972      bDoVSyncUpdate=TRUE;
973
974      if (!(PSXDisplay.Interlaced))                      // stupid frame skipping option
975       {
976        if(UseFrameSkip)  updateDisplay();
977        if(dwActFixes&64) bDoLazyUpdate=TRUE;
978       }
979     }return;
980    //--------------------------------------------------//
981    // setting width
982    case 0x06:
983
984     PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
985     PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
986
987     PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
988
989     ChangeDispOffsetsX();
990
991     return;
992    //--------------------------------------------------//
993    // setting height
994    case 0x07:
995     {
996
997      PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
998      PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
999                                       
1000      PreviousPSXDisplay.Height = PSXDisplay.Height;
1001
1002      PSXDisplay.Height = PSXDisplay.Range.y1 - 
1003                          PSXDisplay.Range.y0 +
1004                          PreviousPSXDisplay.DisplayModeNew.y;
1005
1006      if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1007       {
1008        PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1009
1010        ChangeDispOffsetsY();
1011
1012        updateDisplayIfChanged();
1013       }
1014      return;
1015     }
1016    //--------------------------------------------------//
1017    // setting display infos
1018    case 0x08:
1019
1020     PSXDisplay.DisplayModeNew.x =
1021      sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1022
1023     if (gdata&0x04) PSXDisplay.Double=2;
1024     else            PSXDisplay.Double=1;
1025
1026     PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1027
1028     ChangeDispOffsetsY();
1029
1030     PSXDisplay.PAL           = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1031     PSXDisplay.RGB24New      = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1032     PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1033
1034     lGPUstatusRet&=~GPUSTATUS_WIDTHBITS;                   // Clear the width bits
1035     lGPUstatusRet|=
1036                (((gdata & 0x03) << 17) | 
1037                ((gdata & 0x40) << 10));                // Set the width bits
1038
1039     if(PSXDisplay.InterlacedNew)
1040      {
1041       if(!PSXDisplay.Interlaced)
1042        {
1043         PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1044         PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1045        }
1046       lGPUstatusRet|=GPUSTATUS_INTERLACED;
1047      }
1048     else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1049
1050     if (PSXDisplay.PAL)
1051          lGPUstatusRet|=GPUSTATUS_PAL;
1052     else lGPUstatusRet&=~GPUSTATUS_PAL;
1053
1054     if (PSXDisplay.Double==2)
1055          lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1056     else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1057
1058     if (PSXDisplay.RGB24New)
1059          lGPUstatusRet|=GPUSTATUS_RGB24;
1060     else lGPUstatusRet&=~GPUSTATUS_RGB24;
1061
1062     updateDisplayIfChanged();
1063
1064     return;
1065    //--------------------------------------------------//
1066    // ask about GPU version and other stuff
1067    case 0x10: 
1068
1069     gdata&=0xff;
1070
1071     switch(gdata) 
1072      {
1073       case 0x02:
1074        lGPUdataRet=lGPUInfoVals[INFO_TW];              // tw infos
1075        return;
1076       case 0x03:
1077        lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART];       // draw start
1078        return;
1079       case 0x04:
1080        lGPUdataRet=lGPUInfoVals[INFO_DRAWEND];         // draw end
1081        return;
1082       case 0x05:
1083       case 0x06:
1084        lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF];         // draw offset
1085        return;
1086       case 0x07:
1087        if(dwGPUVersion==2)
1088             lGPUdataRet=0x01;
1089        else lGPUdataRet=0x02;                          // gpu type
1090        return;
1091       case 0x08:
1092       case 0x0F:                                       // some bios addr?
1093        lGPUdataRet=0xBFC03720;
1094        return;
1095      }
1096     return;
1097    //--------------------------------------------------//
1098   }   
1099 }
1100
1101 ////////////////////////////////////////////////////////////////////////
1102 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1103 ////////////////////////////////////////////////////////////////////////
1104
1105 __inline void FinishedVRAMWrite(void)
1106 {
1107 /*
1108 // NEWX
1109  if(!PSXDisplay.Interlaced && UseFrameSkip)            // stupid frame skipping
1110   {
1111    VRAMWrite.Width +=VRAMWrite.x;
1112    VRAMWrite.Height+=VRAMWrite.y;
1113    if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1114       VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1115       VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1116       VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1117     updateDisplay();
1118   }
1119 */
1120
1121  // Set register to NORMAL operation
1122  DataWriteMode = DR_NORMAL;
1123  // Reset transfer values, to prevent mis-transfer of data
1124  VRAMWrite.x = 0;
1125  VRAMWrite.y = 0;
1126  VRAMWrite.Width = 0;
1127  VRAMWrite.Height = 0;
1128  VRAMWrite.ColsRemaining = 0;
1129  VRAMWrite.RowsRemaining = 0;
1130 }
1131
1132 __inline void FinishedVRAMRead(void)
1133 {
1134  // Set register to NORMAL operation
1135  DataReadMode = DR_NORMAL;
1136  // Reset transfer values, to prevent mis-transfer of data
1137  VRAMRead.x = 0;
1138  VRAMRead.y = 0;
1139  VRAMRead.Width = 0;
1140  VRAMRead.Height = 0;
1141  VRAMRead.ColsRemaining = 0;
1142  VRAMRead.RowsRemaining = 0;
1143
1144  // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1145  lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1146 }
1147
1148 ////////////////////////////////////////////////////////////////////////
1149 // core read from vram
1150 ////////////////////////////////////////////////////////////////////////
1151
1152 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1153 {
1154  int i;
1155
1156  if(DataReadMode!=DR_VRAMTRANSFER) return;
1157
1158  GPUIsBusy;
1159
1160  // adjust read ptr, if necessary
1161  while(VRAMRead.ImagePtr>=psxVuw_eom)
1162   VRAMRead.ImagePtr-=iGPUHeight*1024;
1163  while(VRAMRead.ImagePtr<psxVuw)
1164   VRAMRead.ImagePtr+=iGPUHeight*1024;
1165
1166  for(i=0;i<iSize;i++)
1167   {
1168    // do 2 seperate 16bit reads for compatibility (wrap issues)
1169    if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1170     {
1171      // lower 16 bit
1172      lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1173
1174      VRAMRead.ImagePtr++;
1175      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1176      VRAMRead.RowsRemaining --;
1177
1178      if(VRAMRead.RowsRemaining<=0)
1179       {
1180        VRAMRead.RowsRemaining = VRAMRead.Width;
1181        VRAMRead.ColsRemaining--;
1182        VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1183        if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1184       }
1185
1186      // higher 16 bit (always, even if it's an odd width)
1187      lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1188      PUTLE32(pMem, lGPUdataRet); pMem++;
1189
1190      if(VRAMRead.ColsRemaining <= 0)
1191       {FinishedVRAMRead();goto ENDREAD;}
1192
1193      VRAMRead.ImagePtr++;
1194      if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1195      VRAMRead.RowsRemaining--;
1196      if(VRAMRead.RowsRemaining<=0)
1197       {
1198        VRAMRead.RowsRemaining = VRAMRead.Width;
1199        VRAMRead.ColsRemaining--;
1200        VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1201        if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1202       }
1203      if(VRAMRead.ColsRemaining <= 0)
1204       {FinishedVRAMRead();goto ENDREAD;}
1205     }
1206    else {FinishedVRAMRead();goto ENDREAD;}
1207   }
1208
1209 ENDREAD:
1210  GPUIsIdle;
1211 }
1212
1213
1214 ////////////////////////////////////////////////////////////////////////
1215
1216 uint32_t CALLBACK GPUreadData(void)
1217 {
1218  uint32_t l;
1219  GPUreadDataMem(&l,1);
1220  return lGPUdataRet;
1221 }
1222
1223 ////////////////////////////////////////////////////////////////////////
1224 // processes data send to GPU data register
1225 // extra table entries for fixing polyline troubles
1226 ////////////////////////////////////////////////////////////////////////
1227
1228 const unsigned char primTableCX[256] =
1229 {
1230     // 00
1231     0,0,3,0,0,0,0,0,
1232     // 08
1233     0,0,0,0,0,0,0,0,
1234     // 10
1235     0,0,0,0,0,0,0,0,
1236     // 18
1237     0,0,0,0,0,0,0,0,
1238     // 20
1239     4,4,4,4,7,7,7,7,
1240     // 28
1241     5,5,5,5,9,9,9,9,
1242     // 30
1243     6,6,6,6,9,9,9,9,
1244     // 38
1245     8,8,8,8,12,12,12,12,
1246     // 40
1247     3,3,3,3,0,0,0,0,
1248     // 48
1249 //  5,5,5,5,6,6,6,6,    // FLINE
1250     254,254,254,254,254,254,254,254,
1251     // 50
1252     4,4,4,4,0,0,0,0,
1253     // 58
1254 //  7,7,7,7,9,9,9,9,    // GLINE
1255     255,255,255,255,255,255,255,255,
1256     // 60
1257     3,3,3,3,4,4,4,4,    
1258     // 68
1259     2,2,2,2,3,3,3,3,    // 3=SPRITE1???
1260     // 70
1261     2,2,2,2,3,3,3,3,
1262     // 78
1263     2,2,2,2,3,3,3,3,
1264     // 80
1265     4,0,0,0,0,0,0,0,
1266     // 88
1267     0,0,0,0,0,0,0,0,
1268     // 90
1269     0,0,0,0,0,0,0,0,
1270     // 98
1271     0,0,0,0,0,0,0,0,
1272     // a0
1273     3,0,0,0,0,0,0,0,
1274     // a8
1275     0,0,0,0,0,0,0,0,
1276     // b0
1277     0,0,0,0,0,0,0,0,
1278     // b8
1279     0,0,0,0,0,0,0,0,
1280     // c0
1281     3,0,0,0,0,0,0,0,
1282     // c8
1283     0,0,0,0,0,0,0,0,
1284     // d0
1285     0,0,0,0,0,0,0,0,
1286     // d8
1287     0,0,0,0,0,0,0,0,
1288     // e0
1289     0,1,1,1,1,1,1,0,
1290     // e8
1291     0,0,0,0,0,0,0,0,
1292     // f0
1293     0,0,0,0,0,0,0,0,
1294     // f8
1295     0,0,0,0,0,0,0,0
1296 };
1297
1298 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1299 {
1300  unsigned char command;
1301  uint32_t gdata=0;
1302  int i=0;
1303  GPUIsBusy;
1304  GPUIsNotReadyForCommands;
1305
1306 STARTVRAM:
1307
1308  if(DataWriteMode==DR_VRAMTRANSFER)
1309   {
1310    BOOL bFinished=FALSE;
1311
1312    // make sure we are in vram
1313    while(VRAMWrite.ImagePtr>=psxVuw_eom)
1314     VRAMWrite.ImagePtr-=iGPUHeight*1024;
1315    while(VRAMWrite.ImagePtr<psxVuw)
1316     VRAMWrite.ImagePtr+=iGPUHeight*1024;
1317
1318    // now do the loop
1319    while(VRAMWrite.ColsRemaining>0)
1320     {
1321      while(VRAMWrite.RowsRemaining>0)
1322       {
1323        if(i>=iSize) {goto ENDVRAM;}
1324        i++;
1325
1326        gdata=GETLE32(pMem); pMem++;
1327
1328        PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1329        if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1330        VRAMWrite.RowsRemaining --;
1331
1332        if(VRAMWrite.RowsRemaining <= 0)
1333         {
1334          VRAMWrite.ColsRemaining--;
1335          if (VRAMWrite.ColsRemaining <= 0)             // last pixel is odd width
1336           {
1337            gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1338            FinishedVRAMWrite();
1339            bDoVSyncUpdate=TRUE;
1340            goto ENDVRAM;
1341           }
1342          VRAMWrite.RowsRemaining = VRAMWrite.Width;
1343          VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1344         }
1345
1346        PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1347        if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1348        VRAMWrite.RowsRemaining --;
1349       }
1350
1351      VRAMWrite.RowsRemaining = VRAMWrite.Width;
1352      VRAMWrite.ColsRemaining--;
1353      VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1354      bFinished=TRUE;
1355     }
1356
1357    FinishedVRAMWrite();
1358    if(bFinished) bDoVSyncUpdate=TRUE;
1359   }
1360
1361 ENDVRAM:
1362
1363  if(DataWriteMode==DR_NORMAL)
1364   {
1365    void (* *primFunc)(unsigned char *);
1366    if(bSkipNextFrame) primFunc=primTableSkip;
1367    else               primFunc=primTableJ;
1368
1369    for(;i<iSize;)
1370     {
1371      if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1372
1373      gdata=GETLE32(pMem); pMem++; i++;
1374  
1375      if(gpuDataC == 0)
1376       {
1377        command = (unsigned char)((gdata>>24) & 0xff);
1378  
1379 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1380
1381        if(primTableCX[command])
1382         {
1383          gpuDataC = primTableCX[command];
1384          gpuCommand = command;
1385          PUTLE32(&gpuDataM[0], gdata);
1386          gpuDataP = 1;
1387         }
1388        else continue;
1389       }
1390      else
1391       {
1392        PUTLE32(&gpuDataM[gpuDataP], gdata);
1393        if(gpuDataC>128)
1394         {
1395          if((gpuDataC==254 && gpuDataP>=3) ||
1396             (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1397           {
1398            if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1399             gpuDataP=gpuDataC-1;
1400           }
1401         }
1402        gpuDataP++;
1403       }
1404  
1405      if(gpuDataP == gpuDataC)
1406       {
1407        gpuDataC=gpuDataP=0;
1408        primFunc[gpuCommand]((unsigned char *)gpuDataM);
1409        if(dwEmuFixes&0x0001 || dwActFixes&0x0400)      // hack for emulating "gpu busy" in some games
1410         iFakePrimBusy=4;\r      }
1411     } 
1412   }
1413
1414  lGPUdataRet=gdata;
1415
1416  GPUIsReadyForCommands;
1417  GPUIsIdle;                
1418 }
1419
1420 ////////////////////////////////////////////////////////////////////////
1421
1422 void CALLBACK GPUwriteData(uint32_t gdata)
1423 {
1424  PUTLE32(&gdata, gdata);
1425  GPUwriteDataMem(&gdata,1);
1426 }
1427
1428 ////////////////////////////////////////////////////////////////////////
1429 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1430 ////////////////////////////////////////////////////////////////////////
1431
1432 void CALLBACK GPUsetMode(unsigned long gdata)
1433 {
1434 // Peops does nothing here...
1435 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1436 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1437 }
1438
1439 long CALLBACK GPUgetMode(void)
1440 {
1441  long iT=0;
1442
1443  if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1444  if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1445  return iT;
1446 }
1447
1448 ////////////////////////////////////////////////////////////////////////
1449 // call config dlg
1450 ////////////////////////////////////////////////////////////////////////
1451
1452 long CALLBACK GPUconfigure(void)
1453 {
1454  SoftDlgProc();
1455
1456  return 0;
1457 }
1458
1459 ////////////////////////////////////////////////////////////////////////
1460 // sets all kind of act fixes
1461 ////////////////////////////////////////////////////////////////////////
1462
1463 void SetFixes(void)
1464  {
1465   if(dwActFixes&0x02) sDispWidths[4]=384;
1466   else                sDispWidths[4]=368;
1467  }
1468
1469 ////////////////////////////////////////////////////////////////////////
1470 // process gpu commands
1471 ////////////////////////////////////////////////////////////////////////
1472
1473 unsigned long lUsedAddr[3];
1474
1475 __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1476 {
1477  if(laddr==lUsedAddr[1]) return TRUE;
1478  if(laddr==lUsedAddr[2]) return TRUE;
1479
1480  if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1481  else                   lUsedAddr[2]=laddr;
1482  lUsedAddr[0]=laddr;
1483  return FALSE;
1484 }
1485
1486 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1487 {
1488  uint32_t dmaMem;
1489  unsigned char * baseAddrB;
1490  short count;unsigned int DMACommandCounter = 0;
1491
1492  GPUIsBusy;
1493
1494  lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1495
1496  baseAddrB = (unsigned char*) baseAddrL;
1497
1498  do
1499   {
1500    if(iGPUHeight==512) addr&=0x1FFFFC;
1501    if(DMACommandCounter++ > 2000000) break;
1502    if(CheckForEndlessLoop(addr)) break;
1503
1504    count = baseAddrB[addr+3];
1505
1506    dmaMem=addr+4;
1507
1508    if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1509
1510    addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1511   }
1512  while (addr != 0xffffff);
1513
1514  GPUIsIdle;
1515
1516  return 0;
1517 }
1518
1519 ////////////////////////////////////////////////////////////////////////
1520 // show about dlg
1521 ////////////////////////////////////////////////////////////////////////
1522
1523
1524 void CALLBACK GPUabout(void)                           // ABOUT
1525 {
1526  AboutDlgProc();
1527  return;
1528 }
1529
1530 ////////////////////////////////////////////////////////////////////////
1531 // We are ever fine ;)
1532 ////////////////////////////////////////////////////////////////////////
1533
1534 long CALLBACK GPUtest(void)
1535 {
1536  // if test fails this function should return negative value for error (unable to continue)
1537  // and positive value for warning (can continue but output might be crappy)
1538  return 0;
1539 }
1540
1541 ////////////////////////////////////////////////////////////////////////
1542 // Freeze
1543 ////////////////////////////////////////////////////////////////////////
1544
1545 typedef struct GPUFREEZETAG
1546 {
1547  uint32_t ulFreezeVersion;      // should be always 1 for now (set by main emu)
1548  uint32_t ulStatus;             // current gpu status
1549  uint32_t ulControl[256];       // latest control register values
1550  unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1551 } GPUFreeze_t;
1552
1553 ////////////////////////////////////////////////////////////////////////
1554
1555 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1556 {
1557  //----------------------------------------------------//
1558  if(ulGetFreezeData==2)                                // 2: info, which save slot is selected? (just for display)
1559   {
1560    long lSlotNum=*((long *)pF);
1561    if(lSlotNum<0) return 0;
1562    if(lSlotNum>8) return 0;
1563    lSelectedSlot=lSlotNum+1;
1564    BuildDispMenu(0);
1565    return 1;
1566   }
1567  //----------------------------------------------------//
1568  if(!pF)                    return 0;                  // some checks
1569  if(pF->ulFreezeVersion!=1) return 0;
1570
1571  if(ulGetFreezeData==1)                                // 1: get data
1572   {
1573    pF->ulStatus=lGPUstatusRet;
1574    memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1575    memcpy(pF->psxVRam,  psxVub,         1024*iGPUHeight*2);
1576
1577    return 1;
1578   }
1579
1580  if(ulGetFreezeData!=0) return 0;                      // 0: set data
1581
1582  lGPUstatusRet=pF->ulStatus;
1583  memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1584  memcpy(psxVub,         pF->psxVRam,  1024*iGPUHeight*2);
1585
1586 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1587
1588  GPUwriteStatus(ulStatusControl[0]);
1589  GPUwriteStatus(ulStatusControl[1]);
1590  GPUwriteStatus(ulStatusControl[2]);
1591  GPUwriteStatus(ulStatusControl[3]);
1592  GPUwriteStatus(ulStatusControl[8]);                   // try to repair things
1593  GPUwriteStatus(ulStatusControl[6]);
1594  GPUwriteStatus(ulStatusControl[7]);
1595  GPUwriteStatus(ulStatusControl[5]);
1596  GPUwriteStatus(ulStatusControl[4]);
1597
1598  return 1;
1599 }
1600
1601 ////////////////////////////////////////////////////////////////////////
1602 ////////////////////////////////////////////////////////////////////////
1603 ////////////////////////////////////////////////////////////////////////
1604 ////////////////////////////////////////////////////////////////////////
1605 ////////////////////////////////////////////////////////////////////////
1606 ////////////////////////////////////////////////////////////////////////
1607
1608 ////////////////////////////////////////////////////////////////////////
1609 // SAVE STATE DISPLAY STUFF
1610 ////////////////////////////////////////////////////////////////////////
1611
1612 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1613 // 00 = black
1614 // 01 = white
1615 // 10 = red
1616 // 11 = transparent
1617
1618 unsigned char cFont[10][120]=
1619 {
1620 // 0
1621 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1622  0x80,0x00,0x00,0x00,0x00,0x00,
1623  0x80,0x00,0x00,0x00,0x00,0x00,
1624  0x80,0x00,0x00,0x00,0x00,0x00,
1625  0x80,0x00,0x00,0x00,0x00,0x00,
1626  0x80,0x00,0x05,0x54,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,0x14,0x05,0x00,0x00,
1634  0x80,0x00,0x14,0x05,0x00,0x00,
1635  0x80,0x00,0x05,0x54,0x00,0x00,
1636  0x80,0x00,0x00,0x00,0x00,0x00,
1637  0x80,0x00,0x00,0x00,0x00,0x00,
1638  0x80,0x00,0x00,0x00,0x00,0x00,
1639  0x80,0x00,0x00,0x00,0x00,0x00,
1640  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1641 },
1642 // 1
1643 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1644  0x80,0x00,0x00,0x00,0x00,0x00,
1645  0x80,0x00,0x00,0x00,0x00,0x00,
1646  0x80,0x00,0x00,0x00,0x00,0x00,
1647  0x80,0x00,0x00,0x00,0x00,0x00,
1648  0x80,0x00,0x00,0x50,0x00,0x00,
1649  0x80,0x00,0x05,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,0x00,0x50,0x00,0x00,
1656  0x80,0x00,0x00,0x50,0x00,0x00,
1657  0x80,0x00,0x05,0x55,0x00,0x00,
1658  0x80,0x00,0x00,0x00,0x00,0x00,
1659  0x80,0x00,0x00,0x00,0x00,0x00,
1660  0x80,0x00,0x00,0x00,0x00,0x00,
1661  0x80,0x00,0x00,0x00,0x00,0x00,
1662  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1663 },
1664 // 2
1665 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1666  0x80,0x00,0x00,0x00,0x00,0x00,
1667  0x80,0x00,0x00,0x00,0x00,0x00,
1668  0x80,0x00,0x00,0x00,0x00,0x00,
1669  0x80,0x00,0x00,0x00,0x00,0x00,
1670  0x80,0x00,0x05,0x54,0x00,0x00,
1671  0x80,0x00,0x14,0x05,0x00,0x00,
1672  0x80,0x00,0x00,0x05,0x00,0x00,
1673  0x80,0x00,0x00,0x05,0x00,0x00,
1674  0x80,0x00,0x00,0x14,0x00,0x00,
1675  0x80,0x00,0x00,0x50,0x00,0x00,
1676  0x80,0x00,0x01,0x40,0x00,0x00,
1677  0x80,0x00,0x05,0x00,0x00,0x00,
1678  0x80,0x00,0x14,0x00,0x00,0x00,
1679  0x80,0x00,0x15,0x55,0x00,0x00,
1680  0x80,0x00,0x00,0x00,0x00,0x00,
1681  0x80,0x00,0x00,0x00,0x00,0x00,
1682  0x80,0x00,0x00,0x00,0x00,0x00,
1683  0x80,0x00,0x00,0x00,0x00,0x00,
1684  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1685 },
1686 // 3
1687 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1688  0x80,0x00,0x00,0x00,0x00,0x00,
1689  0x80,0x00,0x00,0x00,0x00,0x00,
1690  0x80,0x00,0x00,0x00,0x00,0x00,
1691  0x80,0x00,0x00,0x00,0x00,0x00,
1692  0x80,0x00,0x05,0x54,0x00,0x00,
1693  0x80,0x00,0x14,0x05,0x00,0x00,
1694  0x80,0x00,0x00,0x05,0x00,0x00,
1695  0x80,0x00,0x00,0x05,0x00,0x00,
1696  0x80,0x00,0x01,0x54,0x00,0x00,
1697  0x80,0x00,0x00,0x05,0x00,0x00,
1698  0x80,0x00,0x00,0x05,0x00,0x00,
1699  0x80,0x00,0x00,0x05,0x00,0x00,
1700  0x80,0x00,0x14,0x05,0x00,0x00,
1701  0x80,0x00,0x05,0x54,0x00,0x00,
1702  0x80,0x00,0x00,0x00,0x00,0x00,
1703  0x80,0x00,0x00,0x00,0x00,0x00,
1704  0x80,0x00,0x00,0x00,0x00,0x00,
1705  0x80,0x00,0x00,0x00,0x00,0x00,
1706  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1707 },
1708 // 4
1709 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1710  0x80,0x00,0x00,0x00,0x00,0x00,
1711  0x80,0x00,0x00,0x00,0x00,0x00,
1712  0x80,0x00,0x00,0x00,0x00,0x00,
1713  0x80,0x00,0x00,0x00,0x00,0x00,
1714  0x80,0x00,0x00,0x14,0x00,0x00,
1715  0x80,0x00,0x00,0x54,0x00,0x00,
1716  0x80,0x00,0x01,0x54,0x00,0x00,
1717  0x80,0x00,0x01,0x54,0x00,0x00,
1718  0x80,0x00,0x05,0x14,0x00,0x00,
1719  0x80,0x00,0x14,0x14,0x00,0x00,
1720  0x80,0x00,0x15,0x55,0x00,0x00,
1721  0x80,0x00,0x00,0x14,0x00,0x00,
1722  0x80,0x00,0x00,0x14,0x00,0x00,
1723  0x80,0x00,0x00,0x55,0x00,0x00,
1724  0x80,0x00,0x00,0x00,0x00,0x00,
1725  0x80,0x00,0x00,0x00,0x00,0x00,
1726  0x80,0x00,0x00,0x00,0x00,0x00,
1727  0x80,0x00,0x00,0x00,0x00,0x00,
1728  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1729 },
1730 // 5
1731 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1732  0x80,0x00,0x00,0x00,0x00,0x00,
1733  0x80,0x00,0x00,0x00,0x00,0x00,
1734  0x80,0x00,0x00,0x00,0x00,0x00,
1735  0x80,0x00,0x00,0x00,0x00,0x00,
1736  0x80,0x00,0x15,0x55,0x00,0x00,
1737  0x80,0x00,0x14,0x00,0x00,0x00,
1738  0x80,0x00,0x14,0x00,0x00,0x00,
1739  0x80,0x00,0x14,0x00,0x00,0x00,
1740  0x80,0x00,0x15,0x54,0x00,0x00,
1741  0x80,0x00,0x00,0x05,0x00,0x00,
1742  0x80,0x00,0x00,0x05,0x00,0x00,
1743  0x80,0x00,0x00,0x05,0x00,0x00,
1744  0x80,0x00,0x14,0x05,0x00,0x00,
1745  0x80,0x00,0x05,0x54,0x00,0x00,
1746  0x80,0x00,0x00,0x00,0x00,0x00,
1747  0x80,0x00,0x00,0x00,0x00,0x00,
1748  0x80,0x00,0x00,0x00,0x00,0x00,
1749  0x80,0x00,0x00,0x00,0x00,0x00,
1750  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1751 },
1752 // 6
1753 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1754  0x80,0x00,0x00,0x00,0x00,0x00,
1755  0x80,0x00,0x00,0x00,0x00,0x00,
1756  0x80,0x00,0x00,0x00,0x00,0x00,
1757  0x80,0x00,0x00,0x00,0x00,0x00,
1758  0x80,0x00,0x01,0x54,0x00,0x00,
1759  0x80,0x00,0x05,0x00,0x00,0x00,
1760  0x80,0x00,0x14,0x00,0x00,0x00,
1761  0x80,0x00,0x14,0x00,0x00,0x00,
1762  0x80,0x00,0x15,0x54,0x00,0x00,
1763  0x80,0x00,0x15,0x05,0x00,0x00,
1764  0x80,0x00,0x14,0x05,0x00,0x00,
1765  0x80,0x00,0x14,0x05,0x00,0x00,
1766  0x80,0x00,0x14,0x05,0x00,0x00,
1767  0x80,0x00,0x05,0x54,0x00,0x00,
1768  0x80,0x00,0x00,0x00,0x00,0x00,
1769  0x80,0x00,0x00,0x00,0x00,0x00,
1770  0x80,0x00,0x00,0x00,0x00,0x00,
1771  0x80,0x00,0x00,0x00,0x00,0x00,
1772  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1773 },
1774 // 7
1775 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1776  0x80,0x00,0x00,0x00,0x00,0x00,
1777  0x80,0x00,0x00,0x00,0x00,0x00,
1778  0x80,0x00,0x00,0x00,0x00,0x00,
1779  0x80,0x00,0x00,0x00,0x00,0x00,
1780  0x80,0x00,0x15,0x55,0x00,0x00,
1781  0x80,0x00,0x14,0x05,0x00,0x00,
1782  0x80,0x00,0x00,0x14,0x00,0x00,
1783  0x80,0x00,0x00,0x14,0x00,0x00,
1784  0x80,0x00,0x00,0x50,0x00,0x00,
1785  0x80,0x00,0x00,0x50,0x00,0x00,
1786  0x80,0x00,0x01,0x40,0x00,0x00,
1787  0x80,0x00,0x01,0x40,0x00,0x00,
1788  0x80,0x00,0x05,0x00,0x00,0x00,
1789  0x80,0x00,0x05,0x00,0x00,0x00,
1790  0x80,0x00,0x00,0x00,0x00,0x00,
1791  0x80,0x00,0x00,0x00,0x00,0x00,
1792  0x80,0x00,0x00,0x00,0x00,0x00,
1793  0x80,0x00,0x00,0x00,0x00,0x00,
1794  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1795 },
1796 // 8
1797 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1798  0x80,0x00,0x00,0x00,0x00,0x00,
1799  0x80,0x00,0x00,0x00,0x00,0x00,
1800  0x80,0x00,0x00,0x00,0x00,0x00,
1801  0x80,0x00,0x00,0x00,0x00,0x00,
1802  0x80,0x00,0x05,0x54,0x00,0x00,
1803  0x80,0x00,0x14,0x05,0x00,0x00,
1804  0x80,0x00,0x14,0x05,0x00,0x00,
1805  0x80,0x00,0x14,0x05,0x00,0x00,
1806  0x80,0x00,0x05,0x54,0x00,0x00,
1807  0x80,0x00,0x14,0x05,0x00,0x00,
1808  0x80,0x00,0x14,0x05,0x00,0x00,
1809  0x80,0x00,0x14,0x05,0x00,0x00,
1810  0x80,0x00,0x14,0x05,0x00,0x00,
1811  0x80,0x00,0x05,0x54,0x00,0x00,
1812  0x80,0x00,0x00,0x00,0x00,0x00,
1813  0x80,0x00,0x00,0x00,0x00,0x00,
1814  0x80,0x00,0x00,0x00,0x00,0x00,
1815  0x80,0x00,0x00,0x00,0x00,0x00,
1816  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1817 },
1818 // 9
1819 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1820  0x80,0x00,0x00,0x00,0x00,0x00,
1821  0x80,0x00,0x00,0x00,0x00,0x00,
1822  0x80,0x00,0x00,0x00,0x00,0x00,
1823  0x80,0x00,0x00,0x00,0x00,0x00,
1824  0x80,0x00,0x05,0x54,0x00,0x00,
1825  0x80,0x00,0x14,0x05,0x00,0x00,
1826  0x80,0x00,0x14,0x05,0x00,0x00,
1827  0x80,0x00,0x14,0x05,0x00,0x00,
1828  0x80,0x00,0x14,0x15,0x00,0x00,
1829  0x80,0x00,0x05,0x55,0x00,0x00,
1830  0x80,0x00,0x00,0x05,0x00,0x00,
1831  0x80,0x00,0x00,0x05,0x00,0x00,
1832  0x80,0x00,0x00,0x14,0x00,0x00,
1833  0x80,0x00,0x05,0x50,0x00,0x00,
1834  0x80,0x00,0x00,0x00,0x00,0x00,
1835  0x80,0x00,0x00,0x00,0x00,0x00,
1836  0x80,0x00,0x00,0x00,0x00,0x00,
1837  0x80,0x00,0x00,0x00,0x00,0x00,
1838  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1839 }
1840 };
1841
1842 ////////////////////////////////////////////////////////////////////////
1843
1844 void PaintPicDot(unsigned char * p,unsigned char c)
1845 {
1846
1847  if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}        // black
1848  if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}        // white
1849  if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}        // red
1850                                                        // transparent
1851 }
1852
1853 ////////////////////////////////////////////////////////////////////////
1854 // the main emu allocs 128x96x3 bytes, and passes a ptr
1855 // to it in pMem... the plugin has to fill it with
1856 // 8-8-8 bit BGR screen data (Win 24 bit BMP format 
1857 // without header). 
1858 // Beware: the func can be called at any time,
1859 // so you have to use the frontbuffer to get a fully
1860 // rendered picture
1861
1862 // LINUX version:
1863
1864 extern char * Xpixels;
1865
1866 void GPUgetScreenPic(unsigned char * pMem)
1867 {
1868 /*
1869  unsigned short c;unsigned char * pf;int x,y;
1870
1871  float XS=(float)iResX/128;
1872  float YS=(float)iResY/96;
1873
1874  pf=pMem;
1875  memset(pMem, 0, 128*96*3);
1876
1877  if(Xpixels)
1878   {
1879    unsigned char * ps=(unsigned char *)Xpixels;
1880     {
1881      long lPitch=iResX<<2;
1882      uint32_t sx;
1883
1884      for(y=0;y<96;y++)
1885       {
1886        for(x=0;x<128;x++)
1887         {
1888          sx=*((uint32_t *)((ps)+
1889               (((int)((float)y*YS))*lPitch)+
1890                ((int)((float)x*XS))*4));
1891          *(pf+0)=(sx&0xff);
1892          *(pf+1)=(sx&0xff00)>>8;
1893          *(pf+2)=(sx&0xff0000)>>16;
1894          pf+=3;
1895         }
1896       }
1897     }
1898   }
1899
1900
1901  /////////////////////////////////////////////////////////////////////
1902  // generic number/border painter
1903
1904  pf=pMem+(103*3);                                      // offset to number rect
1905
1906  for(y=0;y<20;y++)                                     // loop the number rect pixel
1907   {
1908    for(x=0;x<6;x++)
1909     {
1910      c=cFont[lSelectedSlot][x+y*6];                    // get 4 char dot infos at once (number depends on selected slot)
1911      PaintPicDot(pf,(c&0xc0)>>6);pf+=3;                // paint the dots into the rect
1912      PaintPicDot(pf,(c&0x30)>>4);pf+=3;
1913      PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
1914      PaintPicDot(pf,(c&0x03));   pf+=3;
1915     }
1916    pf+=104*3;                                          // next rect y line
1917   }
1918
1919  pf=pMem;                                              // ptr to first pos in 128x96 pic
1920  for(x=0;x<128;x++)                                    // loop top/bottom line
1921   {
1922    *(pf+(95*128*3))=0x00;*pf++=0x00;
1923    *(pf+(95*128*3))=0x00;*pf++=0x00;                   // paint it red
1924    *(pf+(95*128*3))=0xff;*pf++=0xff;
1925   }
1926  pf=pMem;                                              // ptr to first pos
1927  for(y=0;y<96;y++)                                     // loop left/right line
1928   {
1929    *(pf+(127*3))=0x00;*pf++=0x00;
1930    *(pf+(127*3))=0x00;*pf++=0x00;                      // paint it red
1931    *(pf+(127*3))=0xff;*pf++=0xff;
1932    pf+=127*3;                                          // offset to next line
1933   }
1934 */
1935 }
1936
1937
1938 ////////////////////////////////////////////////////////////////////////
1939 // func will be called with 128x96x3 BGR data.
1940 // the plugin has to store the data and display
1941 // it in the upper right corner.
1942 // If the func is called with a NULL ptr, you can
1943 // release your picture data and stop displaying
1944 // the screen pic
1945
1946 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
1947 {
1948  DestroyPic();                                         // destroy old pic data
1949  if(pMem==0) return;                                   // done
1950  CreatePic(pMem);                                      // create new pic... don't free pMem or something like that... just read from it
1951 }
1952
1953 void CALLBACK GPUsetfix(uint32_t dwFixBits)
1954 {
1955  dwEmuFixes=dwFixBits;
1956 }