3624 lines
101 KiB
C
Executable File
3624 lines
101 KiB
C
Executable File
/***************************************************************************
|
|
gpu.c - description
|
|
-------------------
|
|
begin : Sun Mar 08 2009
|
|
copyright : (C) 1999-2009 by Pete Bernert
|
|
email : BlackDove@addcom.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. See also the license.txt file for *
|
|
* additional informations. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
// !!! enable this, if Linux XF86VidMode is not supported:
|
|
//#define NOVMODE
|
|
|
|
#include "stdafx.h"
|
|
|
|
#if defined (_MACGL)
|
|
#include "drawgl.h"
|
|
#elif !defined(_MACGL) && !defined(_WINDOWS)
|
|
|
|
#include "config.h"
|
|
|
|
#ifndef NOVMODE
|
|
#include <X11/extensions/xf86vmode.h>
|
|
static XF86VidModeModeInfo **modes=0;
|
|
static int iOldMode=0;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#define _IN_GPU
|
|
|
|
#include "externals.h"
|
|
#include "gpu.h"
|
|
#include "draw.h"
|
|
#include "cfg.h"
|
|
#include "prim.h"
|
|
#include "psemu_plugin_defs.h"
|
|
#include "texture.h"
|
|
#include "menu.h"
|
|
#include "fps.h"
|
|
#include "key.h"
|
|
#include "gte_accuracy.h"
|
|
#include "pgxp_gpu.h"
|
|
#ifdef _WINDOWS
|
|
#include "resource.h"
|
|
#include "ssave.h"
|
|
#endif
|
|
#ifdef ENABLE_NLS
|
|
#include <libintl.h>
|
|
#include <locale.h>
|
|
#define _(x) gettext(x)
|
|
#define N_(x) (x)
|
|
#elif defined(_MACOSX)
|
|
#ifdef PCSXRCORE
|
|
__private_extern char* Pcsxr_locale_text(char* toloc);
|
|
#define _(String) Pcsxr_locale_text(String)
|
|
#define N_(String) String
|
|
#else
|
|
#ifndef PCSXRPLUG
|
|
#warning please define the plug being built to use Mac OS X localization!
|
|
#define _(msgid) msgid
|
|
#define N_(msgid) msgid
|
|
#else
|
|
//Kludge to get the preprocessor to accept PCSXRPLUG as a variable.
|
|
#define PLUGLOC_x(x,y) x ## y
|
|
#define PLUGLOC_y(x,y) PLUGLOC_x(x,y)
|
|
#define PLUGLOC PLUGLOC_y(PCSXRPLUG,_locale_text)
|
|
__private_extern char* PLUGLOC(char* toloc);
|
|
#define _(String) PLUGLOC(String)
|
|
#define N_(String) String
|
|
#endif
|
|
#endif
|
|
#else
|
|
#define _(x) (x)
|
|
#define N_(x) (x)
|
|
#endif
|
|
|
|
#ifdef _MACGL
|
|
#include "drawgl.h"
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// PPDK developer must change libraryName field and can change revision and build
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
const unsigned char version = 1; // do not touch - library for PSEmu 1.x
|
|
const unsigned char revision = 1;
|
|
const unsigned char build = 78;
|
|
|
|
static char *libraryName = N_("OpenGL Driver");
|
|
|
|
static char *PluginAuthor = N_("Pete Bernert");
|
|
static char *libraryInfo = N_("Based on P.E.Op.S. MesaGL Driver V1.78\nCoded by Pete Bernert\n");
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// memory image of the PSX vram
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned char *psxVSecure;
|
|
unsigned char *psxVub;
|
|
signed char *psxVsb;
|
|
unsigned short *psxVuw;
|
|
unsigned short *psxVuw_eom;
|
|
signed short *psxVsw;
|
|
uint32_t *psxVul;
|
|
signed int *psxVsl;
|
|
|
|
// macro for easy access to packet information
|
|
#define GPUCOMMAND(x) ((x>>24) & 0xff)
|
|
|
|
GLfloat gl_z=0.0f;
|
|
BOOL bNeedInterlaceUpdate=FALSE;
|
|
BOOL bNeedRGB24Update=FALSE;
|
|
BOOL bChangeWinMode=FALSE;
|
|
|
|
#ifdef _WINDOWS
|
|
extern HGLRC GLCONTEXT;
|
|
#endif
|
|
|
|
uint32_t ulStatusControl[256];
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// global GPU vars
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static int GPUdataRet;
|
|
int lGPUstatusRet;
|
|
char szDispBuf[64];
|
|
|
|
uint32_t dwGPUVersion = 0;
|
|
int iGPUHeight = 512;
|
|
int iGPUHeightMask = 511;
|
|
int GlobalTextIL = 0;
|
|
int iTileCheat = 0;
|
|
|
|
static uint32_t gpuDataM[256];
|
|
static unsigned char gpuCommand = 0;
|
|
static int gpuDataC = 0;
|
|
static int gpuDataP = 0;
|
|
|
|
VRAMLoad_t VRAMWrite;
|
|
VRAMLoad_t VRAMRead;
|
|
int iDataWriteMode;
|
|
int iDataReadMode;
|
|
|
|
int lClearOnSwap;
|
|
int lClearOnSwapColor;
|
|
BOOL bSkipNextFrame = FALSE;
|
|
int iColDepth;
|
|
BOOL bChangeRes;
|
|
BOOL bWindowMode;
|
|
int iWinSize;
|
|
|
|
// possible psx display widths
|
|
short dispWidths[8] = {256,320,512,640,368,384,512,640};
|
|
|
|
PSXDisplay_t PSXDisplay;
|
|
PSXDisplay_t PreviousPSXDisplay;
|
|
TWin_t TWin;
|
|
short imageX0,imageX1;
|
|
short imageY0,imageY1;
|
|
BOOL bDisplayNotSet = TRUE;
|
|
GLuint uiScanLine=0;
|
|
int iUseScanLines=0;
|
|
float iScanlineColor[] = {0,0,0, 0.3f}; // easy on the eyes.
|
|
int lSelectedSlot=0;
|
|
unsigned char * pGfxCardScreen=0;
|
|
int iBlurBuffer=0;
|
|
int iScanBlend=0;
|
|
int iRenderFVR=0;
|
|
int iNoScreenSaver=0;
|
|
uint32_t ulGPUInfoVals[16];
|
|
int iFakePrimBusy = 0;
|
|
int iRumbleVal = 0;
|
|
int iRumbleTime = 0;
|
|
uint32_t vBlank=0;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// stuff to make this a true PDK module
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
char * CALLBACK PSEgetLibName(void)
|
|
{
|
|
return _(libraryName);
|
|
}
|
|
|
|
unsigned long CALLBACK PSEgetLibType(void)
|
|
{
|
|
return PSE_LT_GPU;
|
|
}
|
|
|
|
unsigned long CALLBACK PSEgetLibVersion(void)
|
|
{
|
|
return version<<16|revision<<8|build;
|
|
}
|
|
|
|
char * GPUgetLibInfos(void)
|
|
{
|
|
return _(libraryInfo);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// snapshot funcs (saves screen to bitmap / text infos into file)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WINDOWS
|
|
char * GetConfigInfos(HWND hW)
|
|
#else
|
|
char * GetConfigInfos(int hW)
|
|
#endif
|
|
{
|
|
#ifdef _WINDOWS
|
|
HDC hdc;HGLRC hglrc;
|
|
#endif
|
|
char szO[2][4]={"off","on "};
|
|
char szTxt[256];
|
|
char * pB=(char *)malloc(32767);
|
|
|
|
if(!pB) return NULL;
|
|
*pB=0;
|
|
//----------------------------------------------------//
|
|
sprintf(szTxt,"Plugin: %s %d.%d.%d (mod)\r\n",libraryName,version,revision,build);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"Author: %s\r\n",PluginAuthor);
|
|
strcat(pB,szTxt);
|
|
|
|
#ifdef _WINDOWS
|
|
if(hW)
|
|
{
|
|
hdc = GetDC(hW);
|
|
bSetupPixelFormat(hdc);
|
|
hglrc = wglCreateContext(hdc);
|
|
wglMakeCurrent(hdc, hglrc);
|
|
}
|
|
#endif
|
|
|
|
sprintf(szTxt,"Card vendor: %s\r\n",(char *)glGetString(GL_VENDOR));
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"GFX card: %s\r\n",(char *)glGetString(GL_RENDERER));
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"OGL version: %s\r\n\r\n",(char *)glGetString(GL_VERSION));
|
|
strcat(pB,szTxt);
|
|
//strcat(pB,(char *)glGetString(GL_EXTENSIONS));
|
|
//strcat(pB,"\r\n\r\n");
|
|
|
|
#ifdef _WINDOWS
|
|
if(hW)
|
|
{
|
|
wglMakeCurrent(NULL, NULL);
|
|
wglDeleteContext(hglrc);
|
|
ReleaseDC(hW,hdc);
|
|
}
|
|
//----------------------------------------------------//
|
|
#endif
|
|
|
|
if(hW && bWindowMode)
|
|
sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));
|
|
else
|
|
sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);
|
|
strcat(pB,szTxt);
|
|
if(bWindowMode) sprintf(szTxt,"Window mode\r\n");
|
|
else
|
|
{
|
|
sprintf(szTxt,"Fullscreen ");
|
|
strcat(pB,szTxt);
|
|
if(bChangeRes) sprintf(szTxt,"- Desktop changing [%d Bit]\r\n",iColDepth);
|
|
else sprintf(szTxt,"- NO desktop changing\r\n");
|
|
}
|
|
strcat(pB,szTxt);
|
|
|
|
if(iForceVSync>=0) sprintf(szTxt,"- V-Sync: %s\r\n",szO[iForceVSync]);
|
|
else strcpy(szTxt,"- V-Sync: Driver\r\n");
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Keep psx aspect ratio: %s\r\n\r\n",szO[bKeepRatio]);
|
|
strcat(pB,szTxt);
|
|
//----------------------------------------------------//
|
|
strcpy(szTxt,"Textures:\r\n- ");
|
|
if(iTexQuality==0) strcat(szTxt,"Default");
|
|
else if(iTexQuality==1) strcat(szTxt,"R4G4B4A4");
|
|
else if(iTexQuality==2) strcat(szTxt,"R5G5B5A1");
|
|
else if(iTexQuality==3) strcat(szTxt,"R8G8A8A8");
|
|
else if(iTexQuality==4) strcat(szTxt,"B8G8R8A8");
|
|
if(!hW && bGLExt) strcat(szTxt," (packed pixels)\r\n");
|
|
else strcat(szTxt,"\r\n");
|
|
strcat(pB,szTxt);
|
|
if(!hW)
|
|
{
|
|
sprintf(szTxt,"- Filtering: %d - edge clamping ",iFilterType);
|
|
if(iClampType==GL_TO_EDGE_CLAMP) strcat(szTxt,"supported\r\n");
|
|
else strcat(szTxt,"NOT supported\r\n");
|
|
}
|
|
else sprintf(szTxt,"- iFiltering: %d\r\n",iFilterType);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Hi-Res textures: %d\r\n",iHiResTextures);
|
|
strcat(pB,szTxt);
|
|
if(!hW)
|
|
{
|
|
sprintf(szTxt,"- Palettized tex windows: %s\r\n",szO[iUsePalTextures]);
|
|
strcat(pB,szTxt);
|
|
}
|
|
sprintf(szTxt,"- VRam size: %d MBytes",iVRamSize);
|
|
if(!hW)
|
|
sprintf(szTxt+strlen(szTxt)," - %d textures usable\r\n\r\n",iSortTexCnt);
|
|
else strcat(szTxt,"\r\n\r\n");
|
|
strcat(pB,szTxt);
|
|
//----------------------------------------------------//
|
|
sprintf(szTxt,"Framerate:\r\n- FPS limitation: %s\r\n",szO[bUseFrameLimit]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Frame skipping: %s\r\n",szO[bUseFrameSkip]);
|
|
strcat(pB,szTxt);
|
|
if(iFrameLimit==2)
|
|
strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");
|
|
else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);
|
|
strcat(pB,szTxt);
|
|
//----------------------------------------------------//
|
|
sprintf(szTxt,"Compatibility:\r\n- Offscreen drawing: %d\r\n",iOffscreenDrawing);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Framebuffer texture: %d",iFrameTexType);
|
|
if(!hW && iFrameTexType==2)
|
|
{
|
|
if(gTexFrameName) strcat(szTxt," - texture created\r\n");
|
|
else strcat(szTxt," - not used yet\r\n");
|
|
}
|
|
else strcat(szTxt,"\r\n");
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Framebuffer access: %d\r\n",iFrameReadType);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Alpha multipass: %s\r\n",szO[bOpaquePass]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Mask bit: %s\r\n",szO[iUseMask]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Advanced blending: %s",szO[bAdvancedBlend]);
|
|
if(!hW && bAdvancedBlend)
|
|
{
|
|
if(bGLBlend) strcat(szTxt," (hardware)\r\n");
|
|
else strcat(szTxt," (software)\r\n");
|
|
}
|
|
else strcat(szTxt,"\r\n");
|
|
strcat(pB,szTxt);
|
|
|
|
if(!hW)
|
|
{
|
|
strcpy(szTxt,"- Subtractive blending: ");
|
|
if(glBlendEquationEXTEx)
|
|
{
|
|
if(bUseMultiPass) strcat(szTxt,"supported, but not used!");
|
|
else strcat(szTxt,"activated");
|
|
}
|
|
else strcat(szTxt," NOT supported!");
|
|
strcat(szTxt,"\r\n\r\n");
|
|
}
|
|
else strcpy(szTxt,"\r\n");
|
|
|
|
strcat(pB,szTxt);
|
|
//----------------------------------------------------//
|
|
sprintf(szTxt,"Misc:\r\n- Scanlines: %s",szO[iUseScanLines]);
|
|
strcat(pB,szTxt);
|
|
if(iUseScanLines) sprintf(szTxt," [%d]\r\n",iScanBlend);
|
|
else strcpy(szTxt,"\r\n");
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Line mode: %s\r\n",szO[bUseLines]);
|
|
strcat(pB,szTxt);
|
|
// sprintf(szTxt,"- Line AA: %s\r\n",szO[bUseAntiAlias]);
|
|
// fwrite(szTxt,lstrlen(szTxt),1,txtfile);
|
|
sprintf(szTxt,"- Unfiltered FB: %s\r\n",szO[bUseFastMdec]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- 15 bit FB: %s\r\n",szO[bUse15bitMdec]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Dithering: %s\r\n",szO[bDrawDither]);
|
|
strcat(pB,szTxt);
|
|
sprintf(szTxt,"- Screen smoothing: %s",szO[iBlurBuffer]);
|
|
strcat(pB,szTxt);
|
|
if(!hW && iBlurBuffer)
|
|
{
|
|
if(gTexBlurName) strcat(pB," - supported\r\n");
|
|
else strcat(pB," - not supported\r\n");
|
|
}
|
|
else strcat(pB,"\r\n");
|
|
sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[bUseFixes],dwCfgFixes);
|
|
strcat(pB,szTxt);
|
|
//----------------------------------------------------//
|
|
return pB;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// save text infos to file
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void DoTextSnapShot(int iNum)
|
|
{
|
|
FILE *txtfile;char szTxt[256];char * pB;
|
|
|
|
#ifdef _WINDOWS
|
|
sprintf(szTxt,"snap\\pcsxr%04d.txt",iNum);
|
|
#else
|
|
sprintf(szTxt,"%s/pcsxr%04d.txt",getenv("HOME"),iNum);
|
|
#endif
|
|
|
|
if((txtfile=fopen(szTxt,"wb"))==NULL)
|
|
return;
|
|
|
|
pB=GetConfigInfos(0);
|
|
if(pB)
|
|
{
|
|
fwrite(pB,strlen(pB),1,txtfile);
|
|
free(pB);
|
|
}
|
|
fclose(txtfile);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// saves screen bitmap to file
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void DoSnapShot(void)
|
|
{
|
|
unsigned char * snapshotdumpmem=NULL,* p,c;
|
|
FILE *bmpfile;char filename[256];
|
|
unsigned char header[0x36];int size;
|
|
unsigned char empty[2]={0,0};int i;
|
|
unsigned int snapshotnr = 0;
|
|
short SnapWidth;
|
|
short SnapHeigth;
|
|
|
|
bSnapShot=FALSE;
|
|
|
|
SnapWidth = iResX;
|
|
SnapHeigth = iResY;
|
|
|
|
size=SnapWidth * SnapHeigth * 3 + 0x38;
|
|
|
|
if((snapshotdumpmem=(unsigned char *)
|
|
malloc(SnapWidth*SnapHeigth*3))==NULL)
|
|
return;
|
|
|
|
// fill in proper values for BMP
|
|
for(i=0;i<0x36;i++) header[i]=0;
|
|
header[0]='B';
|
|
header[1]='M';
|
|
header[2]=(unsigned char)(size&0xff);
|
|
header[3]=(unsigned char)((size>>8)&0xff);
|
|
header[4]=(unsigned char)((size>>16)&0xff);
|
|
header[5]=(unsigned char)((size>>24)&0xff);
|
|
header[0x0a]=0x36;
|
|
header[0x0e]=0x28;
|
|
header[0x12]=(unsigned char)(SnapWidth%256);
|
|
header[0x13]=(unsigned char)(SnapWidth/256);
|
|
header[0x16]=(unsigned char)(SnapHeigth%256);
|
|
header[0x17]=(unsigned char)(SnapHeigth/256);
|
|
header[0x1a]=0x01;
|
|
header[0x1c]=0x18;
|
|
header[0x26]=0x12;
|
|
header[0x27]=0x0B;
|
|
header[0x2A]=0x12;
|
|
header[0x2B]=0x0B;
|
|
|
|
// increment snapshot value
|
|
// get filename
|
|
do
|
|
{
|
|
snapshotnr++;
|
|
#ifdef _WINDOWS
|
|
sprintf(filename,"snap/pcsxr%04d.bmp",snapshotnr);
|
|
#else
|
|
sprintf(filename,"%s/pcsxr%04d.bmp",getenv("HOME"),snapshotnr);
|
|
#endif
|
|
bmpfile=fopen(filename,"rb");
|
|
if(bmpfile==NULL)break;
|
|
fclose(bmpfile);
|
|
if(snapshotnr==9999) break;
|
|
}
|
|
while(TRUE);
|
|
|
|
// try opening new snapshot file
|
|
if((bmpfile=fopen(filename,"wb"))==NULL)
|
|
{free(snapshotdumpmem);return;}
|
|
|
|
fwrite(header,0x36,1,bmpfile);
|
|
|
|
glReadPixels(0,0,SnapWidth,SnapHeigth,GL_RGB,
|
|
GL_UNSIGNED_BYTE,snapshotdumpmem);
|
|
p=snapshotdumpmem;
|
|
size=SnapWidth * SnapHeigth;
|
|
|
|
for(i=0;i<size;i++,p+=3)
|
|
{c=*p;*p=*(p+2);*(p+2)=c;}
|
|
|
|
fwrite(snapshotdumpmem,size*3,1,bmpfile);
|
|
fwrite(empty,0x2,1,bmpfile);
|
|
fclose(bmpfile);
|
|
free(snapshotdumpmem);
|
|
|
|
DoTextSnapShot(snapshotnr);
|
|
#ifdef _WINDOWS
|
|
MessageBeep((UINT)-1);
|
|
#endif
|
|
}
|
|
|
|
void CALLBACK GPUmakeSnapshot(void)
|
|
{
|
|
bSnapShot = TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GPU INIT... here starts it all (first func called by emu)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long CALLBACK GPUinit()
|
|
{
|
|
memset(ulStatusControl,0,256*sizeof(uint32_t));
|
|
|
|
// different ways of accessing PSX VRAM
|
|
|
|
psxVSecure=(unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
|
|
if(!psxVSecure) return -1;
|
|
|
|
psxVub=psxVSecure+512*1024; // security offset into double sized psx vram!
|
|
psxVsb=(signed char *)psxVub;
|
|
psxVsw=(signed short *)psxVub;
|
|
psxVsl=(signed int *)psxVub;
|
|
psxVuw=(unsigned short *)psxVub;
|
|
psxVul=(uint32_t *)psxVub;
|
|
|
|
psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram
|
|
|
|
memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));
|
|
memset(ulGPUInfoVals,0x00,16*sizeof(uint32_t));
|
|
|
|
InitFrameCap(); // init frame rate stuff
|
|
|
|
PSXDisplay.RGB24 = 0; // init vars
|
|
PreviousPSXDisplay.RGB24= 0;
|
|
PSXDisplay.Interlaced = 0;
|
|
PSXDisplay.InterlacedTest=0;
|
|
PSXDisplay.DrawOffset.x = 0;
|
|
PSXDisplay.DrawOffset.y = 0;
|
|
PSXDisplay.DrawArea.x0 = 0;
|
|
PSXDisplay.DrawArea.y0 = 0;
|
|
PSXDisplay.DrawArea.x1 = 320;
|
|
PSXDisplay.DrawArea.y1 = 240;
|
|
PSXDisplay.DisplayMode.x= 320;
|
|
PSXDisplay.DisplayMode.y= 240;
|
|
PSXDisplay.Disabled = FALSE;
|
|
PreviousPSXDisplay.Range.x0 =0;
|
|
PreviousPSXDisplay.Range.x1 =0;
|
|
PreviousPSXDisplay.Range.y0 =0;
|
|
PreviousPSXDisplay.Range.y1 =0;
|
|
PSXDisplay.Range.x0=0;
|
|
PSXDisplay.Range.x1=0;
|
|
PSXDisplay.Range.y0=0;
|
|
PSXDisplay.Range.y1=0;
|
|
PreviousPSXDisplay.DisplayPosition.x = 1;
|
|
PreviousPSXDisplay.DisplayPosition.y = 1;
|
|
PSXDisplay.DisplayPosition.x = 1;
|
|
PSXDisplay.DisplayPosition.y = 1;
|
|
PreviousPSXDisplay.DisplayModeNew.y=0;
|
|
PSXDisplay.Double=1;
|
|
GPUdataRet=0x400;
|
|
|
|
PSXDisplay.DisplayModeNew.x=0;
|
|
PSXDisplay.DisplayModeNew.y=0;
|
|
|
|
//PreviousPSXDisplay.Height = PSXDisplay.Height = 239;
|
|
|
|
iDataWriteMode = DR_NORMAL;
|
|
|
|
// Reset transfer values, to prevent mis-transfer of data
|
|
memset(&VRAMWrite,0,sizeof(VRAMLoad_t));
|
|
memset(&VRAMRead,0,sizeof(VRAMLoad_t));
|
|
|
|
// device initialised already !
|
|
//lGPUstatusRet = 0x74000000;
|
|
vBlank = 0;
|
|
|
|
STATUSREG = 0x14802000;
|
|
GPUIsIdle;
|
|
GPUIsReadyForCommands;
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GPU OPEN: funcs to open up the gpu display (Windows)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
void ChangeDesktop() // change destop resolution
|
|
{
|
|
DEVMODE dv;long lRes,iTry=0;
|
|
|
|
while(iTry<10) // keep on hammering...
|
|
{
|
|
memset(&dv,0,sizeof(DEVMODE));
|
|
dv.dmSize=sizeof(DEVMODE);
|
|
dv.dmBitsPerPel=iColDepth;
|
|
dv.dmPelsWidth=iResX;
|
|
dv.dmPelsHeight=iResY;
|
|
|
|
dv.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
|
|
|
|
lRes=ChangeDisplaySettings(&dv,0); // ...hammering the anvil
|
|
|
|
if(lRes==DISP_CHANGE_SUCCESSFUL) return;
|
|
iTry++;Sleep(10);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// OPEN interface func: attention!
|
|
// some emus are calling this func in their main Window thread,
|
|
// but all other interface funcs (to draw stuff) in a different thread!
|
|
// that's a problem, since OGL is thread safe! Therefore we cannot
|
|
// initialize the OGL stuff right here, we simply set a "bIsFirstFrame = TRUE"
|
|
// flag, to initialize OGL on the first real draw call.
|
|
// btw, we also call this open func ourselfes, each time when the user
|
|
// is changing between fullscreen/window mode (ENTER key)
|
|
// btw part 2: in windows the plugin gets the window handle from the
|
|
// main emu, and doesn't create it's own window (if it would do it,
|
|
// some PAD or SPU plugins would not work anymore)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
HMENU hPSEMenu=NULL;
|
|
|
|
long CALLBACK GPUopen(HWND hwndGPU)
|
|
{
|
|
HDC hdc;RECT r;DEVMODE dv;
|
|
|
|
hWWindow = hwndGPU; // store hwnd globally
|
|
|
|
InitKeyHandler(); // init key handler (subclass window)
|
|
|
|
if(bChangeWinMode) // user wants to change fullscreen/window mode?
|
|
{
|
|
ReadWinSizeConfig(); // -> get sizes again
|
|
}
|
|
else // first real startup
|
|
{
|
|
ReadConfig(); // -> read config from registry
|
|
|
|
SetFrameRateConfig(); // -> setup frame rate stuff
|
|
}
|
|
|
|
if(iNoScreenSaver) EnableScreenSaver(FALSE); // at least we can try
|
|
|
|
|
|
memset(&dv,0,sizeof(DEVMODE));
|
|
dv.dmSize=sizeof(DEVMODE);
|
|
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dv);
|
|
|
|
bIsFirstFrame = TRUE; // flag: we have to init OGL later in windows!
|
|
|
|
if(bWindowMode) // win mode?
|
|
{
|
|
DWORD dw=GetWindowLong(hWWindow, GWL_STYLE); // -> adjust wnd style (owndc needed by some stupid ogl drivers)
|
|
dw&=~WS_THICKFRAME;
|
|
dw|=WS_BORDER|WS_CAPTION|CS_OWNDC;
|
|
SetWindowLong(hWWindow, GWL_STYLE, dw);
|
|
|
|
hPSEMenu=GetMenu(hWWindow); // -> hide emu menu (if any)
|
|
if(hPSEMenu!=NULL) SetMenu(hWWindow,NULL);
|
|
|
|
iResX=LOWORD(iWinSize);iResY=HIWORD(iWinSize);
|
|
ShowWindow(hWWindow,SW_SHOWNORMAL);
|
|
|
|
MoveWindow(hWWindow, // -> center wnd
|
|
GetSystemMetrics(SM_CXFULLSCREEN)/2-iResX/2,
|
|
GetSystemMetrics(SM_CYFULLSCREEN)/2-iResY/2,
|
|
iResX+GetSystemMetrics(SM_CXFIXEDFRAME)+3,
|
|
iResY+GetSystemMetrics(SM_CYFIXEDFRAME)+GetSystemMetrics(SM_CYCAPTION)+3,
|
|
TRUE);
|
|
UpdateWindow(hWWindow); // -> let windows do some update
|
|
|
|
if(dv.dmBitsPerPel==16 || dv.dmBitsPerPel==32) // -> overwrite user color info with desktop color info
|
|
iColDepth=dv.dmBitsPerPel;
|
|
}
|
|
else // fullscreen mode:
|
|
{
|
|
if(dv.dmBitsPerPel!=(unsigned int)iColDepth || // -> check, if we have to change resolution
|
|
dv.dmPelsWidth !=(unsigned int)iResX ||
|
|
dv.dmPelsHeight!=(unsigned int)iResY)
|
|
bChangeRes=TRUE; else bChangeRes=FALSE;
|
|
|
|
if(bChangeRes) ChangeDesktop(); // -> change the res (had to do an own func because of some MS 'optimizations')
|
|
|
|
SetWindowLong(hWWindow, GWL_STYLE, CS_OWNDC); // -> adjust wnd style as well (to be sure)
|
|
|
|
hPSEMenu=GetMenu(hWWindow); // -> hide menu
|
|
if(hPSEMenu!=NULL) SetMenu(hWWindow,NULL);
|
|
ShowWindow(hWWindow,SW_SHOWMAXIMIZED); // -> max mode
|
|
}
|
|
|
|
rRatioRect.left = rRatioRect.top=0;
|
|
rRatioRect.right = iResX;
|
|
rRatioRect.bottom = iResY;
|
|
|
|
r.left=r.top=0;r.right=iResX;r.bottom=iResY; // hack for getting a clean black window until OGL gets initialized
|
|
hdc = GetDC(hWWindow);
|
|
FillRect(hdc,&r,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
bSetupPixelFormat(hdc);
|
|
ReleaseDC(hWWindow,hdc);
|
|
|
|
bDisplayNotSet = TRUE;
|
|
bSetClip=TRUE;
|
|
|
|
SetFixes(); // setup game fixes
|
|
|
|
InitializeTextureStore(); // init texture mem
|
|
|
|
resetGteVertices();
|
|
|
|
// lGPUstatusRet = 0x74000000;
|
|
|
|
// with some emus, we could do the OGL init right here... oh my
|
|
// if(bIsFirstFrame) GLinitialize();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#elif !defined (_MACGL)
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// LINUX GPU OPEN: func to open up the gpu display (X stuff)
|
|
// please note: in linux we are creating our own display, and we return
|
|
// the display ID to the main emu... that's cleaner
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
char * pCaptionText=0;
|
|
int bFullScreen=0;
|
|
Display *display;
|
|
|
|
static Cursor cursor;
|
|
static XVisualInfo *myvisual;
|
|
static Colormap colormap;
|
|
static Window window;
|
|
|
|
static int bModeChanged=0;
|
|
|
|
typedef struct
|
|
{
|
|
#define MWM_HINTS_DECORATIONS 2
|
|
long flags;
|
|
long functions;
|
|
long decorations;
|
|
long input_mode;
|
|
} MotifWmHints;
|
|
|
|
static int dbdepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,GLX_DEPTH_SIZE,16,None};
|
|
static int dbnodepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,None};
|
|
static GLXContext cx;
|
|
|
|
static int fx=0;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void osd_close_display (void) // close display
|
|
{
|
|
if(display) // display exists?
|
|
{
|
|
glXDestroyContext(display,cx); // -> kill context
|
|
XFreeColormap(display, colormap); // -> kill colormap
|
|
XSync(display,False); // -> sync events
|
|
|
|
#ifndef NOVMODE
|
|
if(bModeChanged) // -> repair screen mode
|
|
{
|
|
int myscreen=DefaultScreen(display);
|
|
XF86VidModeSwitchToMode(display,myscreen, // --> switch mode back
|
|
modes[iOldMode]);
|
|
XF86VidModeSetViewPort(display,myscreen,0,0); // --> set viewport upperleft
|
|
free(modes); // --> finally kill mode infos
|
|
bModeChanged=0; // --> done
|
|
}
|
|
#endif
|
|
|
|
XCloseDisplay(display); // -> close display
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void sysdep_create_display(void) // create display
|
|
{
|
|
XSetWindowAttributes winattr;float fxgamma=2;
|
|
int myscreen;char gammastr[14];
|
|
Screen * screen;XEvent event;
|
|
XSizeHints hints;XWMHints wm_hints;
|
|
MotifWmHints mwmhints;
|
|
Atom mwmatom;
|
|
Atom delwindow;
|
|
XClassHint* classHint;
|
|
char *glxfx;
|
|
|
|
glxfx=getenv("MESA_GLX_FX"); // 3dfx mesa fullscreen flag
|
|
if(glxfx)
|
|
{
|
|
if(glxfx[0]=='f') // -> yup, fullscreen needed
|
|
{
|
|
fx=1; // -> raise flag
|
|
putenv("FX_GLIDE_NO_SPLASH=");
|
|
sprintf(gammastr,"SST_GAMMA=%2.1f",fxgamma); // -> set gamma
|
|
putenv(gammastr);
|
|
}
|
|
}
|
|
|
|
display=XOpenDisplay(NULL); // open display
|
|
if(!display) // no display?
|
|
{
|
|
fprintf (stderr,"Failed to open display!!!\n");
|
|
osd_close_display();
|
|
return; // -> bye
|
|
}
|
|
|
|
myscreen=DefaultScreen(display); // get screen id
|
|
|
|
#ifdef NOVMODE
|
|
if(bFullScreen) {fx=1;bModeChanged=0;}
|
|
#else
|
|
if(bFullScreen)
|
|
{
|
|
XF86VidModeModeLine mode;
|
|
int nmodes,iC;
|
|
fx=1; // raise flag
|
|
XF86VidModeGetModeLine(display,myscreen,&iC,&mode); // get actual mode info
|
|
if(mode.privsize) XFree(mode.private); // no need for private stuff
|
|
bModeChanged=0; // init mode change flag
|
|
if(iResX!=mode.hdisplay || iResY!=mode.vdisplay) // wanted mode is different?
|
|
{
|
|
XF86VidModeGetAllModeLines(display,myscreen, // -> enum all mode infos
|
|
&nmodes,&modes);
|
|
if(modes) // -> infos got?
|
|
{
|
|
for(iC=0;iC<nmodes;++iC) // -> loop modes
|
|
{
|
|
if(mode.hdisplay==modes[iC]->hdisplay && // -> act mode found?
|
|
mode.vdisplay==modes[iC]->vdisplay) // if yes: store mode id
|
|
iOldMode=iC;
|
|
|
|
if(iResX==modes[iC]->hdisplay && // -> wanted mode found?
|
|
iResY==modes[iC]->vdisplay)
|
|
{
|
|
XF86VidModeSwitchToMode(display,myscreen, // --> switch to mode
|
|
modes[iC]);
|
|
XF86VidModeSetViewPort(display,myscreen,0,0);
|
|
bModeChanged=1; // --> raise flag for repairing mode on close
|
|
}
|
|
}
|
|
|
|
if(bModeChanged==0) // -> no mode found?
|
|
{
|
|
free(modes); // --> free infos
|
|
printf("%s", "No proper fullscreen mode found!\n"); // --> some info output
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
screen=DefaultScreenOfDisplay(display);
|
|
|
|
if(iZBufferDepth) // visual (with or without zbuffer)
|
|
myvisual=glXChooseVisual(display,myscreen,dbdepat);
|
|
else myvisual=glXChooseVisual(display,myscreen,dbnodepat);
|
|
|
|
if(!myvisual) // no visual?
|
|
{
|
|
fprintf(stderr,"Failed to obtain visual!!!\n"); // -> bye
|
|
osd_close_display();
|
|
return;
|
|
}
|
|
|
|
cx=glXCreateContext(display,myvisual,0,GL_TRUE); // create rendering context
|
|
|
|
if(!cx) // no context?
|
|
{
|
|
fprintf(stderr,"Failed to create OpenGL context!!!\n");
|
|
osd_close_display(); // -> bxe
|
|
return;
|
|
}
|
|
|
|
// pffff... much work for a simple blank cursor... oh, well...
|
|
if(!bFullScreen) cursor=XCreateFontCursor(display,XC_left_ptr);
|
|
else
|
|
{
|
|
Pixmap p1,p2;XImage * img;
|
|
XColor b,w;unsigned char * idata;
|
|
XGCValues GCv;
|
|
GC GCc;
|
|
|
|
memset(&b,0,sizeof(XColor));
|
|
memset(&w,0,sizeof(XColor));
|
|
idata=(unsigned char *)malloc(8);
|
|
memset(idata,0,8);
|
|
|
|
p1=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);
|
|
p2=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);
|
|
|
|
img = XCreateImage(display,myvisual->visual,
|
|
1,XYBitmap,0,idata,8,8,8,1);
|
|
|
|
GCv.function = GXcopy;
|
|
GCv.foreground = ~0;
|
|
GCv.background = 0;
|
|
GCv.plane_mask = AllPlanes;
|
|
GCc = XCreateGC(display,p1,
|
|
(GCFunction|GCForeground|GCBackground|GCPlaneMask),&GCv);
|
|
|
|
XPutImage(display, p1,GCc,img,0,0,0,0,8,8);
|
|
XPutImage(display, p2,GCc,img,0,0,0,0,8,8);
|
|
XFreeGC(display, GCc);
|
|
|
|
cursor = XCreatePixmapCursor(display,p1,p2,&b,&w,0,0);
|
|
|
|
XFreePixmap(display,p1);
|
|
XFreePixmap(display,p2);
|
|
XDestroyImage(img); // will free idata as well
|
|
}
|
|
|
|
colormap=XCreateColormap(display, // create colormap
|
|
RootWindow(display,myvisual->screen),
|
|
myvisual->visual,AllocNone);
|
|
|
|
winattr.background_pixel=0;
|
|
winattr.border_pixel=WhitePixelOfScreen(screen);
|
|
winattr.bit_gravity=ForgetGravity;
|
|
winattr.win_gravity=NorthWestGravity;
|
|
winattr.backing_store=NotUseful;
|
|
winattr.override_redirect=False;
|
|
winattr.save_under=False;
|
|
winattr.event_mask=ExposureMask |
|
|
VisibilityChangeMask |
|
|
FocusChangeMask |
|
|
KeyPressMask | KeyReleaseMask |
|
|
ButtonPressMask | ButtonReleaseMask |
|
|
PointerMotionMask;
|
|
winattr.do_not_propagate_mask=0;
|
|
winattr.colormap=colormap;
|
|
winattr.cursor=None;
|
|
|
|
window=XCreateWindow(display, // create own window
|
|
RootWindow(display,DefaultScreen(display)),
|
|
0,0,iResX,iResY,
|
|
0,myvisual->depth,
|
|
InputOutput,myvisual->visual,
|
|
CWBorderPixel | CWBackPixel |
|
|
CWEventMask | CWDontPropagate |
|
|
CWColormap | CWCursor | CWEventMask,
|
|
&winattr);
|
|
|
|
if(!window) // no window?
|
|
{
|
|
fprintf(stderr,"Failed in XCreateWindow()!!!\n");
|
|
osd_close_display(); // -> bye
|
|
return;
|
|
}
|
|
|
|
delwindow = XInternAtom(display,"WM_DELETE_WINDOW",0);
|
|
XSetWMProtocols(display, window, &delwindow, 1);
|
|
|
|
hints.flags=PMinSize|PMaxSize; // hints
|
|
if(fx) hints.flags|=USPosition|USSize;
|
|
else hints.flags|=PSize;
|
|
|
|
hints.min_width = hints.max_width = hints.base_width = iResX;
|
|
hints.min_height = hints.max_height = hints.base_height = iResY;
|
|
|
|
wm_hints.input=1;
|
|
wm_hints.flags=InputHint;
|
|
|
|
XSetWMHints(display,window,&wm_hints);
|
|
XSetWMNormalHints(display,window,&hints);
|
|
|
|
if(!pCaptionText)
|
|
pCaptionText = "Pete MesaGL PSX Gpu";
|
|
|
|
// set the WM_NAME and WM_CLASS of the window
|
|
|
|
// set the titlebar name
|
|
XStoreName(display, window, pCaptionText);
|
|
|
|
// set the name and class hints for the window manager to use
|
|
classHint = XAllocClassHint();
|
|
if(classHint)
|
|
{
|
|
classHint->res_name = pCaptionText;
|
|
classHint->res_class = pCaptionText;
|
|
}
|
|
|
|
XSetClassHint(display, window, classHint);
|
|
XFree(classHint);
|
|
|
|
XDefineCursor(display,window,cursor); // cursor
|
|
|
|
if(fx) // window title bar hack
|
|
{
|
|
mwmhints.flags=MWM_HINTS_DECORATIONS;
|
|
mwmhints.decorations=0;
|
|
mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
|
|
XChangeProperty(display,window,mwmatom,mwmatom,32,
|
|
PropModeReplace,(unsigned char *)&mwmhints,4);
|
|
}
|
|
|
|
XMapRaised(display,window);
|
|
XClearWindow(display,window);
|
|
XWindowEvent(display,window,ExposureMask,&event);
|
|
glXMakeCurrent(display,window,cx);
|
|
|
|
/*
|
|
printf("%s", glGetString(GL_VENDOR));
|
|
printf("\n");
|
|
printf("%s", glGetString(GL_RENDERER));
|
|
printf("\n");
|
|
*/
|
|
|
|
if (fx) // after make current: fullscreen resize
|
|
{
|
|
XResizeWindow(display,window,screen->width,screen->height);
|
|
hints.min_width = hints.max_width = hints.base_width = screen->width;
|
|
hints.min_height= hints.max_height = hints.base_height = screen->height;
|
|
XSetWMNormalHints(display,window,&hints);
|
|
|
|
// set the window layer for GNOME
|
|
{
|
|
XEvent xev;
|
|
|
|
memset(&xev, 0, sizeof(xev));
|
|
xev.xclient.type = ClientMessage;
|
|
xev.xclient.serial = 0;
|
|
xev.xclient.send_event = 1;
|
|
xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
|
|
xev.xclient.window = window;
|
|
xev.xclient.format = 32;
|
|
xev.xclient.data.l[0] = 1;
|
|
xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
|
|
xev.xclient.data.l[2] = 0;
|
|
xev.xclient.data.l[3] = 0;
|
|
xev.xclient.data.l[4] = 0;
|
|
|
|
XSendEvent(display, RootWindow(display, DefaultScreen(display)), 0,
|
|
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // !defined(_MACGL)
|
|
|
|
#ifndef _WINDOWS
|
|
|
|
#if defined(_MACGL)
|
|
extern char * pCaptionText;
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
|
|
{
|
|
pCaptionText=CapText;
|
|
#if !defined (_MACGL)
|
|
pConfigFile=CfgFile;
|
|
#endif
|
|
|
|
ReadConfig(); // read text file for config
|
|
|
|
SetFrameRateConfig(); // setup frame rate stuff
|
|
|
|
bIsFirstFrame = TRUE; // we have to init later (well, no really... in Linux we do all in GPUopen)
|
|
|
|
#if defined (_MACGL)
|
|
unsigned long display = ulInitDisplay();
|
|
#else
|
|
sysdep_create_display(); // create display
|
|
#endif
|
|
|
|
InitializeTextureStore(); // init texture mem
|
|
|
|
rRatioRect.left = rRatioRect.top=0;
|
|
rRatioRect.right = iResX;
|
|
rRatioRect.bottom = iResY;
|
|
|
|
GLinitialize(); // init opengl
|
|
|
|
if(disp)
|
|
{
|
|
#if defined (_MACGL)
|
|
*disp = display;
|
|
#else
|
|
*disp=(unsigned long *)display; // return display ID to main emu
|
|
#endif
|
|
}
|
|
|
|
if(display) return 0;
|
|
return -1;
|
|
}
|
|
|
|
#endif // ndef _WINDOWS
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// close
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
long CALLBACK GPUclose() // WINDOWS CLOSE
|
|
{
|
|
ExitKeyHandler();
|
|
|
|
GLcleanup(); // close OGL
|
|
|
|
if(bChangeRes) // change res back
|
|
ChangeDisplaySettings(NULL,0);
|
|
|
|
if(hPSEMenu) // set menu again
|
|
SetMenu(hWWindow,hPSEMenu);
|
|
|
|
if(pGfxCardScreen) free(pGfxCardScreen); // free helper memory
|
|
pGfxCardScreen=0;
|
|
|
|
if(iNoScreenSaver) EnableScreenSaver(TRUE); // enable screen saver again
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
long GPUclose() // LINUX CLOSE
|
|
{
|
|
GLcleanup(); // close OGL
|
|
|
|
if(pGfxCardScreen) free(pGfxCardScreen); // free helper memory
|
|
pGfxCardScreen=0;
|
|
#if defined (_MACGL)
|
|
CloseDisplay();
|
|
#else
|
|
osd_close_display(); // destroy display
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// I shot the sheriff... last function called from emu
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long CALLBACK GPUshutdown()
|
|
{
|
|
if(psxVSecure) free(psxVSecure); // kill emulated vram memory
|
|
psxVSecure=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// paint it black: simple func to clean up optical border garbage
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void PaintBlackBorders(void)
|
|
{
|
|
short s;
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}
|
|
if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
|
|
if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
vertex[0].c.lcol=0xff000000;
|
|
SETCOL(vertex[0]);
|
|
|
|
if(PreviousPSXDisplay.Range.x0)
|
|
{
|
|
s=PreviousPSXDisplay.Range.x0+1;
|
|
glVertex3f(0,0,0.99996f);
|
|
glVertex3f(0,PSXDisplay.DisplayMode.y,0.99996f);
|
|
glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);
|
|
glVertex3f(s,0,0.99996f);
|
|
|
|
s+=PreviousPSXDisplay.Range.x1-2;
|
|
|
|
glVertex3f(s,0,0.99996f);
|
|
glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);
|
|
glVertex3f(PSXDisplay.DisplayMode.x,PSXDisplay.DisplayMode.y,0.99996f);
|
|
glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);
|
|
}
|
|
|
|
if(PreviousPSXDisplay.Range.y0)
|
|
{
|
|
s=PreviousPSXDisplay.Range.y0+1;
|
|
glVertex3f(0,0,0.99996f);
|
|
glVertex3f(0,s,0.99996f);
|
|
glVertex3f(PSXDisplay.DisplayMode.x,s,0.99996f);
|
|
glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// helper to draw scanlines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static __inline void XPRIMdrawTexturedQuad(OGLVertex* vertex1, OGLVertex* vertex2,
|
|
OGLVertex* vertex3, OGLVertex* vertex4)
|
|
{
|
|
|
|
glBegin(GL_QUAD_STRIP);
|
|
glTexCoord2fv(&vertex1->sow);
|
|
PGXP_glVertexfv(&vertex1->x);
|
|
|
|
glTexCoord2fv(&vertex2->sow);
|
|
PGXP_glVertexfv(&vertex2->x);
|
|
|
|
glTexCoord2fv(&vertex4->sow);
|
|
PGXP_glVertexfv(&vertex4->x);
|
|
|
|
glTexCoord2fv(&vertex3->sow);
|
|
PGXP_glVertexfv(&vertex3->x);
|
|
glEnd();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// scanlines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetScanLines(void)
|
|
{
|
|
glLoadIdentity();
|
|
glOrtho(0,iResX,iResY, 0, -1, 1);
|
|
|
|
if(bKeepRatio)
|
|
glViewport(0,0,iResX,iResY);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
|
|
|
|
if(iScanBlend<0) // special texture mask scanline mode
|
|
{
|
|
if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
|
|
gTexName=gTexScanName;
|
|
glBindTexture(GL_TEXTURE_2D, gTexName);
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}
|
|
SetScanTexTrans();
|
|
|
|
vertex[0].x=0;
|
|
vertex[0].y=iResY;
|
|
vertex[0].z=0.99996f;
|
|
|
|
vertex[1].x=iResX;
|
|
vertex[1].y=iResY;
|
|
vertex[1].z=0.99996f;
|
|
|
|
vertex[2].x=iResX;
|
|
vertex[2].y=0;
|
|
vertex[2].z=0.99996f;
|
|
|
|
vertex[3].x=0;
|
|
vertex[3].y=0;
|
|
vertex[3].z=0.99996f;
|
|
|
|
vertex[0].sow=0;
|
|
vertex[0].tow=0;
|
|
vertex[1].sow=(float)iResX/4.0f;
|
|
vertex[1].tow=0;
|
|
vertex[2].sow=vertex[1].sow;
|
|
vertex[2].tow=(float)iResY/4.0f;
|
|
vertex[3].sow=0;
|
|
vertex[3].tow=vertex[2].tow;
|
|
|
|
vertex[0].c.lcol=0xffffffff;
|
|
SETCOL(vertex[0]);
|
|
|
|
XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);
|
|
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
|
|
}
|
|
else // typical line mode
|
|
{
|
|
if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}
|
|
|
|
if(iScanBlend==0)
|
|
{
|
|
if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
|
|
vertex[0].c.lcol=0xff000000;
|
|
}
|
|
else
|
|
{
|
|
if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}
|
|
SetScanTrans();
|
|
vertex[0].c.lcol=iScanBlend<<24;
|
|
}
|
|
|
|
SETCOL(vertex[0]);
|
|
|
|
glCallList(uiScanLine);
|
|
}
|
|
|
|
glLoadIdentity();
|
|
glOrtho(0,PSXDisplay.DisplayMode.x,
|
|
PSXDisplay.DisplayMode.y, 0, -1, 1);
|
|
|
|
//PGXP_SetMatrix(0, PSXDisplay.DisplayMode.x, PSXDisplay.DisplayMode.y, 0, -1, 1);
|
|
|
|
|
|
if(bKeepRatio)
|
|
glViewport(rRatioRect.left,
|
|
iResY-(rRatioRect.top+rRatioRect.bottom),
|
|
rRatioRect.right,
|
|
rRatioRect.bottom); // init viewport
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// blur, babe, blur (heavy performance hit for a so-so fullscreen effect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void BlurBackBuffer(void)
|
|
{
|
|
if(!gTexBlurName) return;
|
|
|
|
if(bKeepRatio) glViewport(0,0,iResX,iResY);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
|
|
if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
|
|
if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
|
|
if(iZBufferDepth) glDisable(GL_DEPTH_TEST);
|
|
if(bDrawDither) glDisable(GL_DITHER);
|
|
|
|
gTexName=gTexBlurName;
|
|
glBindTexture(GL_TEXTURE_2D, gTexName);
|
|
|
|
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // get back buffer in texture
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
iResX,iResY);
|
|
|
|
vertex[0].x=0;
|
|
vertex[0].y=PSXDisplay.DisplayMode.y;
|
|
vertex[1].x=PSXDisplay.DisplayMode.x;
|
|
vertex[1].y=PSXDisplay.DisplayMode.y;
|
|
vertex[2].x=PSXDisplay.DisplayMode.x;
|
|
vertex[2].y=0;
|
|
vertex[3].x=0;
|
|
vertex[3].y=0;
|
|
vertex[0].sow=0;
|
|
vertex[0].tow=0;
|
|
|
|
#ifdef OWNSCALE
|
|
vertex[1].sow=((GLfloat)iFTexA)/256.0f;
|
|
vertex[2].tow=((GLfloat)iFTexB)/256.0f;
|
|
#else
|
|
vertex[1].sow=iFTexA;
|
|
vertex[2].tow=iFTexB;
|
|
#endif
|
|
vertex[1].tow=0;
|
|
vertex[2].sow=vertex[1].sow;
|
|
vertex[3].sow=0;
|
|
vertex[3].tow=vertex[2].tow;
|
|
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
vertex[0].c.lcol=0x7fffffff;
|
|
SETCOL(vertex[0]);
|
|
|
|
DrawMultiBlur(); // draw the backbuffer texture to create blur effect
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
if(iZBufferDepth) glEnable(GL_DEPTH_TEST);
|
|
if(bDrawDither) glEnable(GL_DITHER);
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
|
|
|
|
if(bKeepRatio)
|
|
glViewport(rRatioRect.left, // re-init viewport
|
|
iResY-(rRatioRect.top+rRatioRect.bottom),
|
|
rRatioRect.right,
|
|
rRatioRect.bottom);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// "unblur" repairs the backbuffer after a blur
|
|
|
|
void UnBlurBackBuffer(void)
|
|
{
|
|
if(!gTexBlurName) return;
|
|
|
|
if(bKeepRatio) glViewport(0,0,iResX,iResY);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_ALPHA_TEST);
|
|
if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
|
|
if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
|
|
if(iZBufferDepth) glDisable(GL_DEPTH_TEST);
|
|
if(bDrawDither) glDisable(GL_DITHER);
|
|
|
|
gTexName=gTexBlurName;
|
|
glBindTexture(GL_TEXTURE_2D, gTexName);
|
|
|
|
vertex[0].x=0;
|
|
vertex[0].y=PSXDisplay.DisplayMode.y;
|
|
vertex[1].x=PSXDisplay.DisplayMode.x;
|
|
vertex[1].y=PSXDisplay.DisplayMode.y;
|
|
vertex[2].x=PSXDisplay.DisplayMode.x;
|
|
vertex[2].y=0;
|
|
vertex[3].x=0;
|
|
vertex[3].y=0;
|
|
vertex[0].sow=0;
|
|
vertex[0].tow=0;
|
|
#ifdef OWNSCALE
|
|
vertex[1].sow=((GLfloat)iFTexA)/256.0f;
|
|
vertex[2].tow=((GLfloat)iFTexB)/256.0f;
|
|
#else
|
|
vertex[1].sow=iFTexA;
|
|
vertex[2].tow=iFTexB;
|
|
#endif
|
|
vertex[1].tow=0;
|
|
vertex[2].sow=vertex[1].sow;
|
|
vertex[3].sow=0;
|
|
vertex[3].tow=vertex[2].tow;
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
vertex[0].c.lcol=0xffffffff;
|
|
SETCOL(vertex[0]);
|
|
|
|
// simply draw the backbuffer texture (without blur)
|
|
XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
if(iZBufferDepth) glEnable(GL_DEPTH_TEST);
|
|
if(bDrawDither) glEnable(GL_DITHER); // dither mode
|
|
if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
|
|
|
|
if(bKeepRatio)
|
|
glViewport(rRatioRect.left,
|
|
iResY-(rRatioRect.top+rRatioRect.bottom),
|
|
rRatioRect.right,
|
|
rRatioRect.bottom); // init viewport
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Update display (swap buffers)... called in interlaced mode on
|
|
// every emulated vsync, otherwise whenever the displayed screen region
|
|
// has been changed
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
int iLastRGB24=0; // special vars for checking when to skip two display updates
|
|
int iSkipTwo=0;
|
|
|
|
void updateDisplay(void) // UPDATE DISPLAY
|
|
{
|
|
BOOL bBlur=FALSE;
|
|
|
|
#ifdef _WINDOWS
|
|
HDC hdc=GetDC(hWWindow); // windows:
|
|
wglMakeCurrent(hdc,GLCONTEXT); // -> make context current again
|
|
#endif
|
|
#if defined (_MACGL)
|
|
BringContextForward();
|
|
#endif
|
|
bFakeFrontBuffer=FALSE;
|
|
bRenderFrontBuffer=FALSE;
|
|
|
|
if(iRenderFVR) // frame buffer read fix mode still active?
|
|
{
|
|
iRenderFVR--; // -> if some frames in a row without read access: turn off mode
|
|
if(!iRenderFVR) bFullVRam=FALSE;
|
|
}
|
|
|
|
if(iLastRGB24 && iLastRGB24!=PSXDisplay.RGB24+1) // (mdec) garbage check
|
|
{
|
|
iSkipTwo=2; // -> skip two frames to avoid garbage if color mode changes
|
|
}
|
|
iLastRGB24=0;
|
|
|
|
if(PSXDisplay.RGB24)// && !bNeedUploadAfter) // (mdec) upload wanted?
|
|
{
|
|
PrepareFullScreenUpload(-1);
|
|
UploadScreen(PSXDisplay.Interlaced); // -> upload whole screen from psx vram
|
|
bNeedUploadTest=FALSE;
|
|
bNeedInterlaceUpdate=FALSE;
|
|
bNeedUploadAfter=FALSE;
|
|
bNeedRGB24Update=FALSE;
|
|
}
|
|
else
|
|
if(bNeedInterlaceUpdate) // smaller upload?
|
|
{
|
|
bNeedInterlaceUpdate=FALSE;
|
|
xrUploadArea=xrUploadAreaIL; // -> upload this rect
|
|
UploadScreen(TRUE);
|
|
}
|
|
|
|
if(dwActFixes&512) bCheckFF9G4(NULL); // special game fix for FF9
|
|
|
|
if(PreviousPSXDisplay.Range.x0|| // paint black borders around display area, if needed
|
|
PreviousPSXDisplay.Range.y0)
|
|
PaintBlackBorders();
|
|
|
|
if(PSXDisplay.Disabled) // display disabled?
|
|
{
|
|
// moved here
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glClearColor(0,0,0,128); // -> clear whole backbuffer
|
|
glClear(uiBufferBits);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
gl_z=0.0f;
|
|
bDisplayNotSet = TRUE;
|
|
}
|
|
|
|
if(iSkipTwo) // we are in skipping mood?
|
|
{
|
|
iSkipTwo--;
|
|
iDrawnSomething=0; // -> simply lie about something drawn
|
|
}
|
|
|
|
if(iBlurBuffer && !bSkipNextFrame) // "blur display" activated?
|
|
{BlurBackBuffer();bBlur=TRUE;} // -> blur it
|
|
|
|
if(iUseScanLines) SetScanLines(); // "scan lines" activated? do it
|
|
|
|
if(usCursorActive) ShowGunCursor(); // "gun cursor" wanted? show 'em
|
|
|
|
if(dwActFixes&128) // special FPS limitation mode?
|
|
{
|
|
if(bUseFrameLimit) PCFrameCap(); // -> ok, do it
|
|
if(bUseFrameSkip || ulKeybits&KEY_SHOWFPS)
|
|
PCcalcfps();
|
|
}
|
|
|
|
if(gTexPicName) DisplayPic(); // some gpu info picture active? display it
|
|
|
|
if(bSnapShot) DoSnapShot(); // snapshot key pressed? cheeeese :)
|
|
|
|
if(ulKeybits&KEY_SHOWFPS) // wanna see FPS?
|
|
{
|
|
sprintf(szDispBuf,"%06.1f",fps_cur);
|
|
DisplayText(); // -> show it
|
|
}
|
|
|
|
//----------------------------------------------------//
|
|
// main buffer swapping (well, or skip it)
|
|
|
|
if(bUseFrameSkip) // frame skipping active ?
|
|
{
|
|
if(!bSkipNextFrame)
|
|
{
|
|
if(iDrawnSomething)
|
|
#ifdef _WINDOWS
|
|
SwapBuffers(wglGetCurrentDC()); // -> to skip or not to skip
|
|
#elif defined(_MACGL)
|
|
DoBufferSwap();
|
|
#else
|
|
glXSwapBuffers(display,window);
|
|
#endif
|
|
}
|
|
if(dwActFixes&0x180) // -> special old frame skipping: skip max one in a row
|
|
{
|
|
if((fps_skip < fFrameRateHz) && !(bSkipNextFrame))
|
|
{bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
|
|
else bSkipNextFrame = FALSE;
|
|
}
|
|
else FrameSkip();
|
|
}
|
|
else // no skip ?
|
|
{
|
|
if(iDrawnSomething)
|
|
#ifdef _WINDOWS
|
|
SwapBuffers(wglGetCurrentDC()); // -> swap
|
|
#elif defined(_MACGL)
|
|
DoBufferSwap();
|
|
#else
|
|
glXSwapBuffers(display,window);
|
|
#endif
|
|
}
|
|
|
|
iDrawnSomething=0;
|
|
|
|
//----------------------------------------------------//
|
|
|
|
if(lClearOnSwap) // clear buffer after swap?
|
|
{
|
|
GLclampf g,b,r;
|
|
|
|
if(bDisplayNotSet) // -> set new vals
|
|
SetOGLDisplaySettings(1);
|
|
|
|
g=((GLclampf)GREEN(lClearOnSwapColor))/255.0f; // -> get col
|
|
b=((GLclampf)BLUE(lClearOnSwapColor))/255.0f;
|
|
r=((GLclampf)RED(lClearOnSwapColor))/255.0f;
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glClearColor(r,g,b,128); // -> clear
|
|
glClear(uiBufferBits);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
lClearOnSwap=0; // -> done
|
|
}
|
|
else
|
|
{
|
|
if(bBlur) UnBlurBackBuffer(); // unblur buff, if blurred before
|
|
|
|
if(iZBufferDepth) // clear zbuffer as well (if activated)
|
|
{
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
}
|
|
}
|
|
gl_z=0.0f;
|
|
|
|
//----------------------------------------------------//
|
|
// additional uploads immediatly after swapping
|
|
|
|
if(bNeedUploadAfter) // upload wanted?
|
|
{
|
|
bNeedUploadAfter=FALSE;
|
|
bNeedUploadTest=FALSE;
|
|
UploadScreen(-1); // -> upload
|
|
}
|
|
|
|
if(bNeedUploadTest)
|
|
{
|
|
bNeedUploadTest=FALSE;
|
|
if(PSXDisplay.InterlacedTest &&
|
|
//iOffscreenDrawing>2 &&
|
|
PreviousPSXDisplay.DisplayPosition.x==PSXDisplay.DisplayPosition.x &&
|
|
PreviousPSXDisplay.DisplayEnd.x==PSXDisplay.DisplayEnd.x &&
|
|
PreviousPSXDisplay.DisplayPosition.y==PSXDisplay.DisplayPosition.y &&
|
|
PreviousPSXDisplay.DisplayEnd.y==PSXDisplay.DisplayEnd.y)
|
|
{
|
|
PrepareFullScreenUpload(TRUE);
|
|
UploadScreen(TRUE);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------//
|
|
// rumbling (main emu pad effect)
|
|
|
|
if(iRumbleTime) // shake screen by modifying view port
|
|
{
|
|
int i1=0,i2=0,i3=0,i4=0;
|
|
|
|
iRumbleTime--;
|
|
if(iRumbleTime)
|
|
{
|
|
i1=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
|
|
i2=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
|
|
i3=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
|
|
i4=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
|
|
}
|
|
|
|
glViewport(rRatioRect.left+i1,
|
|
iResY-(rRatioRect.top+rRatioRect.bottom)+i2,
|
|
rRatioRect.right+i3,
|
|
rRatioRect.bottom+i4);
|
|
}
|
|
|
|
#ifdef _WINDOWS
|
|
ReleaseDC(hWWindow,hdc); // ! important !
|
|
#endif
|
|
|
|
if(ulKeybits&KEY_RESETTEXSTORE) ResetStuff(); // reset on gpu mode changes? do it before next frame is filled
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// update front display: smaller update func, if something has changed
|
|
// in the frontbuffer... dirty, but hey... real men know no pain
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void updateFrontDisplay(void)
|
|
{
|
|
if(PreviousPSXDisplay.Range.x0||
|
|
PreviousPSXDisplay.Range.y0)
|
|
PaintBlackBorders();
|
|
|
|
if(iBlurBuffer) BlurBackBuffer();
|
|
|
|
if(iUseScanLines) SetScanLines();
|
|
|
|
if(usCursorActive) ShowGunCursor();
|
|
|
|
bFakeFrontBuffer=FALSE;
|
|
bRenderFrontBuffer=FALSE;
|
|
|
|
if(gTexPicName) DisplayPic();
|
|
if(ulKeybits&KEY_SHOWFPS) DisplayText();
|
|
|
|
#ifdef _WINDOWS
|
|
{ // windows:
|
|
HDC hdc=GetDC(hWWindow);
|
|
wglMakeCurrent(hdc,GLCONTEXT); // -> make current again
|
|
if(iDrawnSomething)
|
|
SwapBuffers(wglGetCurrentDC()); // -> swap
|
|
ReleaseDC(hWWindow,hdc); // -> ! important !
|
|
}
|
|
#elif defined (_MACGL)
|
|
if (iDrawnSomething){
|
|
DoBufferSwap();
|
|
}
|
|
#else
|
|
if(iDrawnSomething) // linux:
|
|
glXSwapBuffers(display,window);
|
|
#endif
|
|
|
|
if(iBlurBuffer) UnBlurBackBuffer();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// check if update needed
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void ChangeDispOffsetsX(void) // CENTER X
|
|
{
|
|
int lx,l;short sO;
|
|
|
|
if(!PSXDisplay.Range.x1) return; // some range given?
|
|
|
|
l=PSXDisplay.DisplayMode.x;
|
|
|
|
l*=(int)PSXDisplay.Range.x1; // some funky calculation
|
|
l/=2560;lx=l;l&=0xfffffff8;
|
|
|
|
if(l==PreviousPSXDisplay.Range.x1) return; // some change?
|
|
|
|
sO=PreviousPSXDisplay.Range.x0; // store old
|
|
|
|
if(lx>=PSXDisplay.DisplayMode.x) // range bigger?
|
|
{
|
|
PreviousPSXDisplay.Range.x1= // -> take display width
|
|
PSXDisplay.DisplayMode.x;
|
|
PreviousPSXDisplay.Range.x0=0; // -> start pos is 0
|
|
}
|
|
else // range smaller? center it
|
|
{
|
|
PreviousPSXDisplay.Range.x1=l; // -> store width (8 pixel aligned)
|
|
PreviousPSXDisplay.Range.x0= // -> calc start pos
|
|
(PSXDisplay.Range.x0-500)/8;
|
|
if(PreviousPSXDisplay.Range.x0<0) // -> we don't support neg. values yet
|
|
PreviousPSXDisplay.Range.x0=0;
|
|
|
|
if((PreviousPSXDisplay.Range.x0+lx)> // -> uhuu... that's too much
|
|
PSXDisplay.DisplayMode.x)
|
|
{
|
|
PreviousPSXDisplay.Range.x0= // -> adjust start
|
|
PSXDisplay.DisplayMode.x-lx;
|
|
PreviousPSXDisplay.Range.x1+=lx-l; // -> adjust width
|
|
}
|
|
}
|
|
|
|
if(sO!=PreviousPSXDisplay.Range.x0) // something changed?
|
|
{
|
|
bDisplayNotSet=TRUE; // -> recalc display stuff
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void ChangeDispOffsetsY(void) // CENTER Y
|
|
{
|
|
int iT;short sO; // store previous y size
|
|
|
|
if(PSXDisplay.PAL) iT=48; else iT=28; // different offsets on PAL/NTSC
|
|
|
|
if(PSXDisplay.Range.y0>=iT) // crossed the security line? :)
|
|
{
|
|
PreviousPSXDisplay.Range.y1= // -> store width
|
|
PSXDisplay.DisplayModeNew.y;
|
|
|
|
sO=(PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double; // -> calc offset
|
|
if(sO<0) sO=0;
|
|
|
|
PSXDisplay.DisplayModeNew.y+=sO; // -> add offset to y size, too
|
|
}
|
|
else sO=0; // else no offset
|
|
|
|
if(sO!=PreviousPSXDisplay.Range.y0) // something changed?
|
|
{
|
|
PreviousPSXDisplay.Range.y0=sO;
|
|
bDisplayNotSet=TRUE; // -> recalc display stuff
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Aspect ratio of ogl screen: simply adjusting ogl view port
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetAspectRatio(void)
|
|
{
|
|
float xs,ys,s,resx,resy;RECT r;
|
|
|
|
if(!PSXDisplay.DisplayModeNew.x) return;
|
|
if(!PSXDisplay.DisplayModeNew.y) return;
|
|
|
|
resx = bForceRatio43 ? 640.0f : (float)PSXDisplay.DisplayModeNew.x;
|
|
resy = bForceRatio43 ? 480.0f : (float)PSXDisplay.DisplayModeNew.y;
|
|
|
|
xs=(float)iResX/resx;
|
|
ys=(float)iResY/resy;
|
|
|
|
s=min(xs,ys);
|
|
r.right =(int)(resx*s);
|
|
r.bottom=(int)(resy*s);
|
|
if(r.right > iResX) r.right = iResX;
|
|
if(r.bottom > iResY) r.bottom = iResY;
|
|
if(r.right < 1) r.right = 1;
|
|
if(r.bottom < 1) r.bottom = 1;
|
|
|
|
r.left = (iResX-r.right)/2;
|
|
r.top = (iResY-r.bottom)/2;
|
|
|
|
if(r.bottom<rRatioRect.bottom ||
|
|
r.right <rRatioRect.right)
|
|
{
|
|
RECT rC;
|
|
glClearColor(0,0,0,128);
|
|
|
|
if(r.right <rRatioRect.right)
|
|
{
|
|
rC.left=0;
|
|
rC.top=0;
|
|
rC.right=r.left;
|
|
rC.bottom=iResY;
|
|
glScissor(rC.left,rC.top,rC.right,rC.bottom);
|
|
glClear(uiBufferBits);
|
|
rC.left=iResX-rC.right;
|
|
glScissor(rC.left,rC.top,rC.right,rC.bottom);
|
|
glClear(uiBufferBits);
|
|
}
|
|
|
|
if(r.bottom <rRatioRect.bottom)
|
|
{
|
|
rC.left=0;
|
|
rC.top=0;
|
|
rC.right=iResX;
|
|
rC.bottom=r.top;
|
|
glScissor(rC.left,rC.top,rC.right,rC.bottom);
|
|
glClear(uiBufferBits);
|
|
rC.top=iResY-rC.bottom;
|
|
glScissor(rC.left,rC.top,rC.right,rC.bottom);
|
|
glClear(uiBufferBits);
|
|
}
|
|
|
|
bSetClip=TRUE;
|
|
bDisplayNotSet=TRUE;
|
|
}
|
|
|
|
rRatioRect=r;
|
|
|
|
|
|
glViewport(rRatioRect.left,
|
|
iResY-(rRatioRect.top+rRatioRect.bottom),
|
|
rRatioRect.right,
|
|
rRatioRect.bottom); // init viewport
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// big ass check, if an ogl swap buffer is needed
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void updateDisplayIfChanged(void)
|
|
{
|
|
BOOL bUp;
|
|
|
|
if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
|
|
(PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
|
|
{
|
|
if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
|
|
(PSXDisplay.Interlaced == PSXDisplay.InterlacedNew))
|
|
return; // nothing has changed? fine, no swap buffer needed
|
|
}
|
|
else // some res change?
|
|
{
|
|
glLoadIdentity();
|
|
glOrtho(0,PSXDisplay.DisplayModeNew.x, // -> new psx resolution
|
|
PSXDisplay.DisplayModeNew.y, 0, -1, 1);
|
|
|
|
// PGXP_SetMatrix(0, PSXDisplay.DisplayModeNew.x, PSXDisplay.DisplayModeNew.y, 0, -1, 1);
|
|
|
|
|
|
if(bKeepRatio) SetAspectRatio();
|
|
}
|
|
|
|
bDisplayNotSet = TRUE; // re-calc offsets/display area
|
|
|
|
bUp=FALSE;
|
|
if(PSXDisplay.RGB24!=PSXDisplay.RGB24New) // clean up textures, if rgb mode change (usually mdec on/off)
|
|
{
|
|
PreviousPSXDisplay.RGB24=0; // no full 24 frame uploaded yet
|
|
ResetTextureArea(FALSE);
|
|
bUp=TRUE;
|
|
}
|
|
|
|
PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
|
|
PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
|
|
PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
|
|
PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
|
|
|
|
PSXDisplay.DisplayEnd.x= // calc new ends
|
|
PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
|
|
PSXDisplay.DisplayEnd.y=
|
|
PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
|
|
PreviousPSXDisplay.DisplayEnd.x=
|
|
PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
|
|
PreviousPSXDisplay.DisplayEnd.y=
|
|
PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
|
|
|
|
ChangeDispOffsetsX();
|
|
|
|
if(iFrameLimit==2) SetAutoFrameCap(); // set new fps limit vals (depends on interlace)
|
|
|
|
if(bUp) updateDisplay(); // yeah, real update (swap buffer)
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// window mode <-> fullscreen mode (windows)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WINDOWS
|
|
void ChangeWindowMode(void)
|
|
{
|
|
GPUclose();
|
|
bWindowMode=!bWindowMode;
|
|
GPUopen(hWWindow);
|
|
bChangeWinMode=FALSE;
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// swap update check (called by psx vsync function)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL bSwapCheck(void)
|
|
{
|
|
static int iPosCheck=0;
|
|
static PSXPoint_t pO;
|
|
static PSXPoint_t pD;
|
|
static int iDoAgain=0;
|
|
|
|
if(PSXDisplay.DisplayPosition.x==pO.x &&
|
|
PSXDisplay.DisplayPosition.y==pO.y &&
|
|
PSXDisplay.DisplayEnd.x==pD.x &&
|
|
PSXDisplay.DisplayEnd.y==pD.y)
|
|
iPosCheck++;
|
|
else iPosCheck=0;
|
|
|
|
pO=PSXDisplay.DisplayPosition;
|
|
pD=PSXDisplay.DisplayEnd;
|
|
|
|
if(iPosCheck<=4) return FALSE;
|
|
|
|
iPosCheck=4;
|
|
|
|
if(PSXDisplay.Interlaced) return FALSE;
|
|
|
|
if (bNeedInterlaceUpdate||
|
|
bNeedRGB24Update ||
|
|
bNeedUploadAfter||
|
|
bNeedUploadTest ||
|
|
iDoAgain
|
|
)
|
|
{
|
|
iDoAgain=0;
|
|
if(bNeedUploadAfter)
|
|
iDoAgain=1;
|
|
if(bNeedUploadTest && PSXDisplay.InterlacedTest)
|
|
iDoAgain=1;
|
|
|
|
bDisplayNotSet = TRUE;
|
|
updateDisplay();
|
|
|
|
PreviousPSXDisplay.DisplayPosition.x=PSXDisplay.DisplayPosition.x;
|
|
PreviousPSXDisplay.DisplayPosition.y=PSXDisplay.DisplayPosition.y;
|
|
PreviousPSXDisplay.DisplayEnd.x=PSXDisplay.DisplayEnd.x;
|
|
PreviousPSXDisplay.DisplayEnd.y=PSXDisplay.DisplayEnd.y;
|
|
pO=PSXDisplay.DisplayPosition;
|
|
pD=PSXDisplay.DisplayEnd;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// gun cursor func: player=0-7, x=0-511, y=0-255
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUcursor(int iPlayer,int x,int y)
|
|
{
|
|
if(iPlayer<0) return;
|
|
if(iPlayer>7) return;
|
|
|
|
usCursorActive|=(1<<iPlayer);
|
|
|
|
if(x<0) x=0;
|
|
if(x>iGPUHeightMask) x=iGPUHeightMask;
|
|
if(y<0) y=0;
|
|
if(y>255) y=255;
|
|
|
|
ptCursorPoint[iPlayer].x=x;
|
|
ptCursorPoint[iPlayer].y=y;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// update lace is called every VSync. Basically we limit frame rate
|
|
// here, and in interlaced mode we swap ogl display buffers.
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static unsigned short usFirstPos=2;
|
|
|
|
void CALLBACK GPUupdateLace(void)
|
|
{
|
|
//if(!(dwActFixes&0x1000))
|
|
// STATUSREG^=0x80000000; // interlaced bit toggle, if the CC game fix is not active (see gpuReadStatus)
|
|
|
|
if(!(dwActFixes&128)) // normal frame limit func
|
|
CheckFrameRate();
|
|
|
|
if(iOffscreenDrawing==4) // special check if high offscreen drawing is on
|
|
{
|
|
if(bSwapCheck()) return;
|
|
}
|
|
|
|
if(PSXDisplay.Interlaced) // interlaced mode?
|
|
{
|
|
STATUSREG^=0x80000000;
|
|
if(PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
|
|
{
|
|
updateDisplay(); // -> swap buffers (new frame)
|
|
}
|
|
}
|
|
else if(bRenderFrontBuffer) // no interlace mode? and some stuff in front has changed?
|
|
{
|
|
updateFrontDisplay(); // -> update front buffer
|
|
}
|
|
else if(usFirstPos==1) // initial updates (after startup)
|
|
{
|
|
updateDisplay();
|
|
}
|
|
|
|
#if defined(_WINDOWS) || defined(_MACGL)
|
|
if(bChangeWinMode) ChangeWindowMode();
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// process read request from GPU status register
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
uint32_t CALLBACK GPUreadStatus(void)
|
|
{
|
|
if(dwActFixes&0x1000) // CC game fix
|
|
{
|
|
static int iNumRead=0;
|
|
if((iNumRead++)==2)
|
|
{
|
|
iNumRead=0;
|
|
STATUSREG^=0x80000000; // interlaced bit toggle... we do it on every second read status... needed by some games (like ChronoCross)
|
|
}
|
|
}
|
|
|
|
if(iFakePrimBusy) // 27.10.2007 - emulating some 'busy' while drawing... pfff... not perfect, but since our emulated dma is not done in an extra thread...
|
|
{
|
|
iFakePrimBusy--;
|
|
|
|
if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
|
|
{
|
|
GPUIsBusy;
|
|
GPUIsNotReadyForCommands;
|
|
}
|
|
else
|
|
{
|
|
GPUIsIdle;
|
|
GPUIsReadyForCommands;
|
|
}
|
|
}
|
|
|
|
return STATUSREG | (vBlank ? 0x80000000 : 0 );;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// processes data send to GPU status register
|
|
// these are always single packet commands.
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUwriteStatus(uint32_t gdata)
|
|
{
|
|
uint32_t lCommand=(gdata>>24)&0xff;
|
|
|
|
#ifdef _WINDOWS
|
|
if(bIsFirstFrame) GLinitialize(); // real ogl startup (needed by some emus)
|
|
#endif
|
|
|
|
ulStatusControl[lCommand]=gdata;
|
|
|
|
switch(lCommand)
|
|
{
|
|
//--------------------------------------------------//
|
|
// reset gpu
|
|
case 0x00:
|
|
memset(ulGPUInfoVals, 0x00, 16 * sizeof(uint32_t));
|
|
lGPUstatusRet = 0x14802000;
|
|
PSXDisplay.Disabled=1;
|
|
iDataWriteMode=iDataReadMode=DR_NORMAL;
|
|
PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
|
|
drawX=drawY=0;drawW=drawH=0;
|
|
sSetMask=0;lSetMask=0;bCheckMask=FALSE;iSetMask=0;
|
|
usMirror=0;
|
|
GlobalTextAddrX=0;GlobalTextAddrY=0;
|
|
GlobalTextTP=0;GlobalTextABR=0;
|
|
PSXDisplay.RGB24=FALSE;
|
|
PSXDisplay.Interlaced=FALSE;
|
|
bUsingTWin = FALSE;
|
|
return;
|
|
|
|
// dis/enable display
|
|
case 0x03:
|
|
PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
|
|
PSXDisplay.Disabled = (gdata & 1);
|
|
|
|
if(PSXDisplay.Disabled)
|
|
STATUSREG|=GPUSTATUS_DISPLAYDISABLED;
|
|
else STATUSREG&=~GPUSTATUS_DISPLAYDISABLED;
|
|
|
|
if (iOffscreenDrawing==4 &&
|
|
PreviousPSXDisplay.Disabled &&
|
|
!(PSXDisplay.Disabled))
|
|
{
|
|
|
|
if(!PSXDisplay.RGB24)
|
|
{
|
|
PrepareFullScreenUpload(TRUE);
|
|
UploadScreen(TRUE);
|
|
updateDisplay();
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
// setting transfer mode
|
|
case 0x04:
|
|
gdata &= 0x03; // only want the lower two bits
|
|
|
|
iDataWriteMode=iDataReadMode=DR_NORMAL;
|
|
if(gdata==0x02) iDataWriteMode=DR_VRAMTRANSFER;
|
|
if(gdata==0x03) iDataReadMode =DR_VRAMTRANSFER;
|
|
|
|
STATUSREG&=~GPUSTATUS_DMABITS; // clear the current settings of the DMA bits
|
|
STATUSREG|=(gdata << 29); // set the DMA bits according to the received data
|
|
|
|
return;
|
|
|
|
// setting display position
|
|
case 0x05:
|
|
{
|
|
short sx=(short)(gdata & 0x3ff);
|
|
short sy;
|
|
|
|
if(iGPUHeight==1024)
|
|
{
|
|
if(dwGPUVersion==2)
|
|
sy = (short)((gdata>>12)&0x3ff);
|
|
else sy = (short)((gdata>>10)&0x3ff);
|
|
}
|
|
else sy = (short)((gdata>>10)&0x3ff); // really: 0x1ff, but we adjust it later
|
|
|
|
if (sy & 0x200)
|
|
{
|
|
sy|=0xfc00;
|
|
PreviousPSXDisplay.DisplayModeNew.y=sy/PSXDisplay.Double;
|
|
sy=0;
|
|
}
|
|
else PreviousPSXDisplay.DisplayModeNew.y=0;
|
|
|
|
if(sx>1000) sx=0;
|
|
|
|
if(usFirstPos)
|
|
{
|
|
usFirstPos--;
|
|
if(usFirstPos)
|
|
{
|
|
PreviousPSXDisplay.DisplayPosition.x = sx;
|
|
PreviousPSXDisplay.DisplayPosition.y = sy;
|
|
PSXDisplay.DisplayPosition.x = sx;
|
|
PSXDisplay.DisplayPosition.y = sy;
|
|
}
|
|
}
|
|
|
|
if(dwActFixes&8)
|
|
{
|
|
if((!PSXDisplay.Interlaced) &&
|
|
PreviousPSXDisplay.DisplayPosition.x == sx &&
|
|
PreviousPSXDisplay.DisplayPosition.y == sy)
|
|
return;
|
|
|
|
PSXDisplay.DisplayPosition.x = PreviousPSXDisplay.DisplayPosition.x;
|
|
PSXDisplay.DisplayPosition.y = PreviousPSXDisplay.DisplayPosition.y;
|
|
PreviousPSXDisplay.DisplayPosition.x = sx;
|
|
PreviousPSXDisplay.DisplayPosition.y = sy;
|
|
}
|
|
else
|
|
{
|
|
if((!PSXDisplay.Interlaced) &&
|
|
PSXDisplay.DisplayPosition.x == sx &&
|
|
PSXDisplay.DisplayPosition.y == sy)
|
|
return;
|
|
PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
|
|
PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
|
|
PSXDisplay.DisplayPosition.x = sx;
|
|
PSXDisplay.DisplayPosition.y = sy;
|
|
}
|
|
|
|
PSXDisplay.DisplayEnd.x=
|
|
PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
|
|
PSXDisplay.DisplayEnd.y=
|
|
PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
|
|
|
|
PreviousPSXDisplay.DisplayEnd.x=
|
|
PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
|
|
PreviousPSXDisplay.DisplayEnd.y=
|
|
PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
|
|
|
|
bDisplayNotSet = TRUE;
|
|
|
|
if (!(PSXDisplay.Interlaced))
|
|
{
|
|
updateDisplay();
|
|
}
|
|
else
|
|
if(PSXDisplay.InterlacedTest &&
|
|
((PreviousPSXDisplay.DisplayPosition.x != PSXDisplay.DisplayPosition.x)||
|
|
(PreviousPSXDisplay.DisplayPosition.y != PSXDisplay.DisplayPosition.y)))
|
|
PSXDisplay.InterlacedTest--;
|
|
|
|
return;
|
|
}
|
|
|
|
// setting width
|
|
case 0x06:
|
|
|
|
PSXDisplay.Range.x0=gdata & 0x7ff; //0x3ff;
|
|
PSXDisplay.Range.x1=(gdata>>12) & 0xfff;//0x7ff;
|
|
|
|
PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
|
|
|
|
ChangeDispOffsetsX();
|
|
|
|
return;
|
|
|
|
// setting height
|
|
case 0x07:
|
|
|
|
PreviousPSXDisplay.Height = PSXDisplay.Height;
|
|
|
|
PSXDisplay.Range.y0=gdata & 0x3ff;
|
|
PSXDisplay.Range.y1=(gdata>>10) & 0x3ff;
|
|
|
|
PSXDisplay.Height = PSXDisplay.Range.y1 -
|
|
PSXDisplay.Range.y0 +
|
|
PreviousPSXDisplay.DisplayModeNew.y;
|
|
|
|
if (PreviousPSXDisplay.Height != PSXDisplay.Height)
|
|
{
|
|
PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
|
|
ChangeDispOffsetsY();
|
|
updateDisplayIfChanged();
|
|
}
|
|
return;
|
|
|
|
// setting display infos
|
|
case 0x08:
|
|
|
|
PSXDisplay.DisplayModeNew.x = dispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
|
|
|
|
if (gdata&0x04) PSXDisplay.Double=2;
|
|
else PSXDisplay.Double=1;
|
|
PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
|
|
|
|
ChangeDispOffsetsY();
|
|
|
|
PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
|
|
PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
|
|
PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
|
|
|
|
STATUSREG&=~GPUSTATUS_WIDTHBITS; // clear the width bits
|
|
|
|
STATUSREG|=
|
|
(((gdata & 0x03) << 17) |
|
|
((gdata & 0x40) << 10)); // set the width bits
|
|
|
|
PreviousPSXDisplay.InterlacedNew=FALSE;
|
|
if (PSXDisplay.InterlacedNew)
|
|
{
|
|
if(!PSXDisplay.Interlaced)
|
|
{
|
|
PSXDisplay.InterlacedTest=2;
|
|
PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
|
|
PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
|
|
PreviousPSXDisplay.InterlacedNew=TRUE;
|
|
}
|
|
|
|
STATUSREG|=GPUSTATUS_INTERLACED;
|
|
}
|
|
else
|
|
{
|
|
PSXDisplay.InterlacedTest=0;
|
|
STATUSREG&=~GPUSTATUS_INTERLACED;
|
|
}
|
|
|
|
if (PSXDisplay.PAL)
|
|
STATUSREG|=GPUSTATUS_PAL;
|
|
else STATUSREG&=~GPUSTATUS_PAL;
|
|
|
|
if (PSXDisplay.Double==2)
|
|
STATUSREG|=GPUSTATUS_DOUBLEHEIGHT;
|
|
else STATUSREG&=~GPUSTATUS_DOUBLEHEIGHT;
|
|
|
|
if (PSXDisplay.RGB24New)
|
|
STATUSREG|=GPUSTATUS_RGB24;
|
|
else STATUSREG&=~GPUSTATUS_RGB24;
|
|
|
|
updateDisplayIfChanged();
|
|
|
|
return;
|
|
|
|
//--------------------------------------------------//
|
|
// ask about GPU version and other stuff
|
|
case 0x10:
|
|
|
|
gdata&=0xff;
|
|
|
|
switch(gdata)
|
|
{
|
|
case 0x02:
|
|
GPUdataRet=ulGPUInfoVals[INFO_TW]; // tw infos
|
|
return;
|
|
case 0x03:
|
|
GPUdataRet=ulGPUInfoVals[INFO_DRAWSTART]; // draw start
|
|
return;
|
|
case 0x04:
|
|
GPUdataRet=ulGPUInfoVals[INFO_DRAWEND]; // draw end
|
|
return;
|
|
case 0x05:
|
|
case 0x06:
|
|
GPUdataRet=ulGPUInfoVals[INFO_DRAWOFF]; // draw offset
|
|
return;
|
|
case 0x07:
|
|
if(dwGPUVersion==2)
|
|
GPUdataRet=0x01;
|
|
else GPUdataRet=0x02; // gpu type
|
|
return;
|
|
case 0x08:
|
|
case 0x0F: // some bios addr?
|
|
GPUdataRet=0xBFC03720;
|
|
return;
|
|
}
|
|
return;
|
|
//--------------------------------------------------//
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// vram read/write helpers
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL bNeedWriteUpload=FALSE;
|
|
|
|
static __inline void FinishedVRAMWrite(void)
|
|
{
|
|
if(bNeedWriteUpload)
|
|
{
|
|
bNeedWriteUpload=FALSE;
|
|
CheckWriteUpdate();
|
|
}
|
|
|
|
// set register to NORMAL operation
|
|
iDataWriteMode = DR_NORMAL;
|
|
|
|
// reset transfer values, to prevent mis-transfer of data
|
|
VRAMWrite.ColsRemaining = 0;
|
|
VRAMWrite.RowsRemaining = 0;
|
|
}
|
|
|
|
static __inline void FinishedVRAMRead(void)
|
|
{
|
|
// set register to NORMAL operation
|
|
iDataReadMode = DR_NORMAL;
|
|
// reset transfer values, to prevent mis-transfer of data
|
|
VRAMRead.x = 0;
|
|
VRAMRead.y = 0;
|
|
VRAMRead.Width = 0;
|
|
VRAMRead.Height = 0;
|
|
VRAMRead.ColsRemaining = 0;
|
|
VRAMRead.RowsRemaining = 0;
|
|
|
|
// indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
|
|
STATUSREG&=~GPUSTATUS_READYFORVRAM;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// vram read check ex (reading from card's back/frontbuffer if needed...
|
|
// slow!)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CheckVRamReadEx(int x, int y, int dx, int dy)
|
|
{
|
|
unsigned short sArea;
|
|
int ux,uy,udx,udy,wx,wy;
|
|
unsigned short * p1, *p2;
|
|
float XS,YS;
|
|
unsigned char * ps;
|
|
unsigned char * px;
|
|
unsigned short s,sx;
|
|
|
|
if(STATUSREG&GPUSTATUS_RGB24) return;
|
|
|
|
if(((dx > PSXDisplay.DisplayPosition.x) &&
|
|
(x < PSXDisplay.DisplayEnd.x) &&
|
|
(dy > PSXDisplay.DisplayPosition.y) &&
|
|
(y < PSXDisplay.DisplayEnd.y)))
|
|
sArea=0;
|
|
else
|
|
if((!(PSXDisplay.InterlacedTest) &&
|
|
(dx > PreviousPSXDisplay.DisplayPosition.x) &&
|
|
(x < PreviousPSXDisplay.DisplayEnd.x) &&
|
|
(dy > PreviousPSXDisplay.DisplayPosition.y) &&
|
|
(y < PreviousPSXDisplay.DisplayEnd.y)))
|
|
sArea=1;
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
//////////////
|
|
|
|
if(iRenderFVR)
|
|
{
|
|
bFullVRam=TRUE;iRenderFVR=2;return;
|
|
}
|
|
bFullVRam=TRUE;iRenderFVR=2;
|
|
|
|
//////////////
|
|
|
|
p2=0;
|
|
|
|
if(sArea==0)
|
|
{
|
|
ux=PSXDisplay.DisplayPosition.x;
|
|
uy=PSXDisplay.DisplayPosition.y;
|
|
udx=PSXDisplay.DisplayEnd.x-ux;
|
|
udy=PSXDisplay.DisplayEnd.y-uy;
|
|
if((PreviousPSXDisplay.DisplayEnd.x-
|
|
PreviousPSXDisplay.DisplayPosition.x)==udx &&
|
|
(PreviousPSXDisplay.DisplayEnd.y-
|
|
PreviousPSXDisplay.DisplayPosition.y)==udy)
|
|
p2=(psxVuw + (1024*PreviousPSXDisplay.DisplayPosition.y) +
|
|
PreviousPSXDisplay.DisplayPosition.x);
|
|
}
|
|
else
|
|
{
|
|
ux=PreviousPSXDisplay.DisplayPosition.x;
|
|
uy=PreviousPSXDisplay.DisplayPosition.y;
|
|
udx=PreviousPSXDisplay.DisplayEnd.x-ux;
|
|
udy=PreviousPSXDisplay.DisplayEnd.y-uy;
|
|
if((PSXDisplay.DisplayEnd.x-
|
|
PSXDisplay.DisplayPosition.x)==udx &&
|
|
(PSXDisplay.DisplayEnd.y-
|
|
PSXDisplay.DisplayPosition.y)==udy)
|
|
p2=(psxVuw + (1024*PSXDisplay.DisplayPosition.y) +
|
|
PSXDisplay.DisplayPosition.x);
|
|
}
|
|
|
|
p1=(psxVuw + (1024*uy) + ux);
|
|
if(p1==p2) p2=0;
|
|
|
|
x=0;y=0;
|
|
wx=dx=udx;wy=dy=udy;
|
|
|
|
if(udx<=0) return;
|
|
if(udy<=0) return;
|
|
if(dx<=0) return;
|
|
if(dy<=0) return;
|
|
if(wx<=0) return;
|
|
if(wy<=0) return;
|
|
|
|
XS=(float)rRatioRect.right/(float)wx;
|
|
YS=(float)rRatioRect.bottom/(float)wy;
|
|
|
|
dx=(int)((float)(dx)*XS);
|
|
dy=(int)((float)(dy)*YS);
|
|
|
|
if(dx>iResX) dx=iResX;
|
|
if(dy>iResY) dy=iResY;
|
|
|
|
if(dx<=0) return;
|
|
if(dy<=0) return;
|
|
|
|
// ogl y adjust
|
|
y=iResY-y-dy;
|
|
|
|
x+=rRatioRect.left;
|
|
y-=rRatioRect.top;
|
|
|
|
if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;
|
|
|
|
if(!pGfxCardScreen)
|
|
{
|
|
glPixelStorei(GL_PACK_ALIGNMENT,1);
|
|
pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
|
|
}
|
|
|
|
ps=pGfxCardScreen;
|
|
|
|
if(!sArea) glReadBuffer(GL_FRONT);
|
|
|
|
glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);
|
|
|
|
if(!sArea) glReadBuffer(GL_BACK);
|
|
|
|
s=0;
|
|
|
|
XS=(float)dx/(float)(udx);
|
|
YS=(float)dy/(float)(udy+1);
|
|
|
|
for(y=udy;y>0;y--)
|
|
{
|
|
for(x=0;x<udx;x++)
|
|
{
|
|
if(p1>=psxVuw && p1<psxVuw_eom)
|
|
{
|
|
px=ps+(3*((int)((float)x * XS))+
|
|
(3*dx)*((int)((float)y*YS)));
|
|
sx=(*px)>>3;px++;
|
|
s=sx;
|
|
sx=(*px)>>3;px++;
|
|
s|=sx<<5;
|
|
sx=(*px)>>3;
|
|
s|=sx<<10;
|
|
s&=~0x8000;
|
|
*p1=s;
|
|
}
|
|
if(p2>=psxVuw && p2<psxVuw_eom) *p2=s;
|
|
|
|
p1++;
|
|
if(p2) p2++;
|
|
}
|
|
|
|
p1 += 1024 - udx;
|
|
if(p2) p2 += 1024 - udx;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// vram read check (reading from card's back/frontbuffer if needed...
|
|
// slow!)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CheckVRamRead(int x, int y, int dx, int dy,BOOL bFront)
|
|
{
|
|
unsigned short sArea;unsigned short * p;
|
|
int ux,uy,udx,udy,wx,wy;float XS,YS;
|
|
unsigned char * ps, * px;
|
|
unsigned short s=0,sx;
|
|
|
|
if(STATUSREG&GPUSTATUS_RGB24) return;
|
|
|
|
if(((dx > PSXDisplay.DisplayPosition.x) &&
|
|
(x < PSXDisplay.DisplayEnd.x) &&
|
|
(dy > PSXDisplay.DisplayPosition.y) &&
|
|
(y < PSXDisplay.DisplayEnd.y)))
|
|
sArea=0;
|
|
else
|
|
if((!(PSXDisplay.InterlacedTest) &&
|
|
(dx > PreviousPSXDisplay.DisplayPosition.x) &&
|
|
(x < PreviousPSXDisplay.DisplayEnd.x) &&
|
|
(dy > PreviousPSXDisplay.DisplayPosition.y) &&
|
|
(y < PreviousPSXDisplay.DisplayEnd.y)))
|
|
sArea=1;
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(dwActFixes&0x40)
|
|
{
|
|
if(iRenderFVR)
|
|
{
|
|
bFullVRam=TRUE;iRenderFVR=2;return;
|
|
}
|
|
bFullVRam=TRUE;iRenderFVR=2;
|
|
}
|
|
|
|
ux=x;uy=y;udx=dx;udy=dy;
|
|
|
|
if(sArea==0)
|
|
{
|
|
x -=PSXDisplay.DisplayPosition.x;
|
|
dx-=PSXDisplay.DisplayPosition.x;
|
|
y -=PSXDisplay.DisplayPosition.y;
|
|
dy-=PSXDisplay.DisplayPosition.y;
|
|
wx=PSXDisplay.DisplayEnd.x-PSXDisplay.DisplayPosition.x;
|
|
wy=PSXDisplay.DisplayEnd.y-PSXDisplay.DisplayPosition.y;
|
|
}
|
|
else
|
|
{
|
|
x -=PreviousPSXDisplay.DisplayPosition.x;
|
|
dx-=PreviousPSXDisplay.DisplayPosition.x;
|
|
y -=PreviousPSXDisplay.DisplayPosition.y;
|
|
dy-=PreviousPSXDisplay.DisplayPosition.y;
|
|
wx=PreviousPSXDisplay.DisplayEnd.x-PreviousPSXDisplay.DisplayPosition.x;
|
|
wy=PreviousPSXDisplay.DisplayEnd.y-PreviousPSXDisplay.DisplayPosition.y;
|
|
}
|
|
if(x<0) {ux-=x;x=0;}
|
|
if(y<0) {uy-=y;y=0;}
|
|
if(dx>wx) {udx-=(dx-wx);dx=wx;}
|
|
if(dy>wy) {udy-=(dy-wy);dy=wy;}
|
|
udx-=ux;
|
|
udy-=uy;
|
|
|
|
p=(psxVuw + (1024*uy) + ux);
|
|
|
|
if(udx<=0) return;
|
|
if(udy<=0) return;
|
|
if(dx<=0) return;
|
|
if(dy<=0) return;
|
|
if(wx<=0) return;
|
|
if(wy<=0) return;
|
|
|
|
XS=(float)rRatioRect.right/(float)wx;
|
|
YS=(float)rRatioRect.bottom/(float)wy;
|
|
|
|
dx=(int)((float)(dx)*XS);
|
|
dy=(int)((float)(dy)*YS);
|
|
x=(int)((float)x*XS);
|
|
y=(int)((float)y*YS);
|
|
|
|
dx-=x;
|
|
dy-=y;
|
|
|
|
if(dx>iResX) dx=iResX;
|
|
if(dy>iResY) dy=iResY;
|
|
|
|
if(dx<=0) return;
|
|
if(dy<=0) return;
|
|
|
|
// ogl y adjust
|
|
y=iResY-y-dy;
|
|
|
|
x+=rRatioRect.left;
|
|
y-=rRatioRect.top;
|
|
|
|
if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;
|
|
|
|
if(!pGfxCardScreen)
|
|
{
|
|
glPixelStorei(GL_PACK_ALIGNMENT,1);
|
|
pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
|
|
}
|
|
|
|
ps=pGfxCardScreen;
|
|
|
|
if(bFront) glReadBuffer(GL_FRONT);
|
|
|
|
glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);
|
|
|
|
if(bFront) glReadBuffer(GL_BACK);
|
|
|
|
XS=(float)dx/(float)(udx);
|
|
YS=(float)dy/(float)(udy+1);
|
|
|
|
for(y=udy;y>0;y--)
|
|
{
|
|
for(x=0;x<udx;x++)
|
|
{
|
|
if(p>=psxVuw && p<psxVuw_eom)
|
|
{
|
|
px=ps+(3*((int)((float)x * XS))+
|
|
(3*dx)*((int)((float)y*YS)));
|
|
sx=(*px)>>3;px++;
|
|
s=sx;
|
|
sx=(*px)>>3;px++;
|
|
s|=sx<<5;
|
|
sx=(*px)>>3;
|
|
s|=sx<<10;
|
|
s&=~0x8000;
|
|
*p=s;
|
|
}
|
|
p++;
|
|
}
|
|
p += 1024 - udx;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// core read from vram
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUreadDataMem(uint32_t *pMem, int iSize)
|
|
{
|
|
int i;
|
|
|
|
if(iDataReadMode!=DR_VRAMTRANSFER) return;
|
|
|
|
GPUIsBusy;
|
|
|
|
// adjust read ptr, if necessary
|
|
while(VRAMRead.ImagePtr>=psxVuw_eom)
|
|
VRAMRead.ImagePtr-=iGPUHeight*1024;
|
|
while(VRAMRead.ImagePtr<psxVuw)
|
|
VRAMRead.ImagePtr+=iGPUHeight*1024;
|
|
|
|
if((iFrameReadType&1 && iSize>1) &&
|
|
!(iDrawnSomething==2 &&
|
|
VRAMRead.x == VRAMWrite.x &&
|
|
VRAMRead.y == VRAMWrite.y &&
|
|
VRAMRead.Width == VRAMWrite.Width &&
|
|
VRAMRead.Height == VRAMWrite.Height))
|
|
CheckVRamRead(VRAMRead.x,VRAMRead.y,
|
|
VRAMRead.x+VRAMRead.RowsRemaining,
|
|
VRAMRead.y+VRAMRead.ColsRemaining,
|
|
TRUE);
|
|
|
|
for(i=0;i<iSize;i++)
|
|
{
|
|
// do 2 seperate 16bit reads for compatibility (wrap issues)
|
|
if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
|
|
{
|
|
// lower 16 bit
|
|
GPUdataRet=(uint32_t)*VRAMRead.ImagePtr;
|
|
|
|
VRAMRead.ImagePtr++;
|
|
if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
|
|
VRAMRead.RowsRemaining --;
|
|
|
|
if(VRAMRead.RowsRemaining<=0)
|
|
{
|
|
VRAMRead.RowsRemaining = VRAMRead.Width;
|
|
VRAMRead.ColsRemaining--;
|
|
VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
|
|
if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
|
|
}
|
|
|
|
// higher 16 bit (always, even if it's an odd width)
|
|
GPUdataRet|=(uint32_t)(*VRAMRead.ImagePtr)<<16;
|
|
*pMem++=GPUdataRet;
|
|
|
|
if(VRAMRead.ColsRemaining <= 0)
|
|
{FinishedVRAMRead();goto ENDREAD;}
|
|
|
|
VRAMRead.ImagePtr++;
|
|
if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
|
|
VRAMRead.RowsRemaining--;
|
|
if(VRAMRead.RowsRemaining<=0)
|
|
{
|
|
VRAMRead.RowsRemaining = VRAMRead.Width;
|
|
VRAMRead.ColsRemaining--;
|
|
VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
|
|
if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
|
|
}
|
|
if(VRAMRead.ColsRemaining <= 0)
|
|
{FinishedVRAMRead();goto ENDREAD;}
|
|
}
|
|
else {FinishedVRAMRead();goto ENDREAD;}
|
|
}
|
|
|
|
ENDREAD:
|
|
GPUIsIdle;
|
|
}
|
|
|
|
uint32_t CALLBACK GPUreadData(void)
|
|
{
|
|
uint32_t l;
|
|
GPUreadDataMem(&l,1);
|
|
return GPUdataRet;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// helper table to know how much data is used by drawing commands
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
const unsigned char primTableCX[256] =
|
|
{
|
|
// 00
|
|
0,0,3,0,0,0,0,0,
|
|
// 08
|
|
0,0,0,0,0,0,0,0,
|
|
// 10
|
|
0,0,0,0,0,0,0,0,
|
|
// 18
|
|
0,0,0,0,0,0,0,0,
|
|
// 20
|
|
4,4,4,4,7,7,7,7,
|
|
// 28
|
|
5,5,5,5,9,9,9,9,
|
|
// 30
|
|
6,6,6,6,9,9,9,9,
|
|
// 38
|
|
8,8,8,8,12,12,12,12,
|
|
// 40
|
|
3,3,3,3,0,0,0,0,
|
|
// 48
|
|
// 5,5,5,5,6,6,6,6, //FLINE
|
|
254,254,254,254,254,254,254,254,
|
|
// 50
|
|
4,4,4,4,0,0,0,0,
|
|
// 58
|
|
// 7,7,7,7,9,9,9,9, // LINEG3 LINEG4
|
|
255,255,255,255,255,255,255,255,
|
|
// 60
|
|
3,3,3,3,4,4,4,4, // TILE SPRT
|
|
// 68
|
|
2,2,2,2,3,3,3,3, // TILE1
|
|
// 70
|
|
2,2,2,2,3,3,3,3,
|
|
// 78
|
|
2,2,2,2,3,3,3,3,
|
|
// 80
|
|
4,0,0,0,0,0,0,0,
|
|
// 88
|
|
0,0,0,0,0,0,0,0,
|
|
// 90
|
|
0,0,0,0,0,0,0,0,
|
|
// 98
|
|
0,0,0,0,0,0,0,0,
|
|
// a0
|
|
3,0,0,0,0,0,0,0,
|
|
// a8
|
|
0,0,0,0,0,0,0,0,
|
|
// b0
|
|
0,0,0,0,0,0,0,0,
|
|
// b8
|
|
0,0,0,0,0,0,0,0,
|
|
// c0
|
|
3,0,0,0,0,0,0,0,
|
|
// c8
|
|
0,0,0,0,0,0,0,0,
|
|
// d0
|
|
0,0,0,0,0,0,0,0,
|
|
// d8
|
|
0,0,0,0,0,0,0,0,
|
|
// e0
|
|
0,1,1,1,1,1,1,0,
|
|
// e8
|
|
0,0,0,0,0,0,0,0,
|
|
// f0
|
|
0,0,0,0,0,0,0,0,
|
|
// f8
|
|
0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// processes data send to GPU data register
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUwriteDataMem(uint32_t *pMem, int iSize)
|
|
{
|
|
unsigned char command;
|
|
uint32_t gdata=0;
|
|
int i=0;
|
|
GPUIsBusy;
|
|
GPUIsNotReadyForCommands;
|
|
|
|
STARTVRAM:
|
|
|
|
if(iDataWriteMode==DR_VRAMTRANSFER)
|
|
{
|
|
// make sure we are in vram
|
|
while(VRAMWrite.ImagePtr>=psxVuw_eom)
|
|
VRAMWrite.ImagePtr-=iGPUHeight*1024;
|
|
while(VRAMWrite.ImagePtr<psxVuw)
|
|
VRAMWrite.ImagePtr+=iGPUHeight*1024;
|
|
|
|
// now do the loop
|
|
while(VRAMWrite.ColsRemaining>0)
|
|
{
|
|
while(VRAMWrite.RowsRemaining>0)
|
|
{
|
|
if(i>=iSize) {goto ENDVRAM;}
|
|
i++;
|
|
|
|
gdata=*pMem++;
|
|
|
|
// Write odd pixel - Wrap from beginning to next index if going past GPU width
|
|
if(VRAMWrite.Width+VRAMWrite.x-VRAMWrite.RowsRemaining >= 1024) {
|
|
*((VRAMWrite.ImagePtr++)-1024) = (unsigned short)gdata;
|
|
} else { *VRAMWrite.ImagePtr++ = (unsigned short)gdata;}
|
|
if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;// Check if went past framebuffer
|
|
VRAMWrite.RowsRemaining --;
|
|
|
|
// Check if end at odd pixel drawn
|
|
if(VRAMWrite.RowsRemaining <= 0)
|
|
{
|
|
VRAMWrite.ColsRemaining--;
|
|
if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
|
|
{
|
|
gdata=(gdata&0xFFFF)|(((uint32_t)(*VRAMWrite.ImagePtr))<<16);
|
|
FinishedVRAMWrite();
|
|
goto ENDVRAM;
|
|
}
|
|
VRAMWrite.RowsRemaining = VRAMWrite.Width;
|
|
VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
|
|
}
|
|
|
|
// Write even pixel - Wrap from beginning to next index if going past GPU width
|
|
if(VRAMWrite.Width+VRAMWrite.x-VRAMWrite.RowsRemaining >= 1024) {
|
|
*((VRAMWrite.ImagePtr++)-1024) = (unsigned short)(gdata>>16);
|
|
} else *VRAMWrite.ImagePtr++ = (unsigned short)(gdata>>16);
|
|
if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;// Check if went past framebuffer
|
|
VRAMWrite.RowsRemaining --;
|
|
}
|
|
|
|
VRAMWrite.RowsRemaining = VRAMWrite.Width;
|
|
VRAMWrite.ColsRemaining--;
|
|
VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
|
|
}
|
|
|
|
FinishedVRAMWrite();
|
|
}
|
|
|
|
ENDVRAM:
|
|
|
|
if(iDataWriteMode==DR_NORMAL)
|
|
{
|
|
void (* *primFunc)(unsigned char *);
|
|
if(bSkipNextFrame) primFunc=primTableSkip;
|
|
else primFunc=primTableJ;
|
|
|
|
for(;i<iSize;)
|
|
{
|
|
if(iDataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
|
|
|
|
gdata=*pMem++;i++;
|
|
|
|
if(gpuDataC == 0)
|
|
{
|
|
command = (unsigned char)((gdata>>24) & 0xff);
|
|
|
|
if(primTableCX[command])
|
|
{
|
|
gpuDataC = primTableCX[command];
|
|
gpuCommand = command;
|
|
gpuDataM[0] = gdata;
|
|
gpuDataP = 1;
|
|
}
|
|
else continue;
|
|
}
|
|
else
|
|
{
|
|
gpuDataM[gpuDataP] = gdata;
|
|
if(gpuDataC>128)
|
|
{
|
|
if((gpuDataC==254 && gpuDataP>=3) ||
|
|
(gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
|
|
{
|
|
if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
|
|
gpuDataP=gpuDataC-1;
|
|
}
|
|
}
|
|
gpuDataP++;
|
|
}
|
|
|
|
if(gpuDataP == gpuDataC)
|
|
{
|
|
gpuDataC=gpuDataP=0;
|
|
for (unsigned int i = 0; i < 4; i++) //iCB: remove stale vertex data
|
|
{
|
|
vertex[i].x = vertex[i].y = 0.f;
|
|
vertex[i].z = 0.95f;
|
|
vertex[i].w = 1.f;
|
|
vertex[i].PGXP_flag = 0;
|
|
}
|
|
primFunc[gpuCommand]((unsigned char *)gpuDataM);
|
|
|
|
if(dwEmuFixes&0x0001 || dwActFixes&0x20000) // hack for emulating "gpu busy" in some games
|
|
iFakePrimBusy=4;
|
|
}
|
|
}
|
|
}
|
|
|
|
GPUdataRet=gdata;
|
|
|
|
GPUIsReadyForCommands;
|
|
GPUIsIdle;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUwriteData(uint32_t gdata)
|
|
{
|
|
GPUwriteDataMem(&gdata,1);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// call config dlg
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
long CALLBACK GPUconfigure(void)
|
|
{
|
|
HWND hWP=GetActiveWindow();
|
|
DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG),
|
|
hWP,(DLGPROC)CfgDlgProc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#elif defined(_MACGL)
|
|
long CALLBACK GPUconfigure(void)
|
|
{
|
|
DlgProc();
|
|
return 0;
|
|
}
|
|
#else
|
|
|
|
void StartCfgTool(char *arg) // linux: start external cfg tool
|
|
{
|
|
char cfg[256];
|
|
struct stat buf;
|
|
|
|
strcpy(cfg, "./cfgpeopsxgl");
|
|
if (stat(cfg, &buf) != -1) {
|
|
int pid = fork();
|
|
if (pid == 0) {
|
|
if (fork() == 0) {
|
|
execl(cfg, "cfgpeopsxgl", arg, NULL);
|
|
}
|
|
exit(0);
|
|
} else {
|
|
waitpid(pid, NULL, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
strcpy(cfg, "./cfg/cfgpeopsxgl");
|
|
if (stat(cfg, &buf) != -1) {
|
|
int pid = fork();
|
|
if (pid == 0) {
|
|
if (fork() == 0) {
|
|
execl(cfg, "cfgpeopsxgl", arg, NULL);
|
|
}
|
|
exit(0);
|
|
} else {
|
|
waitpid(pid, NULL, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
sprintf(cfg, "%s/.pcsxr/plugins/cfg/cfgpeopsxgl", getenv("HOME"));
|
|
if (stat(cfg, &buf) != -1) {
|
|
int pid = fork();
|
|
if (pid == 0) {
|
|
if (fork() == 0) {
|
|
execl(cfg, "cfgpeopsxgl", arg, NULL);
|
|
}
|
|
exit(0);
|
|
} else {
|
|
waitpid(pid, NULL, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
printf("ERROR: cfgpeopsxgl file not found!\n");
|
|
}
|
|
|
|
long CALLBACK GPUconfigure(void)
|
|
{
|
|
StartCfgTool("configure");
|
|
return 0;
|
|
}
|
|
|
|
#endif // def _WINDOWS / _MACGL
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// sets all kind of act fixes
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetFixes(void)
|
|
{
|
|
ReInitFrameCap();
|
|
|
|
if(dwActFixes & 0x2000)
|
|
dispWidths[4]=384;
|
|
else dispWidths[4]=368;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Pete Special: make an 'intelligent' dma chain check (<-Tekken3)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
uint32_t lUsedAddr[3];
|
|
|
|
static __inline BOOL CheckForEndlessLoop(uint32_t laddr)
|
|
{
|
|
if(laddr==lUsedAddr[1]) return TRUE;
|
|
if(laddr==lUsedAddr[2]) return TRUE;
|
|
|
|
if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
|
|
else lUsedAddr[2]=laddr;
|
|
lUsedAddr[0]=laddr;
|
|
return FALSE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// core gives a dma chain to gpu: same as the gpuwrite interface funcs
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long CALLBACK GPUdmaChain(uint32_t *baseAddrL, uint32_t addr)
|
|
{
|
|
uint32_t dmaMem;
|
|
unsigned char * baseAddrB;
|
|
short count;unsigned int DMACommandCounter = 0;
|
|
|
|
if(bIsFirstFrame) GLinitialize();
|
|
|
|
GPUIsBusy;
|
|
|
|
lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
|
|
|
|
baseAddrB = (unsigned char*) baseAddrL;
|
|
|
|
uint32_t depthCount = 0;
|
|
do
|
|
{
|
|
if(iGPUHeight==512) addr&=0x1FFFFC;
|
|
|
|
if(DMACommandCounter++ > 2000000) break;
|
|
if(CheckForEndlessLoop(addr)) break;
|
|
|
|
count = baseAddrB[addr+3];
|
|
|
|
dmaMem=addr+4;
|
|
|
|
if (count > 0)
|
|
{
|
|
PGXP_SetAddress(dmaMem >> 2, &baseAddrL[dmaMem >> 2], count);
|
|
GPUwriteDataMem(&baseAddrL[dmaMem >> 2], count);
|
|
}
|
|
else
|
|
PGXP_SetDepth(depthCount++);
|
|
|
|
addr = baseAddrL[addr>>2]&0xffffff;
|
|
}
|
|
while (addr != 0xffffff);
|
|
|
|
GPUIsIdle;
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// show about dlg
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUabout(void)
|
|
{
|
|
#ifdef _WINDOWS
|
|
HWND hWP=GetActiveWindow(); // to be sure
|
|
DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG_ABOUT), hWP,(DLGPROC)AboutDlgProc);
|
|
#elif defined(_MACGL)
|
|
AboutDlgProc();
|
|
#else
|
|
StartCfgTool("about");
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// We are ever fine ;)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long CALLBACK GPUtest(void)
|
|
{
|
|
// if test fails this function should return negative value for error (unable to continue)
|
|
// and positive value for warning (can continue but output might be crappy)
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// save state funcs
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct GPUFREEZETAG
|
|
{
|
|
uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
|
|
uint32_t ulStatus; // current gpu status
|
|
uint32_t ulControl[256]; // latest control register values
|
|
unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
|
|
} GPUFreeze_t;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
|
|
{
|
|
if(ulGetFreezeData==2)
|
|
{
|
|
int lSlotNum=*((int *)pF);
|
|
if(lSlotNum<0) return 0;
|
|
if(lSlotNum>8) return 0;
|
|
lSelectedSlot=lSlotNum+1;
|
|
return 1;
|
|
}
|
|
|
|
if(!pF) return 0;
|
|
if(pF->ulFreezeVersion!=1) return 0;
|
|
|
|
if(ulGetFreezeData==1)
|
|
{
|
|
pF->ulStatus=STATUSREG;
|
|
memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
|
|
memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if(ulGetFreezeData!=0) return 0;
|
|
|
|
STATUSREG=pF->ulStatus;
|
|
memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
|
|
memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
|
|
|
|
ResetTextureArea(TRUE);
|
|
|
|
GPUwriteStatus(ulStatusControl[0]);
|
|
GPUwriteStatus(ulStatusControl[1]);
|
|
GPUwriteStatus(ulStatusControl[2]);
|
|
GPUwriteStatus(ulStatusControl[3]);
|
|
GPUwriteStatus(ulStatusControl[8]);
|
|
GPUwriteStatus(ulStatusControl[6]);
|
|
GPUwriteStatus(ulStatusControl[7]);
|
|
GPUwriteStatus(ulStatusControl[5]);
|
|
GPUwriteStatus(ulStatusControl[4]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// special "emu infos" / "emu effects" functions
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//00 = black
|
|
//01 = white
|
|
//10 = red
|
|
//11 = transparent
|
|
|
|
unsigned char cFont[10][120]=
|
|
{
|
|
// 0
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 1
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x05,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x05,0x55,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 2
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x01,0x40,0x00,0x00,
|
|
0x80,0x00,0x05,0x00,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x15,0x55,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 3
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x01,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 4
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x54,0x00,0x00,
|
|
0x80,0x00,0x01,0x54,0x00,0x00,
|
|
0x80,0x00,0x01,0x54,0x00,0x00,
|
|
0x80,0x00,0x05,0x14,0x00,0x00,
|
|
0x80,0x00,0x14,0x14,0x00,0x00,
|
|
0x80,0x00,0x15,0x55,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x55,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 5
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x15,0x55,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x15,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 6
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x01,0x54,0x00,0x00,
|
|
0x80,0x00,0x05,0x00,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x14,0x00,0x00,0x00,
|
|
0x80,0x00,0x15,0x54,0x00,0x00,
|
|
0x80,0x00,0x15,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 7
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x15,0x55,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x50,0x00,0x00,
|
|
0x80,0x00,0x01,0x40,0x00,0x00,
|
|
0x80,0x00,0x01,0x40,0x00,0x00,
|
|
0x80,0x00,0x05,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 8
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
},
|
|
// 9
|
|
{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x05,0x54,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x05,0x00,0x00,
|
|
0x80,0x00,0x14,0x15,0x00,0x00,
|
|
0x80,0x00,0x05,0x55,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x05,0x00,0x00,
|
|
0x80,0x00,0x00,0x14,0x00,0x00,
|
|
0x80,0x00,0x05,0x50,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0x80,0x00,0x00,0x00,0x00,0x00,
|
|
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void PaintPicDot(unsigned char * p,unsigned char c)
|
|
{
|
|
if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}
|
|
if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}
|
|
if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUgetScreenPic(unsigned char * pMem)
|
|
{
|
|
float XS,YS;int x,y,v;
|
|
unsigned char * ps, * px, * pf;
|
|
unsigned char c;
|
|
|
|
if(!pGfxCardScreen)
|
|
{
|
|
glPixelStorei(GL_PACK_ALIGNMENT,1);
|
|
pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
|
|
}
|
|
|
|
ps=pGfxCardScreen;
|
|
|
|
glReadBuffer(GL_FRONT);
|
|
|
|
glReadPixels(0,0,iResX,iResY,GL_RGB,GL_UNSIGNED_BYTE,ps);
|
|
|
|
glReadBuffer(GL_BACK);
|
|
|
|
XS=(float)iResX/128;
|
|
YS=(float)iResY/96;
|
|
pf=pMem;
|
|
|
|
for(y=96;y>0;y--)
|
|
{
|
|
for(x=0;x<128;x++)
|
|
{
|
|
px=ps+(3*((int)((float)x * XS))+
|
|
(3*iResX)*((int)((float)y*YS)));
|
|
*(pf+0)=*(px+2);
|
|
*(pf+1)=*(px+1);
|
|
*(pf+2)=*(px+0);
|
|
pf+=3;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// generic number/border painter
|
|
|
|
pf=pMem+(103*3);
|
|
|
|
for(y=0;y<20;y++)
|
|
{
|
|
for(x=0;x<6;x++)
|
|
{
|
|
c=cFont[lSelectedSlot][x+y*6];
|
|
v=(c&0xc0)>>6;
|
|
PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect
|
|
v=(c&0x30)>>4;
|
|
PaintPicDot(pf,(unsigned char)v);pf+=3;
|
|
v=(c&0x0c)>>2;
|
|
PaintPicDot(pf,(unsigned char)v);pf+=3;
|
|
v=c&0x03;
|
|
PaintPicDot(pf,(unsigned char)v);pf+=3;
|
|
}
|
|
pf+=104*3;
|
|
}
|
|
|
|
pf=pMem;
|
|
for(x=0;x<128;x++)
|
|
{
|
|
*(pf+(95*128*3))=0x00;*pf++=0x00;
|
|
*(pf+(95*128*3))=0x00;*pf++=0x00;
|
|
*(pf+(95*128*3))=0xff;*pf++=0xff;
|
|
}
|
|
pf=pMem;
|
|
for(y=0;y<96;y++)
|
|
{
|
|
*(pf+(127*3))=0x00;*pf++=0x00;
|
|
*(pf+(127*3))=0x00;*pf++=0x00;
|
|
*(pf+(127*3))=0xff;*pf++=0xff;
|
|
pf+=127*3;
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUshowScreenPic(unsigned char * pMem)
|
|
{
|
|
DestroyPic();
|
|
if(pMem==0) return;
|
|
CreatePic(pMem);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUsetfix(uint32_t dwFixBits)
|
|
{
|
|
dwEmuFixes=dwFixBits;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUvisualVibration(uint32_t iSmall, uint32_t iBig)
|
|
{
|
|
int iVibVal;
|
|
|
|
if(PSXDisplay.DisplayModeNew.x) // calc min "shake pixel" from screen width
|
|
iVibVal=max(1,iResX/PSXDisplay.DisplayModeNew.x);
|
|
else iVibVal=1;
|
|
// big rumble: 4...15 sp ; small rumble 1...3 sp
|
|
if(iBig) iRumbleVal=max(4*iVibVal,min(15*iVibVal,((int)iBig *iVibVal)/10));
|
|
else iRumbleVal=max(1*iVibVal,min( 3*iVibVal,((int)iSmall*iVibVal)/10));
|
|
|
|
srand(timeGetTime()); // init rand (will be used in BufferSwap)
|
|
|
|
iRumbleTime=15; // let the rumble last 16 buffer swaps
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// main emu can set display infos (A/M/G/D)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void CALLBACK GPUdisplayFlags(uint32_t dwFlags)
|
|
{
|
|
dwCoreFlags=dwFlags;
|
|
}
|
|
|
|
void CALLBACK GPUvBlank( int val )
|
|
{
|
|
vBlank = val;
|
|
}
|