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