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