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