diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fb47b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +*.Identifier diff --git a/CMakeLists.txt b/CMakeLists.txt index 456e2af..0654c8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,14 +217,20 @@ target_link_libraries(${PROJECT_NAME} PRIVATE pspnet_apctl pspnet_inet pspnet_resolver + pspctrl + pspaudiolib + psputility ) -# Compiler options +# Compiler options use -O0 -g for debugging set(COMMON_COMPILE_FLAGS -G0 -Wall -Wno-narrowing -O2 + -w + -DPSP_LARGE_MEMORY=ON + -DBUILD_PRX=ON -fno-exceptions -fno-rtti -std=c++11 @@ -233,7 +239,7 @@ set(COMMON_COMPILE_FLAGS -DDEBUG -DLOCALE=US -DTARGET=POSTAL_2015 - -w + -DPSPFW3X ) target_compile_options(${PROJECT_NAME} PRIVATE ${COMMON_COMPILE_FLAGS}) @@ -244,8 +250,9 @@ if(PSP) TARGET ${PROJECT_NAME} ICON_PATH "../source/ICON0.PNG" BACKGROUND_PATH "../source/PIC1.PNG" + MUSIC_PATH "../source/SND0.AT3" PREVIEW_PATH NULL - TITLE POSTAL PSP + TITLE "POSTAL PSP" VERSION 01.00 ) endif() diff --git a/README.md b/README.md index e37947f..ca87df0 100644 --- a/README.md +++ b/README.md @@ -9,19 +9,31 @@ Toolchain is [PSPDEV](https://pspdev.github.io/installation.html) To play get a copy at [Steam](https://store.steampowered.com/app/232770/POSTAL/) or [GOG](https://www.gog.com/en/game/postal_classic_and_uncut) -The game is playable on stock firmware (unmodded PSP) - ## Buildung After setting up PSPDEV and git clone the repo ```bash cd postal-psp mkdir build && cd build -psp-cmake -DBUILD_PRX=1 -DENC_PRX=1 .. +psp-cmake -DBUILD_PRX=1 .. make ``` +#### DO NOT USE `-DENC_PRX=1` + +### Debbuging using WSL + +- [Detailed Guide](https://pspdev.github.io/debugging.html) +- Launch [PSPLINK](https://github.com/pspdev/psplinkusb/releases/download/latest/psplink.zip) +- Open Windows PowerShell as admin and install `winget install usbipd` +- Then `usbipd list` and look for PSP Type-B +- Then `usbipd bind --busid=X-X` and look for PSP Type-B +- `usbipd attach --wsl --busid=X-X` +- Then run [PSP Link](https://pspdev.github.io/debugging.html) + ## Known issues -- Plays fine in PPSSPP but crashes on real hardware -- Low fps (high cpu usage) \ No newline at end of file +- Plays fine in PPSSPP but slow and unstable on real hardware +- Low FPS (high cpu usage) +- Long loading times +- Controls need to be adjusted \ No newline at end of file diff --git a/source/RSPiX/Src/BLUE/unix/Bdisp.cpp b/source/RSPiX/Src/BLUE/unix/Bdisp.cpp index 7527bbb..5c6753a 100644 --- a/source/RSPiX/Src/BLUE/unix/Bdisp.cpp +++ b/source/RSPiX/Src/BLUE/unix/Bdisp.cpp @@ -18,7 +18,7 @@ /////////////////////////////////////////////////////////////////////////////// // // bdisp.cpp -// +// // History: // 06/04/04 RCG Started. // @@ -34,6 +34,30 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + float u, v; + uint32_t colour; + float x, y, z; +} TextureVertex; + +typedef struct +{ + float width; // Texture width + float height; // Texture height + uint32_t *data; // Pointer to texture pixel data (VRAM) +} Texture; + +char list[0x20000] __attribute__((aligned(64))); + extern SDL_Window *sdlWindow; static char *sdlAppName; static SDL_Renderer *sdlRenderer; @@ -45,42 +69,52 @@ static int FramebufferHeight = 0; static Uint32 *TexturePointer = NULL; static Uint8 *PalettedTexturePointer = NULL; -typedef struct // Stores information on usable video modes. +typedef struct // Stores information on usable video modes. +{ + int16_t sWidth; + int16_t sHeight; + int16_t sColorDepth; + int16_t sPages; +} VIDEO_MODE, *PVIDEO_MODE; + +static RSList slvmModes; // List of available video modes. + +typedef union +{ + struct { - int16_t sWidth; - int16_t sHeight; - int16_t sColorDepth; - int16_t sPages; - } VIDEO_MODE, *PVIDEO_MODE; - -static RSList slvmModes; // List of available video modes. - -typedef union { struct { Uint8 b; Uint8 g; Uint8 r; Uint8 a; }; Uint32 argb; } ArgbColor; -static ArgbColor apeApp[256]; // App's palette. The palette - // entries the App actually set. -//Unused! Why? -//static ArgbColor apeMapped[256]; // Tweaked palette. - // This is the palette updated to - // the hardware. apeApp is trans- - // lated through au8MapRed, Green, - // and Blue and stored here for - // updating to the hardware on - // rspUpdatePalette(). - -static U8 au8MapRed[256]; // Map of red intensities to hardware - // values. Initially an identity - // mapping. -static U8 au8MapGreen[256]; // Map of green intensities to - // hardware values. Initially an - // identity mapping. -static U8 au8MapBlue[256]; // Map of blue intensities to hardware - // values. Initially an identity - // mapping. - -static int16_t asPalEntryLocks[256]; // TRUE, if an indexed entry is locked. - // FALSE, if not. Implemented as - // shorts in case we ever do levels of - // locking. + Uint8 b; + Uint8 g; + Uint8 r; + Uint8 a; + }; + Uint32 argb; +} ArgbColor; +static ArgbColor apeApp[256]; // App's palette. The palette + // entries the App actually set. +// Unused! Why? +// static ArgbColor apeMapped[256]; // Tweaked palette. +// This is the palette updated to +// the hardware. apeApp is trans- +// lated through au8MapRed, Green, +// and Blue and stored here for +// updating to the hardware on +// rspUpdatePalette(). + +static U8 au8MapRed[256]; // Map of red intensities to hardware + // values. Initially an identity + // mapping. +static U8 au8MapGreen[256]; // Map of green intensities to + // hardware values. Initially an + // identity mapping. +static U8 au8MapBlue[256]; // Map of blue intensities to hardware + // values. Initially an identity + // mapping. + +static int16_t asPalEntryLocks[256]; // TRUE, if an indexed entry is locked. + // FALSE, if not. Implemented as + // shorts in case we ever do levels of + // locking. extern bool mouse_grabbed; @@ -89,192 +123,189 @@ extern bool mouse_grabbed; ////////////////////////////////////////////////////////////////////////////// // Only set value if not NULL. -#define SET(ptr, val) ( ((ptr) != NULL) ? *(ptr) = (val) : 0) - +#define SET(ptr, val) (((ptr) != NULL) ? *(ptr) = (val) : 0) ////////////////////////////////////////////////////////////////////////////// // // Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. // ////////////////////////////////////////////////////////////////////////////// -extern int16_t Clip( // Returns non-zero if image entirely clipped out. - int16_t* px, // Rectangle to be clipped. - int16_t* py, - int16_t* pw, - int16_t* ph, - int16_t sx, // Bounding rectangle. - int16_t sy, - int16_t sw, - int16_t sh) - { +extern int16_t Clip( // Returns non-zero if image entirely clipped out. + int16_t *px, // Rectangle to be clipped. + int16_t *py, + int16_t *pw, + int16_t *ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) +{ if (*px < sx) - { + { TRACE("Clip(): x too small.\n"); // Adjust width. *pw -= sx - *px; // Adjust x. *px = sx; - } + } if (*py < sy) - { + { TRACE("Clip(): y too small.\n"); // Adjust height. *ph -= sy - *py; // Adjust y. *py = sy; - } + } if (*px + *pw > sw) - { + { TRACE("Clip(): Width or x too large.\n"); // Adjust width. *pw -= ((*px + *pw) - sw); - } + } if (*py + *ph > sh) - { + { TRACE("Clip(): Height or y too large.\n"); // Adjust height. *ph -= ((*py + *ph) - sh); - } - - // Return 0 (success) if there's a width and a height left. - return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); } + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); +} + ////////////////////////////////////////////////////////////////////////////// // // Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. // ////////////////////////////////////////////////////////////////////////////// -extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. - int16_t* px, // Rectangle to be clipped. - int16_t* py, - int16_t* pw, - int16_t* ph, - int16_t sx, // Bounding rectangle. - int16_t sy, - int16_t sw, - int16_t sh) - { +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int16_t *px, // Rectangle to be clipped. + int16_t *py, + int16_t *pw, + int16_t *ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) +{ if (*px < sx) - { + { // Adjust width. *pw -= sx - *px; // Adjust x. *px = sx; - } + } if (*py < sy) - { + { // Adjust height. *ph -= sy - *py; // Adjust y. *py = sy; - } + } if (*px + *pw > sw) - { + { // Adjust width. *pw -= ((*px + *pw) - sw); - } + } if (*py + *ph > sh) - { + { // Adjust height. *ph -= ((*py + *ph) - sh); - } - - // Return 0 (success) if there's a width and a height left. - return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); } + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); +} + ////////////////////////////////////////////////////////////////////////////// // // Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. // Uses short version of function ClipQuiet(...). // ////////////////////////////////////////////////////////////////////////////// -extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. - int32_t* px, // Rectangle to be clipped. - int32_t* py, - int32_t* pw, - int32_t* ph, - int32_t sx, // Bounding rectangle. - int32_t sy, - int32_t sw, - int32_t sh) - { - int16_t sX = (int16_t)(*px); - int16_t sY = (int16_t)(*py); - int16_t sW = (int16_t)(*pw); - int16_t sH = (int16_t)(*ph); +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int32_t *px, // Rectangle to be clipped. + int32_t *py, + int32_t *pw, + int32_t *ph, + int32_t sx, // Bounding rectangle. + int32_t sy, + int32_t sw, + int32_t sh) +{ + int16_t sX = (int16_t)(*px); + int16_t sY = (int16_t)(*py); + int16_t sW = (int16_t)(*pw); + int16_t sH = (int16_t)(*ph); - int16_t sRes = ClipQuiet(&sX, &sY, &sW, &sH, - (int16_t)sx, (int16_t)sy, (int16_t)sw, (int16_t)sh); + int16_t sRes = ClipQuiet(&sX, &sY, &sW, &sH, + (int16_t)sx, (int16_t)sy, (int16_t)sw, (int16_t)sh); - *px = sX; - *py = sY; - *pw = sW; - *ph = sH; + *px = sX; + *py = sY; + *pw = sW; + *ph = sH; return sRes; - } - +} int16_t CompareModes(PVIDEO_MODE pvm1, PVIDEO_MODE pvm2); -extern void Disp_Init(void) // Returns nothing. +extern void Disp_Init(void) // Returns nothing. { - extern char **_argv; - const int arg = rspCommandLine("resolution"); - if ((arg) && (_argv[arg+1])) - { - if (SDL_sscanf(_argv[arg+1], "%dx%d", &RequestedWidth, &RequestedHeight) != 2) - RequestedWidth = RequestedHeight = 0; - } + extern char **_argv; + const int arg = rspCommandLine("resolution"); + if ((arg) && (_argv[arg + 1])) + { + if (SDL_sscanf(_argv[arg + 1], "%dx%d", &RequestedWidth, &RequestedHeight) != 2) + RequestedWidth = RequestedHeight = 0; + } - if ((RequestedWidth <= 0) || (RequestedHeight <= 0)) - { - if (rspCommandLine("windowed")) - { - RequestedWidth = 1024; - RequestedHeight = 768; - } - else - { - RequestedWidth = 0; - RequestedHeight = 0; - } - } + if ((RequestedWidth <= 0) || (RequestedHeight <= 0)) + { + if (rspCommandLine("windowed")) + { + RequestedWidth = 1024; + RequestedHeight = 768; + } + else + { + RequestedWidth = 0; + RequestedHeight = 0; + } + } // Initialize maps to indentities. int16_t i; for (i = 0; i < 256; i++) - { - au8MapRed[i] = i; - au8MapGreen[i] = i; - au8MapBlue[i] = i; - } + { + au8MapRed[i] = i; + au8MapGreen[i] = i; + au8MapBlue[i] = i; + } // Never ever ever unlock these. - asPalEntryLocks[0] = TRUE; - asPalEntryLocks[255] = TRUE; + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; slvmModes.SetCompareFunc(CompareModes); } extern void rspSetApplicationName( - char* pszName) // In: Application name + char *pszName) // In: Application name { - SDL_free(sdlAppName); - sdlAppName = SDL_strdup(pszName); - if (sdlWindow) - SDL_SetWindowTitle(sdlWindow, sdlAppName); + SDL_free(sdlAppName); + sdlAppName = SDL_strdup(pszName); + if (sdlWindow) + SDL_SetWindowTitle(sdlWindow, sdlAppName); } - ////////////////////////////////////////////////////////////////////////////// // // Compares two video modes in order of sColorDepth, sWidth, sHeight, @@ -284,204 +315,199 @@ extern void rspSetApplicationName( // Returns positive if *pvm1 > *pvm2. // ////////////////////////////////////////////////////////////////////////////// -extern int16_t CompareModes( // Returns as described above. - PVIDEO_MODE pvm1, // First video mode to compare. - PVIDEO_MODE pvm2) // Second video mode to compare. - { - int16_t sRes = 1; // Assume *pvm1 > *pvm2. +extern int16_t CompareModes( // Returns as described above. + PVIDEO_MODE pvm1, // First video mode to compare. + PVIDEO_MODE pvm2) // Second video mode to compare. +{ + int16_t sRes = 1; // Assume *pvm1 > *pvm2. if (pvm1->sColorDepth == pvm2->sColorDepth) - { + { if (pvm1->sWidth == pvm2->sWidth) - { + { if (pvm1->sHeight == pvm2->sHeight) - { + { if (pvm1->sPages == pvm2->sPages) - { + { sRes = 0; - } + } else - { + { if (pvm1->sPages < pvm2->sPages) - { + { sRes = -1; - } } } + } else - { + { if (pvm1->sHeight < pvm2->sHeight) - { + { sRes = -1; - } } } + } else - { + { if (pvm1->sWidth < pvm2->sWidth) - { + { sRes = -1; - } } } + } else - { + { if (pvm1->sColorDepth < pvm2->sColorDepth) - { + { sRes = -1; - } } - - return sRes; } - + return sRes; +} ////////////////////////////////////////////////////////////////////////////// // // Attempts to find a mode that is sWidth by sHeight or larger // with the given color depth. An available mode that closest matches -// the width and height is chosen, if successful. If no mode is found, +// the width and height is chosen, if successful. If no mode is found, // *psWidth, *psHeight. If psPixelDoubling is not NULL and *psPixelDoubling -// is TRUE, a mode may be returned that requires pixel doubling. If a +// is TRUE, a mode may be returned that requires pixel doubling. If a // mode requires pixel doubling, *psPixelDoubling will be TRUE on return; // otherwise, it will be FALSE. Passing psPixelDoubling as NULL is // equivalent to passing *psPixelDoubling with FALSE. -// Utilizes rspQueryVideoMode to find the mode. Does not affect the current +// Utilizes rspQueryVideoMode to find the mode. Does not affect the current // rspQueryVideoMode. // This function should not be a part of Blue. It is always implementable // via rspQueryVideoMode. // ////////////////////////////////////////////////////////////////////////////// extern int16_t rspSuggestVideoMode( // Returns 0 if successfull, non-zero otherwise - int16_t sDepth, // In: Required depth - int16_t sWidth, // In: Requested width - int16_t sHeight, // In: Requested height - int16_t sPages, // In: Required pages - int16_t sScaling, // In: Requested scaling - int16_t* psDeviceWidth /*= NULL*/, // Out: Suggested device width (unless NULL) - int16_t* psDeviceHeight /*= NULL*/, // Out: Suggested device height (unless NULL) - int16_t* psScaling /*= NULL*/) // Out: Suggested scaling (unless NULL) - { - int16_t sRes = 0; // Assume success. + int16_t sDepth, // In: Required depth + int16_t sWidth, // In: Requested width + int16_t sHeight, // In: Requested height + int16_t sPages, // In: Required pages + int16_t sScaling, // In: Requested scaling + int16_t *psDeviceWidth /*= NULL*/, // Out: Suggested device width (unless NULL) + int16_t *psDeviceHeight /*= NULL*/, // Out: Suggested device height (unless NULL) + int16_t *psScaling /*= NULL*/) // Out: Suggested scaling (unless NULL) +{ + int16_t sRes = 0; // Assume success. // Store video mode that the app is currently iterating. - PVIDEO_MODE pvmOldModeQuery = slvmModes.GetCurrent(); + PVIDEO_MODE pvmOldModeQuery = slvmModes.GetCurrent(); rspQueryVideoModeReset(); // Query results. - int16_t sModeWidth; - int16_t sModeHeight; + int16_t sModeWidth; + int16_t sModeHeight; int16_t sModeColorDepth; - int16_t sModePages; + int16_t sModePages; // Best results. - int16_t sBestModeWidth = 16380; - int16_t sBestModeHeight = 16380; - int16_t sModeFound = FALSE; + int16_t sBestModeWidth = 16380; + int16_t sBestModeHeight = 16380; + int16_t sModeFound = FALSE; while (rspQueryVideoMode(&sModeColorDepth, &sModeWidth, &sModeHeight, &sModePages) == 0) - { + { // Must be same color depth. if (sModeColorDepth == sDepth && sPages == sModePages) - { + { // If the desired resolution would fit into this mode . . . if (sWidth <= sModeWidth && sHeight <= sModeHeight) - { + { // If this mode is closer than a previous one . . . - float fFactorOld = ((float)sBestModeWidth * (float)sBestModeHeight) - / ((float)sWidth * (float)sHeight); - float fFactorNew = ((float)sModeWidth * (float)sModeHeight) - / ((float)sWidth * (float)sHeight); + float fFactorOld = ((float)sBestModeWidth * (float)sBestModeHeight) / ((float)sWidth * (float)sHeight); + float fFactorNew = ((float)sModeWidth * (float)sModeHeight) / ((float)sWidth * (float)sHeight); if (fFactorNew < fFactorOld) - { - sBestModeWidth = sModeWidth; - sBestModeHeight = sModeHeight; - sModeFound = TRUE; - } + { + sBestModeWidth = sModeWidth; + sBestModeHeight = sModeHeight; + sModeFound = TRUE; } } } + } // If we found an acceptable mode . . . if (sModeFound != FALSE) - { + { // If pixel doubling was specified . . . if (psScaling != NULL) - { + { // If pixel doubling is allowed . . . if (sScaling != FALSE) + { + // If the chosen mode is more than or equal to twice the + // requested mode . . . + if (sWidth * 2 <= sBestModeWidth && sHeight * 2 <= sBestModeHeight) { - // If the chosen mode is more than or equal to twice the - // requested mode . . . - if (sWidth * 2 <= sBestModeWidth - && sHeight * 2 <= sBestModeHeight) - { // Okay to pixel double. Leave *psPixelDoubling as TRUE. // Reduce best width and height appropriately. - sBestModeWidth /= 2; - sBestModeHeight /= 2; - } + sBestModeWidth /= 2; + sBestModeHeight /= 2; + } else - { + { // No pixel doubling possible for this mode. - *psScaling = FALSE; - } + *psScaling = FALSE; } } - - *psDeviceWidth = sBestModeWidth; - *psDeviceHeight = sBestModeHeight; } + + *psDeviceWidth = sBestModeWidth; + *psDeviceHeight = sBestModeHeight; + } else - { + { // Failed to find an acceptable mode. - sRes = 1; - } + sRes = 1; + } return sRes; - } +} ////////////////////////////////////////////////////////////////////////////// // // Puts parameters about the hardware video mode into your shorts. -// You may call this function even when in "no mode" (e.g., before +// You may call this function even when in "no mode" (e.g., before // rspSetVideoMode is first called, after it fails, or after rspKillVideMode // is called). This way you can get information on the user's current mode. // If in "no mode", psWidth, psHeight, and psPages will receive 0, if not NULL. // ////////////////////////////////////////////////////////////////////////////// extern int16_t rspGetVideoMode( - int16_t* psDeviceDepth, // Hardware display color depth returned here - // (unless NULL). - int16_t* psDeviceWidth, // Hardware display width returned here - // (unless NULL). - int16_t* psDeviceHeight, // Hardware display height returned here - // (unless NULL). - int16_t* psDevicePages, // Hardware display back buffers returned here - // (unless NULL). - int16_t* psWidth, // Display area width returned here - // (unless NULL). - int16_t* psHeight, // Display area height returned here - // (unless NULL). - int16_t* psPages/*= NULL*/, // Number of pages (1 to n) returned here - // (unless NULL). More than 1 indicates a - // page flipping scenario. - int16_t* psPixelScaling/*= NULL*/) // Pixel scaling in effect (1) or not (0) - // (unless NULL). + int16_t *psDeviceDepth, // Hardware display color depth returned here + // (unless NULL). + int16_t *psDeviceWidth, // Hardware display width returned here + // (unless NULL). + int16_t *psDeviceHeight, // Hardware display height returned here + // (unless NULL). + int16_t *psDevicePages, // Hardware display back buffers returned here + // (unless NULL). + int16_t *psWidth, // Display area width returned here + // (unless NULL). + int16_t *psHeight, // Display area height returned here + // (unless NULL). + int16_t *psPages /*= NULL*/, // Number of pages (1 to n) returned here + // (unless NULL). More than 1 indicates a + // page flipping scenario. + int16_t *psPixelScaling /*= NULL*/) // Pixel scaling in effect (1) or not (0) + // (unless NULL). { - // lie about everything. - SET(psPixelScaling, 0); - SET(psDevicePages, 0); - SET(psPages, 1); - SET(psWidth, FramebufferWidth); - SET(psHeight, FramebufferHeight); - SET(psDeviceDepth, 8); - SET(psDeviceHeight, FramebufferWidth); - SET(psDeviceWidth, FramebufferHeight); - - return 0; + // lie about everything. + SET(psPixelScaling, 0); + SET(psDevicePages, 0); + SET(psPages, 1); + SET(psWidth, FramebufferWidth); + SET(psHeight, FramebufferHeight); + SET(psDeviceDepth, 8); + SET(psDeviceHeight, FramebufferWidth); + SET(psDeviceWidth, FramebufferHeight); + + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -493,45 +519,45 @@ extern int16_t rspGetVideoMode( static void addMode(int w, int h, int depth) { - PVIDEO_MODE pvm; - - if (depth >= 8) - { - pvm = new VIDEO_MODE; - pvm->sWidth = w; - pvm->sHeight = h; - pvm->sColorDepth = 8; - pvm->sPages = 1; - slvmModes.Insert(pvm); - } + PVIDEO_MODE pvm; - if (depth >= 16) - { - pvm = new VIDEO_MODE; - pvm->sWidth = w; - pvm->sHeight = h; - pvm->sColorDepth = 16; - pvm->sPages = 1; - slvmModes.Insert(pvm); - } + if (depth >= 8) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 8; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } - if (depth >= 24) - { - pvm = new VIDEO_MODE; - pvm->sWidth = w; - pvm->sHeight = h; - pvm->sColorDepth = 32; - pvm->sPages = 1; - slvmModes.Insert(pvm); - } + if (depth >= 16) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 16; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } + + if (depth >= 24) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 32; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } } extern void rspQueryVideoModeReset(void) { - static bool enumerated = false; - if (!enumerated) - { - ASSERT(SDL_WasInit(SDL_INIT_VIDEO)); + static bool enumerated = false; + if (!enumerated) + { + ASSERT(SDL_WasInit(SDL_INIT_VIDEO)); // Attempt to grab user's current desktop resolution instead of forcing 640x480 #ifndef MOBILE @@ -543,8 +569,8 @@ extern void rspQueryVideoModeReset(void) #endif addMode(640, 480, 8); - enumerated = true; - } + enumerated = true; + } slvmModes.GetHead(); } @@ -560,74 +586,72 @@ extern void rspQueryVideoModeReset(void) // non-zero, the other parameters are not updated. // ////////////////////////////////////////////////////////////////////////////// -extern int16_t rspQueryVideoMode( // Returns 0 for each valid mode, then non-zero thereafter - int16_t* psColorDepth, // Color depth (8, 15, 16, 24, 32) - // Unless NULL. - int16_t* psWidth /*= NULL*/, // Width returned here - // Unless NULL. - int16_t* psHeight /*= NULL*/, // Height returned here - // Unless NULL. - int16_t* psPages /*= NULL*/) // Number of video pages possible. - { - int16_t sRes = 0; // Assume success. +extern int16_t rspQueryVideoMode( // Returns 0 for each valid mode, then non-zero thereafter + int16_t *psColorDepth, // Color depth (8, 15, 16, 24, 32) + // Unless NULL. + int16_t *psWidth /*= NULL*/, // Width returned here + // Unless NULL. + int16_t *psHeight /*= NULL*/, // Height returned here + // Unless NULL. + int16_t *psPages /*= NULL*/) // Number of video pages possible. +{ + int16_t sRes = 0; // Assume success. - PVIDEO_MODE pvm = slvmModes.GetCurrent(); + PVIDEO_MODE pvm = slvmModes.GetCurrent(); if (pvm != NULL) - { - SET(psColorDepth, pvm->sColorDepth); - SET(psWidth, pvm->sWidth); - SET(psHeight, pvm->sHeight); + { + SET(psColorDepth, pvm->sColorDepth); + SET(psWidth, pvm->sWidth); + SET(psHeight, pvm->sHeight); - SET(psPages, pvm->sPages); + SET(psPages, pvm->sPages); // Goto next video mode. slvmModes.GetNext(); - } + } else - { + { sRes = 1; - } - - return sRes; } + return sRes; +} static SDL_Renderer *createRendererToggleVsync(SDL_Window *window, const int index, bool vsync) { - SDL_Renderer *retval = NULL; - + SDL_Renderer *retval = NULL; + #if defined(SWITCH) || defined(PSP) fprintf(stderr, ">> Create SDL_RENDERER_SOFTWARE %s\n", SDL_GetError()); retval = SDL_CreateRenderer(window, index, SDL_RENDERER_SOFTWARE); #else - if (vsync) - retval = SDL_CreateRenderer(window, index, SDL_RENDERER_PRESENTVSYNC); - if (!retval) - retval = SDL_CreateRenderer(window, index, 0); -#endif - return retval; + if (vsync) + retval = SDL_CreateRenderer(window, index, SDL_RENDERER_PRESENTVSYNC); + if (!retval) + retval = SDL_CreateRenderer(window, index, 0); +#endif + return retval; } static SDL_Renderer *createRendererByName(SDL_Window *window, const char *name) { - const bool vsync = !rspCommandLine("novsync"); - if (name == NULL) - return createRendererToggleVsync(window, -1, vsync); - else - { - const int max = SDL_GetNumRenderDrivers(); - for (int i = 0; i < max; i++) - { - SDL_RendererInfo info; - if ((SDL_GetRenderDriverInfo(i, &info) == 0) && (SDL_strcmp(info.name, name) == 0)) - return createRendererToggleVsync(window, i, vsync); - } - } - return NULL; + const bool vsync = !rspCommandLine("novsync"); + if (name == NULL) + return createRendererToggleVsync(window, -1, vsync); + else + { + const int max = SDL_GetNumRenderDrivers(); + for (int i = 0; i < max; i++) + { + SDL_RendererInfo info; + if ((SDL_GetRenderDriverInfo(i, &info) == 0) && (SDL_strcmp(info.name, name) == 0)) + return createRendererToggleVsync(window, i, vsync); + } + } + return NULL; } - ////////////////////////////////////////////////////////////////////////////// // // Set a new video mode. Specified color depth, width, and height for the @@ -638,7 +662,7 @@ static SDL_Renderer *createRendererByName(SDL_Window *window, const char *name) // display areas; instead, the previous buffer is destroyed and a new buffer // is created to take it's place. // If pixel doubling is allowed (with rspAllowPixelDoubling) and the requested -// display area is less than or equal to half the requested hardware resolution, +// display area is less than or equal to half the requested hardware resolution, // pixel doubling will be activated. // If this function fails, you will be in no mode; meaning you may not access // the display (i.e., call display/palette functions) even if you were in a mode @@ -647,141 +671,195 @@ static SDL_Renderer *createRendererByName(SDL_Window *window, const char *name) // the display. // ////////////////////////////////////////////////////////////////////////////// -extern int16_t rspSetVideoMode( // Returns 0 if successfull, non-zero otherwise - int16_t sDeviceDepth, // Specify required device video depth here. - int16_t sDeviceWidth, // Specify required device resolution width here. - int16_t sDeviceHeight, // Specify required device resolution height here. - int16_t sWidth, // Specify width of display area on screen. - int16_t sHeight, // Specify height of display area on screen. - int16_t sPages /*= 1*/, // Specify number of video pages. More than 1 - // indicates a page flipping scenario. - int16_t sPixelDoubling /*= FALSE*/) - // TRUE indicates to set the video mode - // to twice that indicated by sDeviceWidth, - // sDeviceHeight and double the coordinate - // system and blts. - // FALSE indicates not to use this garbage. +extern int16_t rspSetVideoMode( // Returns 0 if successfull, non-zero otherwise + int16_t sDeviceDepth, // Specify required device video depth here. + int16_t sDeviceWidth, // Specify required device resolution width here. + int16_t sDeviceHeight, // Specify required device resolution height here. + int16_t sWidth, // Specify width of display area on screen. + int16_t sHeight, // Specify height of display area on screen. + int16_t sPages /*= 1*/, // Specify number of video pages. More than 1 + // indicates a page flipping scenario. + int16_t sPixelDoubling /*= FALSE*/) +// TRUE indicates to set the video mode +// to twice that indicated by sDeviceWidth, +// sDeviceHeight and double the coordinate +// system and blts. +// FALSE indicates not to use this garbage. +{ + TRACE("rspSetVideoMode(%i, %i, %i, %i, %i, %i, %i)\n", sDeviceDepth, sDeviceWidth, sDeviceHeight, sWidth, sHeight, sPages, sPixelDoubling); + ASSERT(sDeviceDepth == 8); + // ASSERT(sDeviceWidth == 0); + // ASSERT(sDeviceHeight == 0); + // ASSERT(sWidth == 640); + ASSERT(sHeight == 480); + + for (size_t i = 0; i < 256; i++) + apeApp[i].a = 0xFF; + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + + if (sPixelDoubling) { - TRACE("rspSetVideoMode(%i, %i, %i, %i, %i, %i, %i)\n", sDeviceDepth, sDeviceWidth, sDeviceHeight, sWidth, sHeight, sPages, sPixelDoubling); - ASSERT(sDeviceDepth == 8); - //ASSERT(sDeviceWidth == 0); - //ASSERT(sDeviceHeight == 0); - //ASSERT(sWidth == 640); - ASSERT(sHeight == 480); - - for (size_t i = 0; i < 256; i++) - apeApp[i].a = 0xFF; - - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - - if (sPixelDoubling) - { - fprintf(stderr, "STUBBED: pixel doubling? %s:%d\n", __FILE__, __LINE__); - return -1; - } + fprintf(stderr, "STUBBED: pixel doubling? %s:%d\n", __FILE__, __LINE__); + return -1; + } - FramebufferWidth = sWidth; - FramebufferHeight = sHeight; + FramebufferWidth = sWidth; + FramebufferHeight = sHeight; - mouse_grabbed = !rspCommandLine("nomousegrab"); + mouse_grabbed = !rspCommandLine("nomousegrab"); - Uint32 flags = 0; - if (!rspCommandLine("windowed")) - { - if ((!RequestedWidth) || (!RequestedHeight)) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - else - flags |= SDL_WINDOW_FULLSCREEN; - } + Uint32 flags = 0; + if (!rspCommandLine("windowed")) + { + if ((!RequestedWidth) || (!RequestedHeight)) + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + else + flags |= SDL_WINDOW_FULLSCREEN; + } - if (mouse_grabbed) - flags |= SDL_WINDOW_INPUT_GRABBED; + if (mouse_grabbed) + flags |= SDL_WINDOW_INPUT_GRABBED; #if PLATFORM_IOS - flags |= SDL_WINDOW_BORDERLESS; // don't show the status bar + flags |= SDL_WINDOW_BORDERLESS; // don't show the status bar #endif - TRACE("RequestedWidth %d RequestedHeight %d\n",RequestedWidth,RequestedHeight); - - const char *title = sdlAppName ? sdlAppName : ""; - sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sWidth, sHeight, SDL_WINDOW_FULLSCREEN); - if (!sdlWindow) - { - char buf[128]; - SDL_snprintf(buf, sizeof (buf), "Couldn't create window: %s.", SDL_GetError()); - fprintf(stderr, "POSTAL: %s\n", buf); - SDL_Quit(); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); - exit(1); - } - int w = 0, h = 0; - SDL_GetWindowSize(sdlWindow, &w, &h); - TRACE("SDL Window initialized at %ix%i\n", w, h); - - bool bRequestedRenderer = true; - if (rspCommandLine("direct3d")) - sdlRenderer = createRendererByName(sdlWindow, "direct3d"); - else if (rspCommandLine("opengl")) - sdlRenderer = createRendererByName(sdlWindow, "opengl"); - else if (rspCommandLine("software")) - sdlRenderer = createRendererByName(sdlWindow, "software"); - else - { - bRequestedRenderer = false; - sdlRenderer = createRendererByName(sdlWindow, NULL); - } + TRACE("RequestedWidth %d RequestedHeight %d\n", RequestedWidth, RequestedHeight); - if (!sdlRenderer) - { - char buf[128]; - SDL_snprintf(buf, sizeof (buf), "Couldn't create %s renderer: %s", bRequestedRenderer ? "requested" : "a", SDL_GetError()); - fprintf(stderr, "POSTAL: %s\n", buf); - SDL_DestroyWindow(sdlWindow); - sdlWindow = NULL; - SDL_Quit(); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); - exit(1); - } + const char *title = sdlAppName ? sdlAppName : ""; + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sWidth, sHeight, SDL_WINDOW_FULLSCREEN); + if (!sdlWindow) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create window: %s.", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + int w = 0, h = 0; + SDL_GetWindowSize(sdlWindow, &w, &h); + TRACE("SDL Window initialized at %ix%i\n", w, h); + + bool bRequestedRenderer = true; + if (rspCommandLine("direct3d")) + sdlRenderer = createRendererByName(sdlWindow, "direct3d"); + else if (rspCommandLine("opengl")) + sdlRenderer = createRendererByName(sdlWindow, "opengl"); + else if (rspCommandLine("software")) + sdlRenderer = createRendererByName(sdlWindow, "software"); + else + { + bRequestedRenderer = false; + sdlRenderer = createRendererByName(sdlWindow, NULL); + } + + if (!sdlRenderer) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create %s renderer: %s", bRequestedRenderer ? "requested" : "a", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + TRACE("blah\n"); + + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); +#ifndef MOBILE // Need to remove this for the mouse point to be in the correct place, Android And IOS + // SDL_RenderSetLogicalSize(sdlRenderer, FramebufferWidth, FramebufferHeight); + TRACE("SDL Renderer set: %ix%i\n", FramebufferWidth, FramebufferHeight); + +// https://pspdev.github.io/basic_programs.html +#define BUFFER_WIDTH 512 +#define BUFFER_HEIGHT 272 +#define SCREEN_WIDTH 480 +#define SCREEN_HEIGHT BUFFER_HEIGHT + // setup GU + + pspDebugScreenInit(); + // setupCallbacks(); + + // Setup GU + void *fbp0 = guGetStaticVramBuffer(BUFFER_WIDTH, SCREEN_HEIGHT, GU_PSM_8888); + void *fbp1 = guGetStaticVramBuffer(BUFFER_WIDTH, SCREEN_HEIGHT, GU_PSM_8888); + + sceGuInit(); + + // Set up buffers + sceGuStart(GU_DIRECT, list); + sceGuDrawBuffer(GU_PSM_8888, fbp0, BUFFER_WIDTH); + sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, fbp1, BUFFER_WIDTH); + + // We do not care about the depth buffer in this example + sceGuDepthBuffer(fbp0, 0); // Set depth buffer to a length of 0 + sceGuDisable(GU_DEPTH_TEST); // Disable depth testing + + // Set up viewport + sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2)); + sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT); + sceGuEnable(GU_SCISSOR_TEST); + sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + + // Start a new frame and enable the display + sceGuFinish(); + sceGuDisplay(GU_TRUE); + + TexturePointer = new uint32_t[512 * 512]; + if (!TexturePointer) + { + fprintf(stderr, "Error: Unable to allocate VRAM for texture.\n"); + exit(1); + } + + PalettedTexturePointer = new uint8_t[FramebufferWidth * FramebufferHeight]; + if (!PalettedTexturePointer) + { + fprintf(stderr, "Error: Unable to allocate memory for palette data.\n"); + exit(1); + } -TRACE("blah\n"); + // init stuff + memset(TexturePointer, 0, FramebufferWidth * FramebufferHeight * sizeof(uint32_t)); + memset(PalettedTexturePointer, 0, FramebufferWidth * FramebufferHeight * sizeof(uint8_t)); + fprintf(stderr, "Texture and palette data successfully initialized.\n"); - SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); - SDL_RenderClear(sdlRenderer); - SDL_RenderPresent(sdlRenderer); - SDL_RenderClear(sdlRenderer); - SDL_RenderPresent(sdlRenderer); - SDL_RenderClear(sdlRenderer); - SDL_RenderPresent(sdlRenderer); -#ifndef MOBILE //Need to remove this for the mouse point to be in the correct place, Android And IOS - //SDL_RenderSetLogicalSize(sdlRenderer, FramebufferWidth, FramebufferHeight); - TRACE("SDL Renderer set: %ix%i\n", FramebufferWidth, FramebufferHeight); #endif - sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 512, 512); - if (!sdlTexture) - { - char buf[128]; - SDL_snprintf(buf, sizeof (buf), "Couldn't create texture: %s", SDL_GetError()); - fprintf(stderr, "POSTAL: %s\n", buf); - SDL_DestroyRenderer(sdlRenderer); - sdlRenderer = NULL; - SDL_DestroyWindow(sdlWindow); - sdlWindow = NULL; - SDL_Quit(); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); - exit(1); - } + sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 512, 512); + if (!sdlTexture) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create texture: %s", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyRenderer(sdlRenderer); + sdlRenderer = NULL; + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } - TexturePointer = new Uint32[FramebufferWidth * FramebufferHeight]; - PalettedTexturePointer = new Uint8[FramebufferWidth * FramebufferHeight]; - SDL_memset(TexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof (Uint32)); - SDL_memset(PalettedTexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof (Uint8)); - SDL_UpdateTexture(sdlTexture, NULL, TexturePointer, FramebufferWidth * 4); + TexturePointer = new Uint32[FramebufferWidth * FramebufferHeight]; + PalettedTexturePointer = new Uint8[FramebufferWidth * FramebufferHeight]; + SDL_memset(TexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof(Uint32)); + SDL_memset(PalettedTexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof(Uint8)); + SDL_UpdateTexture(sdlTexture, NULL, TexturePointer, FramebufferWidth * 4); - SDL_ShowCursor(0); - //SDL_SetRelativeMouseMode(mouse_grabbed ? SDL_TRUE : SDL_FALSE); + SDL_ShowCursor(0); + // SDL_SetRelativeMouseMode(mouse_grabbed ? SDL_TRUE : SDL_FALSE); - return 0; - } + return 0; +} ////////////////////////////////////////////////////////////////////////////// // @@ -792,24 +870,24 @@ TRACE("blah\n"); // ////////////////////////////////////////////////////////////////////////////// extern void rspKillVideoMode(void) - { - /* no-op ... SDL_Quit() will catch this. */ - } +{ + /* no-op ... SDL_Quit() will catch this. */ +} ////////////////////////////////////////////////////////////////////////////// // // Frees the memory (and, perhaps, structure(s)) associated with the memory -// stored in system RAM that is allocate rspSetVideoMode. If you are not -// using the system buffer (i.e., you are not calling rspLockVideoBuffer), -// you can call this to free up some additional memory. Calls to -// rspLockVideoBuffer will fail after a call to this function without a +// stored in system RAM that is allocate rspSetVideoMode. If you are not +// using the system buffer (i.e., you are not calling rspLockVideoBuffer), +// you can call this to free up some additional memory. Calls to +// rspLockVideoBuffer will fail after a call to this function without a // subsequent call to rspSetVideoMode. // ////////////////////////////////////////////////////////////////////////////// extern void rspKillVideoBuffer(void) - { - /* no-op ... SDL_Quit() will catch this. */ - } +{ + /* no-op ... SDL_Quit() will catch this. */ +} ////////////////////////////////////////////////////////////////////////////// // @@ -820,122 +898,244 @@ extern void rspKillVideoBuffer(void) extern void rspUpdateDisplayRects(void) { - // no-op, just blast it all to the GPU. + // no-op, just blast it all to the GPU. } extern void rspCacheDirtyRect( - int16_t sX, // x coord of upper-left corner of area to update - int16_t sY, // y coord of upper-left corner of area to update - int16_t sWidth, // Width of area to update - int16_t sHeight) // Height of area to update + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update { } -bool ValidateFrame(Uint32* frameBuffer, int width, int height) { - // Simple validation logic (customize based on your distortion patterns) - int invalidPixelCount = 0; - const int threshold = (width * height) / 10; // Example: 10% of pixels can be invalid +bool ValidateFrame(Uint32 *frameBuffer, int width, int height) +{ + // Simple validation logic (customize based on your distortion patterns) + int invalidPixelCount = 0; + const int threshold = (width * height) / 10; // Example: 10% of pixels can be invalid - for (int i = 0; i < width * height; i++) { - Uint32 pixel = frameBuffer[i]; + for (int i = 0; i < width * height; i++) + { + Uint32 pixel = frameBuffer[i]; - // Check for corruption (e.g., all pixels are the same or too many black pixels) - Uint8 r, g, b, a; - SDL_GetRGBA(pixel, SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888), &r, &g, &b, &a); + // Check for corruption (e.g., all pixels are the same or too many black pixels) + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888), &r, &g, &b, &a); - if (r == 0 && g == 0 && b == 0 && a == 255) { // Example: fully black pixels - invalidPixelCount++; - } + if (r == 0 && g == 0 && b == 0 && a == 255) + { // Example: fully black pixels + invalidPixelCount++; + } + + if (invalidPixelCount > threshold) + { + return false; // Frame is distorted + } + } + return true; // Frame is valid +} + +SDL_Surface *frameSurface = NULL; +SDL_Surface *scaledSurface = NULL; + +void drawTexture(Texture *texture, float x, float y, float w, float h) +{ +typedef struct { + float u, v; // Texture coordinates + unsigned int color; // Vertex color + float x, y, z; // Screen coordinates +} Vertex; + +Vertex vertices[2]; + +// Top-left corner +vertices[0].u = 0.0f; +vertices[0].v = 0.0f; +vertices[0].color = 0xFFFFFFFF; +vertices[0].x = 0.0f; +vertices[0].y = 0.0f; +vertices[0].z = 0.0f; + +// Bottom-right corner +vertices[1].u = (float)480; // Use scaled width +vertices[1].v = (float)272; // Use scaled height +vertices[1].color = 0xFFFFFFFF; +vertices[1].x = 480.0f; +vertices[1].y = 272.0f; +vertices[1].z = 0.0f; + + +sceGuTexMode(GU_PSM_8888, 0, 0, GU_FALSE); +sceGuTexImage(0, 512, 272, 512, TexturePointer); +sceGuTexWrap(GU_CLAMP, GU_CLAMP); +sceGuTexScale((float)480 / 512.0f, (float)272 / 512.0f); // Scale UVs correctly + +sceGuEnable(GU_TEXTURE_2D); +sceGuDrawArray(GU_SPRITES, GU_COLOR_8888 | GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices); +sceGuDisable(GU_TEXTURE_2D); - if (invalidPixelCount > threshold) { - return false; // Frame is distorted - } - } - return true; // Frame is valid } -SDL_Surface* frameSurface = NULL; -SDL_Surface* scaledSurface = NULL; extern void rspPresentFrame(void) { - if (!sdlWindow) return; +if (!sdlWindow) + return; + +ASSERT(sizeof(apeApp[0]) == sizeof(uint32_t)); + +// update texture data +/*const Uint8 *src = PalettedTexturePointer; +Uint32 *dst = TexturePointer; +for (int y = 0; y < FramebufferHeight; y++) { + for (int x = 0; x < FramebufferWidth; x++, src++, dst++) { + ArgbColor color = apeApp[*src]; + Uint8 r = color.r; + Uint8 g = color.g; + Uint8 b = color.b; + Uint8 a = color.a; + + *dst = (a << 24) | (b << 16) | (g << 8) | r; // BGRA + } +}*/ - // !!! FIXME: I imagine this is not fast. Maybe keep the dirty rect code at least? - ASSERT(sizeof (apeApp[0]) == sizeof (Uint32)); const Uint8 *src = PalettedTexturePointer; - Uint32 *dst = TexturePointer; - for (int y = 0; y < FramebufferHeight; y++) - { - for (int x = 0; x < FramebufferWidth; x++, src++, dst++) - *dst = apeApp[*src].argb; - } - - int srcWidth = 640, srcHeight = 480; - int dstWidth = 480, dstHeight = 272; - - if (!frameSurface) { - frameSurface = SDL_CreateRGBSurfaceFrom( - TexturePointer, srcWidth, srcHeight, 32, - FramebufferWidth * 4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 - ); - if (!frameSurface) { - fprintf(stderr, "Failed to create SDL_Surface: %s\n", SDL_GetError()); - return; + Uint32 *dst = TexturePointer; + int scaledWidth = 480; + int scaledHeight = 272; + + for (int y = 0; y < scaledHeight; y++) { + int srcY = (y * FramebufferHeight) / scaledHeight; + const Uint8 *srcRow = src + (srcY * FramebufferWidth); + + for (int x = 0; x < scaledWidth; x++, dst++) { + int srcX = (x * FramebufferWidth) / scaledWidth; + Uint8 paletteIndex = srcRow[srcX]; + ArgbColor color = apeApp[paletteIndex]; + *dst = (color.a << 24) | (color.b << 16) | (color.g << 8) | color.r; } + dst += (512 - scaledWidth); // Align to 512 width } - if (!scaledSurface) { - scaledSurface = SDL_CreateRGBSurfaceWithFormat(0, dstWidth, dstHeight, 32, SDL_PIXELFORMAT_ARGB8888); - if (!scaledSurface) { - fprintf(stderr, "Failed to create scaled SDL_Surface: %s\n", SDL_GetError()); - SDL_FreeSurface(frameSurface); - return; - } - } - SDL_Rect srcRect = {0, 0, srcWidth, srcHeight}; - SDL_Rect dstRect = {0, 0, dstWidth, dstHeight}; - if (SDL_BlitScaled(frameSurface, &srcRect, scaledSurface, &dstRect) != 0) { - fprintf(stderr, "Failed to scale SDL_Surface: %s\n", SDL_GetError()); - return; - } - SDL_Texture* frameTexture = SDL_CreateTextureFromSurface(sdlRenderer, scaledSurface); - if (!frameTexture) { - fprintf(stderr, "Failed to create SDL_Texture: %s\n", SDL_GetError()); - return; - } +fprintf(stderr, "FramebufferWidth: %d, FramebufferHeight: %d\n", FramebufferWidth, FramebufferHeight); +if (!TexturePointer || !apeApp) { + fprintf(stderr, "Error: TexturePointer or apeApp is NULL.\n"); + return; +} + +// create texture +Texture myTexture = { + .width = FramebufferWidth, + .height = FramebufferHeight, + .data = TexturePointer +}; + +// begin +sceGuStart(GU_DIRECT, list); + +// clear +//sceGuClearColor(GU_RGBA(255, 255, 255, 255)); // white +//sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT); + +// Set the buffer correctly +void* framebuffer = 0; +sceGuDrawBuffer(GU_PSM_8888, framebuffer, 512); + +// Draw texture to framebuffer +sceGuCopyImage(GU_PSM_8888, 0, 0, 480, 272, 512, TexturePointer, 0, 0, 512, (void*)(((unsigned int)framebuffer)+0x4000000)); +sceGuTexSync(); + +// Finish rendering and wait for VBlank +sceGuFinish(); +sceGuSync(0, 0); +sceDisplayWaitVblankStart(); +sceDisplaySetFrameBuf(framebuffer, 512, GU_PSM_8888, PSP_DISPLAY_SETBUF_NEXTFRAME); + +// Swap buffers after waiting for VBlank +framebuffer = sceGuSwapBuffers(); + +// Optional: Limit frame rate +//sceKernelDelayThread(16667); + + /* + // !!! FIXME: I imagine this is not fast. Maybe keep the dirty rect code at least? + ASSERT(sizeof (apeApp[0]) == sizeof (Uint32)); + const Uint8 *src = PalettedTexturePointer; + Uint32 *dst = TexturePointer; + for (int y = 0; y < FramebufferHeight; y++) + { + for (int x = 0; x < FramebufferWidth; x++, src++, dst++) + *dst = apeApp[*src].argb; + } + + int srcWidth = 640, srcHeight = 480; + int dstWidth = 480, dstHeight = 272; + + if (!frameSurface) { + frameSurface = SDL_CreateRGBSurfaceFrom( + TexturePointer, srcWidth, srcHeight, 32, + FramebufferWidth * 4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 + ); + if (!frameSurface) { + fprintf(stderr, "Failed to create SDL_Surface: %s\n", SDL_GetError()); + return; + } + } - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, frameTexture, NULL, NULL); - SDL_RenderPresent(sdlRenderer); + if (!scaledSurface) { + scaledSurface = SDL_CreateRGBSurfaceWithFormat(0, dstWidth, dstHeight, 32, SDL_PIXELFORMAT_ARGB8888); + if (!scaledSurface) { + fprintf(stderr, "Failed to create scaled SDL_Surface: %s\n", SDL_GetError()); + SDL_FreeSurface(frameSurface); + return; + } + } - SDL_DestroyTexture(frameTexture); + SDL_Rect srcRect = {0, 0, srcWidth, srcHeight}; + SDL_Rect dstRect = {0, 0, dstWidth, dstHeight}; + if (SDL_BlitScaled(frameSurface, &srcRect, scaledSurface, &dstRect) != 0) { + fprintf(stderr, "Failed to scale SDL_Surface: %s\n", SDL_GetError()); + return; + } - static Uint32 lastframeticks = 0; - const Uint32 now = SDL_GetTicks(); + SDL_Texture* frameTexture = SDL_CreateTextureFromSurface(sdlRenderer, scaledSurface); + if (!frameTexture) { + fprintf(stderr, "Failed to create SDL_Texture: %s\n", SDL_GetError()); + return; + } - if ((lastframeticks) && (lastframeticks <= now)) - { - const Uint32 elapsed = (now - lastframeticks); - if (elapsed <= 5) // going WAY too fast, maybe OpenGL (and/or no vsync)? - SDL_Delay(16 - elapsed); // try to get closer to 60fps. - } + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, frameTexture, NULL, NULL); + SDL_RenderPresent(sdlRenderer); - lastframeticks = now; - - //#if 0 - static Uint32 ticks = 0; - static Uint32 frames = 0; - frames++; - if ((now - ticks) > 5000) - { - if (ticks > 0) - printf("fps: %f\n", (((double) frames) / ((double) (now - ticks))) * 1000.0); - ticks = now; - frames = 0; - } - //#endif + SDL_DestroyTexture(frameTexture); + */ + static Uint32 lastframeticks = 0; + const Uint32 now = SDL_GetTicks(); + + if ((lastframeticks) && (lastframeticks <= now)) + { + const Uint32 elapsed = (now - lastframeticks); + if (elapsed <= 5) // going WAY too fast, maybe OpenGL (and/or no vsync)? + SDL_Delay(16 - elapsed); // try to get closer to 60fps. + } + + lastframeticks = now; + + // #if 0 + static Uint32 ticks = 0; + static Uint32 frames = 0; + frames++; + if ((now - ticks) > 5000) + { + if (ticks > 0) + printf("fps: %f\n", (((double)frames) / ((double)(now - ticks))) * 1000.0); + ticks = now; + frames = 0; + } + // #endif } extern void rspUpdateDisplay(void) @@ -949,10 +1149,10 @@ extern void rspUpdateDisplay(void) // /////////////////////////////////////////////////////////////////////////////// extern void rspUpdateDisplay( - int16_t sX, // x coord of upper-left corner of area to update - int16_t sY, // y coord of upper-left corner of area to update - int16_t sWidth, // Width of area to update - int16_t sHeight) // Height of area to update + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update { } @@ -962,15 +1162,15 @@ extern void rspUpdateDisplay( // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern int16_t rspLockVideoPage( // Returns 0 if screen memory could be locked. - // Returns non-zero otherwise. - void** ppvMemory, // Pointer to display memory returned here. - // NULL returned if not supported. - int32_t* plPitch) // Pitch of display memory returned here. - { +extern int16_t rspLockVideoPage( // Returns 0 if screen memory could be locked. + // Returns non-zero otherwise. + void **ppvMemory, // Pointer to display memory returned here. + // NULL returned if not supported. + int32_t *plPitch) // Pitch of display memory returned here. +{ /* no-op. */ return 1; - } +} /////////////////////////////////////////////////////////////////////////////// // @@ -978,10 +1178,10 @@ extern int16_t rspLockVideoPage( // Returns 0 if screen memory could be locked. // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern void rspUnlockVideoPage(void) // Returns nothing. - { +extern void rspUnlockVideoPage(void) // Returns nothing. +{ /* no-op. */ - } +} /////////////////////////////////////////////////////////////////////////////// // @@ -989,14 +1189,14 @@ extern void rspUnlockVideoPage(void) // Returns nothing. // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern int16_t rspLockVideoFlipPage( // Returns 0 if flip screen memory could be - // locked. Returns non-zero otherwise. - void** ppvMemory, // Pointer to flip screen memory returned here. - // NULL returned on failure. - int32_t* plPitch) // Pitch of flip screen memory returned here. - { +extern int16_t rspLockVideoFlipPage( // Returns 0 if flip screen memory could be + // locked. Returns non-zero otherwise. + void **ppvMemory, // Pointer to flip screen memory returned here. + // NULL returned on failure. + int32_t *plPitch) // Pitch of flip screen memory returned here. +{ return -1; - } +} /////////////////////////////////////////////////////////////////////////////// // @@ -1004,9 +1204,9 @@ extern int16_t rspLockVideoFlipPage( // Returns 0 if flip screen memory could be // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern void rspUnlockVideoFlipPage(void) // Returns nothing. - { - } +extern void rspUnlockVideoFlipPage(void) // Returns nothing. +{ +} /////////////////////////////////////////////////////////////////////////////// // @@ -1014,20 +1214,20 @@ extern void rspUnlockVideoFlipPage(void) // Returns nothing. // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern int16_t rspLockVideoBuffer( // Returns 0 if system buffer could be locked. - // Returns non-zero otherwise. - void** ppvBuffer, // Pointer to system buffer returned here. - // NULL returned on failure. - int32_t* plPitch) // Pitch of system buffer returned here. - { - if (!sdlWindow) - return -1; +extern int16_t rspLockVideoBuffer( // Returns 0 if system buffer could be locked. + // Returns non-zero otherwise. + void **ppvBuffer, // Pointer to system buffer returned here. + // NULL returned on failure. + int32_t *plPitch) // Pitch of system buffer returned here. +{ + if (!sdlWindow) + return -1; - *ppvBuffer = PalettedTexturePointer; - *plPitch = FramebufferWidth; + *ppvBuffer = PalettedTexturePointer; + *plPitch = FramebufferWidth; - return(0); - } + return (0); +} /////////////////////////////////////////////////////////////////////////////// // @@ -1035,9 +1235,9 @@ extern int16_t rspLockVideoBuffer( // Returns 0 if system buffer could be locked // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern void rspUnlockVideoBuffer(void) // Returns nothing. - { - } +extern void rspUnlockVideoBuffer(void) // Returns nothing. +{ +} /////////////////////////////////////////////////////////////////////////////// // @@ -1045,10 +1245,10 @@ extern void rspUnlockVideoBuffer(void) // Returns nothing. // See function comment in appropriate CPP (BGDisp/BXDisp). // /////////////////////////////////////////////////////////////////////////////// -extern int16_t rspAllowPageFlip(void) // Returns 0 on success. - { +extern int16_t rspAllowPageFlip(void) // Returns 0 on success. +{ return 0; - } +} ////////////////////////////////////////////////////////////////////////////// // External Palette module functions. @@ -1063,41 +1263,41 @@ extern int16_t rspAllowPageFlip(void) // Returns 0 on success. // /////////////////////////////////////////////////////////////////////////////// extern void rspSetPaletteEntries( - int16_t sStartIndex, // Palette entry to start copying to (has no effect on source!) - int16_t sCount, // Number of palette entries to do - uint8_t* pucRed, // Pointer to first red component to copy from - uint8_t* pucGreen, // Pointer to first green component to copy from - uint8_t* pucBlue, // Pointer to first blue component to copy from - int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy - { + int16_t sStartIndex, // Palette entry to start copying to (has no effect on source!) + int16_t sCount, // Number of palette entries to do + uint8_t *pucRed, // Pointer to first red component to copy from + uint8_t *pucGreen, // Pointer to first green component to copy from + uint8_t *pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ // Set up destination pointers. - uint8_t* pucDstRed = &(apeApp[sStartIndex].r); - uint8_t* pucDstGreen = &(apeApp[sStartIndex].g); - uint8_t* pucDstBlue = &(apeApp[sStartIndex].b); + uint8_t *pucDstRed = &(apeApp[sStartIndex].r); + uint8_t *pucDstGreen = &(apeApp[sStartIndex].g); + uint8_t *pucDstBlue = &(apeApp[sStartIndex].b); // Set up lock pointer. - int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); while (sCount-- > 0) - { + { if (*psLock++ == 0) - { - *pucDstRed = *pucRed; - *pucDstGreen = *pucGreen; - *pucDstBlue = *pucBlue; - } + { + *pucDstRed = *pucRed; + *pucDstGreen = *pucGreen; + *pucDstBlue = *pucBlue; + } // Increment source. - pucRed += lIncBytes; - pucGreen += lIncBytes; - pucBlue += lIncBytes; + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; // Increment destination. - pucDstRed += sizeof(apeApp[0]); - pucDstGreen += sizeof(apeApp[0]); - pucDstBlue += sizeof(apeApp[0]); - } + pucDstRed += sizeof(apeApp[0]); + pucDstGreen += sizeof(apeApp[0]); + pucDstBlue += sizeof(apeApp[0]); } +} /////////////////////////////////////////////////////////////////////////////// // @@ -1106,20 +1306,20 @@ extern void rspSetPaletteEntries( // /////////////////////////////////////////////////////////////////////////////// void rspSetPaletteEntry( - int16_t sEntry, // Palette entry (0 to 255) - uint8_t ucRed, // Red component (0 to 255) - uint8_t ucGreen, // Green component (0 to 255) - uint8_t ucBlue) // Blue component (0 to 255) - { + int16_t sEntry, // Palette entry (0 to 255) + uint8_t ucRed, // Red component (0 to 255) + uint8_t ucGreen, // Green component (0 to 255) + uint8_t ucBlue) // Blue component (0 to 255) +{ ASSERT(sEntry >= 0 && sEntry < 256); if (asPalEntryLocks[sEntry] == 0) - { - apeApp[sEntry].r = ucRed; - apeApp[sEntry].g = ucGreen; - apeApp[sEntry].b = ucBlue; - } + { + apeApp[sEntry].r = ucRed; + apeApp[sEntry].g = ucGreen; + apeApp[sEntry].b = ucBlue; } +} /////////////////////////////////////////////////////////////////////////////// // @@ -1128,17 +1328,17 @@ void rspSetPaletteEntry( // /////////////////////////////////////////////////////////////////////////////// void rspGetPaletteEntry( - int16_t sEntry, // Palette entry (0 to 255) - int16_t* psRed, // Red component (0 to 255) returned if not NULL. - int16_t* psGreen, // Green component (0 to 255) returned if not NULL. - int16_t* psBlue) // Blue component (0 to 255) returned if not NULL. - { + int16_t sEntry, // Palette entry (0 to 255) + int16_t *psRed, // Red component (0 to 255) returned if not NULL. + int16_t *psGreen, // Green component (0 to 255) returned if not NULL. + int16_t *psBlue) // Blue component (0 to 255) returned if not NULL. +{ ASSERT(sEntry >= 0 && sEntry < 256); - SET(psRed, apeApp[sEntry].r); - SET(psGreen, apeApp[sEntry].g); - SET(psBlue, apeApp[sEntry].b); - } + SET(psRed, apeApp[sEntry].r); + SET(psGreen, apeApp[sEntry].g); + SET(psBlue, apeApp[sEntry].b); +} /////////////////////////////////////////////////////////////////////////////// // @@ -1150,34 +1350,34 @@ void rspGetPaletteEntry( // /////////////////////////////////////////////////////////////////////////////// extern void rspGetPaletteEntries( - int16_t sStartIndex, // Palette entry to start copying from - int16_t sCount, // Number of palette entries to do - uint8_t* pucRed, // Pointer to first red component to copy to - uint8_t* pucGreen, // Pointer to first green component to copy to - uint8_t* pucBlue, // Pointer to first blue component to copy to - int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy - { + int16_t sStartIndex, // Palette entry to start copying from + int16_t sCount, // Number of palette entries to do + uint8_t *pucRed, // Pointer to first red component to copy to + uint8_t *pucGreen, // Pointer to first green component to copy to + uint8_t *pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ // Set up source pointers. - uint8_t* pucSrcRed = &(apeApp[sStartIndex].r); - uint8_t* pucSrcGreen = &(apeApp[sStartIndex].g); - uint8_t* pucSrcBlue = &(apeApp[sStartIndex].b); + uint8_t *pucSrcRed = &(apeApp[sStartIndex].r); + uint8_t *pucSrcGreen = &(apeApp[sStartIndex].g); + uint8_t *pucSrcBlue = &(apeApp[sStartIndex].b); while (sCount-- > 0) - { - *pucRed = *pucSrcRed; - *pucGreen = *pucSrcGreen; - *pucBlue = *pucSrcBlue; + { + *pucRed = *pucSrcRed; + *pucGreen = *pucSrcGreen; + *pucBlue = *pucSrcBlue; // Increment destination. - pucRed += lIncBytes; - pucGreen += lIncBytes; - pucBlue += lIncBytes; + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; // Increment source. - pucSrcRed += sizeof(apeApp[0]); - pucSrcGreen += sizeof(apeApp[0]); - pucSrcBlue += sizeof(apeApp[0]); - } + pucSrcRed += sizeof(apeApp[0]); + pucSrcGreen += sizeof(apeApp[0]); + pucSrcBlue += sizeof(apeApp[0]); } +} /////////////////////////////////////////////////////////////////////////////// // @@ -1187,77 +1387,77 @@ extern void rspGetPaletteEntries( // /////////////////////////////////////////////////////////////////////////////// extern void rspUpdatePalette(void) - { - } +{ +} /////////////////////////////////////////////////////////////////////////////// // -// Set entries in the color map used to tweak values set via +// Set entries in the color map used to tweak values set via // rspSetPaletteEntries(). Those colors' values will be used as indices // into this map when rspUpdatePalette() is called. The resulting values // will be updated to the hardware. -// rspGetPaletteEntries/Entry() will still return the original values set +// rspGetPaletteEntries/Entry() will still return the original values set // (not mapped values). -// +// /////////////////////////////////////////////////////////////////////////////// extern void rspSetPaletteMaps( - int16_t sStartIndex, // Map entry to start copying to (has no effect on source!) - int16_t sCount, // Number of map entries to do - uint8_t* pucRed, // Pointer to first red component to copy from - uint8_t* pucGreen, // Pointer to first green component to copy from - uint8_t* pucBlue, // Pointer to first blue component to copy from - int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy - { + int16_t sStartIndex, // Map entry to start copying to (has no effect on source!) + int16_t sCount, // Number of map entries to do + uint8_t *pucRed, // Pointer to first red component to copy from + uint8_t *pucGreen, // Pointer to first green component to copy from + uint8_t *pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ // Set up destination pointers. - uint8_t* pucDstRed = &(au8MapRed[sStartIndex]); - uint8_t* pucDstGreen = &(au8MapGreen[sStartIndex]); - uint8_t* pucDstBlue = &(au8MapBlue[sStartIndex]); + uint8_t *pucDstRed = &(au8MapRed[sStartIndex]); + uint8_t *pucDstGreen = &(au8MapGreen[sStartIndex]); + uint8_t *pucDstBlue = &(au8MapBlue[sStartIndex]); while (sCount-- > 0) - { - *pucDstRed++ = *pucRed; - *pucDstGreen++ = *pucGreen; - *pucDstBlue++ = *pucBlue; + { + *pucDstRed++ = *pucRed; + *pucDstGreen++ = *pucGreen; + *pucDstBlue++ = *pucBlue; // Increment source. - pucRed += lIncBytes; - pucGreen += lIncBytes; - pucBlue += lIncBytes; - } + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; } +} /////////////////////////////////////////////////////////////////////////////// // -// Get entries in the color map used to tweak values set via +// Get entries in the color map used to tweak values set via // rspSetPaletteEntries(). Those colors' values will be used as indices // into this map when rspUpdatePalette() is called. The resulting values // will be updated to the hardware. -// rspGetPaletteEntries/Entry() will still return the original values set +// rspGetPaletteEntries/Entry() will still return the original values set // (not mapped values). -// +// /////////////////////////////////////////////////////////////////////////////// extern void rspGetPaletteMaps( - int16_t sStartIndex, // Map entry to start copying from (has no effect on dest!) - int16_t sCount, // Number of map entries to do - uint8_t* pucRed, // Pointer to first red component to copy to - uint8_t* pucGreen, // Pointer to first green component to copy to - uint8_t* pucBlue, // Pointer to first blue component to copy to - int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy - { + int16_t sStartIndex, // Map entry to start copying from (has no effect on dest!) + int16_t sCount, // Number of map entries to do + uint8_t *pucRed, // Pointer to first red component to copy to + uint8_t *pucGreen, // Pointer to first green component to copy to + uint8_t *pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ // Set up source pointers. - uint8_t* pucSrcRed = &(au8MapRed[sStartIndex]); - uint8_t* pucSrcGreen = &(au8MapGreen[sStartIndex]); - uint8_t* pucSrcBlue = &(au8MapBlue[sStartIndex]); + uint8_t *pucSrcRed = &(au8MapRed[sStartIndex]); + uint8_t *pucSrcGreen = &(au8MapGreen[sStartIndex]); + uint8_t *pucSrcBlue = &(au8MapBlue[sStartIndex]); while (sCount-- > 0) - { - *pucRed = *pucSrcRed++; - *pucGreen = *pucSrcGreen++; - *pucBlue = *pucSrcBlue++; + { + *pucRed = *pucSrcRed++; + *pucGreen = *pucSrcGreen++; + *pucBlue = *pucSrcBlue++; // Increment destination. - pucRed += lIncBytes; - pucGreen += lIncBytes; - pucBlue += lIncBytes; - } + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; } +} /////////////////////////////////////////////////////////////////////////////// // Lock several palette entries. Locking an entry keeps it from @@ -1265,43 +1465,42 @@ extern void rspGetPaletteMaps( // with rspUnlockPaletteEntries() ). /////////////////////////////////////////////////////////////////////////////// extern void rspLockPaletteEntries( - int16_t sStartIndex, // Palette entry at which to start locking. - int16_t sCount) // Number of palette entries to lock. - { + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. +{ // Set up iterator pointer. - int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); while (sCount-- > 0) - { - *psLock = TRUE; - } + { + *psLock = TRUE; } +} /////////////////////////////////////////////////////////////////////////////// // Unlock several palette entries previously locked by rspLockPaletteEntries(). /////////////////////////////////////////////////////////////////////////////// extern void rspUnlockPaletteEntries( - int16_t sStartIndex, // Palette entry at which to start locking. - int16_t sCount) // Number of palette entries to lock. - { + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. +{ // Set up iterator pointer. - int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); while (sCount-- > 0) - { - *psLock = FALSE; - } + { + *psLock = FALSE; + } // Never ever ever unlock these. - asPalEntryLocks[0] = TRUE; - asPalEntryLocks[255] = TRUE; - } + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; +} /////////////////////////////////////////////////////////////////////////////// // Dyna schtuff. /////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// // External Background module functions. ////////////////////////////////////////////////////////////////////////////// @@ -1311,31 +1510,30 @@ extern void rspUnlockPaletteEntries( // Set a callback to be called when the application moves into the background. // /////////////////////////////////////////////////////////////////////////////// -extern void rspSetBackgroundCallback( // Returns nothing. - void (BackgroundCall)(void)) // Callback when app processing becomes - // background. NULL to clear. - { - /* no-op. */ - } +extern void rspSetBackgroundCallback( // Returns nothing. + void(BackgroundCall)(void)) // Callback when app processing becomes + // background. NULL to clear. +{ + /* no-op. */ +} /////////////////////////////////////////////////////////////////////////////// // // Set a callback to be called when the application moves into the foreground. // /////////////////////////////////////////////////////////////////////////////// -extern void rspSetForegroundCallback( // Returns nothing. - void (ForegroundCall)(void)) // Callback when app processing becomes - // foreground. NULL to clear. - { - /* no-op. */ - } +extern void rspSetForegroundCallback( // Returns nothing. + void(ForegroundCall)(void)) // Callback when app processing becomes + // foreground. NULL to clear. +{ + /* no-op. */ +} -extern int16_t rspIsBackground(void) // Returns TRUE if in background, FALSE otherwise - { - extern bool GSDLAppIsActive; - return (int16_t) (!GSDLAppIsActive); - } +extern int16_t rspIsBackground(void) // Returns TRUE if in background, FALSE otherwise +{ + extern bool GSDLAppIsActive; + return (int16_t)(!GSDLAppIsActive); +} ////////////////////////////////////////////////////////////////////////////// // EOF -////////////////////////////////////////////////////////////////////////////// - +////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/source/RSPiX/Src/BLUE/unix/Bdisp_psp.c b/source/RSPiX/Src/BLUE/unix/Bdisp_psp.c new file mode 100644 index 0000000..3d78f3b --- /dev/null +++ b/source/RSPiX/Src/BLUE/unix/Bdisp_psp.c @@ -0,0 +1,1500 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 RWS Inc, All Rights Reserved +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of version 2 of the GNU General Public License as published by +// the Free Software Foundation +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +/////////////////////////////////////////////////////////////////////////////// +// +// bdisp.cpp +// +// History: +// 06/04/04 RCG Started. +// +////////////////////////////////////////////////////////////////////////////// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include "SDL.h" +#include "Blue.h" +#include "ORANGE/CDT/slist.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef struct +{ + float u, v; + uint32_t colour; + float x, y, z; +} TextureVertex; + +typedef struct +{ + float width; // Texture width + float height; // Texture height + uint32_t *data; // Pointer to texture pixel data (VRAM) +} Texture; + +char list[0x20000] __attribute__((aligned(64))); + +extern SDL_Window *sdlWindow; +static char *sdlAppName; +static SDL_Renderer *sdlRenderer; +static SDL_Texture *sdlTexture; +static int RequestedWidth = 0; +static int RequestedHeight = 0; +static int FramebufferWidth = 0; +static int FramebufferHeight = 0; +static Uint32 *TexturePointer = NULL; +static Uint8 *PalettedTexturePointer = NULL; + +typedef struct // Stores information on usable video modes. +{ + int16_t sWidth; + int16_t sHeight; + int16_t sColorDepth; + int16_t sPages; +} VIDEO_MODE, *PVIDEO_MODE; + +static RSList slvmModes; // List of available video modes. + +typedef union +{ + struct + { + Uint8 b; + Uint8 g; + Uint8 r; + Uint8 a; + }; + Uint32 argb; +} ArgbColor; +static ArgbColor apeApp[256]; // App's palette. The palette + // entries the App actually set. +// Unused! Why? +// static ArgbColor apeMapped[256]; // Tweaked palette. +// This is the palette updated to +// the hardware. apeApp is trans- +// lated through au8MapRed, Green, +// and Blue and stored here for +// updating to the hardware on +// rspUpdatePalette(). + +static U8 au8MapRed[256]; // Map of red intensities to hardware + // values. Initially an identity + // mapping. +static U8 au8MapGreen[256]; // Map of green intensities to + // hardware values. Initially an + // identity mapping. +static U8 au8MapBlue[256]; // Map of blue intensities to hardware + // values. Initially an identity + // mapping. + +static int16_t asPalEntryLocks[256]; // TRUE, if an indexed entry is locked. + // FALSE, if not. Implemented as + // shorts in case we ever do levels of + // locking. + +extern bool mouse_grabbed; + +////////////////////////////////////////////////////////////////////////////// +// Module specific macros. +////////////////////////////////////////////////////////////////////////////// + +// Only set value if not NULL. +#define SET(ptr, val) (((ptr) != NULL) ? *(ptr) = (val) : 0) + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t Clip( // Returns non-zero if image entirely clipped out. + int16_t *px, // Rectangle to be clipped. + int16_t *py, + int16_t *pw, + int16_t *ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) +{ + if (*px < sx) + { + TRACE("Clip(): x too small.\n"); + // Adjust width. + *pw -= sx - *px; + // Adjust x. + *px = sx; + } + + if (*py < sy) + { + TRACE("Clip(): y too small.\n"); + // Adjust height. + *ph -= sy - *py; + // Adjust y. + *py = sy; + } + + if (*px + *pw > sw) + { + TRACE("Clip(): Width or x too large.\n"); + // Adjust width. + *pw -= ((*px + *pw) - sw); + } + + if (*py + *ph > sh) + { + TRACE("Clip(): Height or y too large.\n"); + // Adjust height. + *ph -= ((*py + *ph) - sh); + } + + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int16_t *px, // Rectangle to be clipped. + int16_t *py, + int16_t *pw, + int16_t *ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) +{ + if (*px < sx) + { + // Adjust width. + *pw -= sx - *px; + // Adjust x. + *px = sx; + } + + if (*py < sy) + { + // Adjust height. + *ph -= sy - *py; + // Adjust y. + *py = sy; + } + + if (*px + *pw > sw) + { + // Adjust width. + *pw -= ((*px + *pw) - sw); + } + + if (*py + *ph > sh) + { + // Adjust height. + *ph -= ((*py + *ph) - sh); + } + + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// Uses short version of function ClipQuiet(...). +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int32_t *px, // Rectangle to be clipped. + int32_t *py, + int32_t *pw, + int32_t *ph, + int32_t sx, // Bounding rectangle. + int32_t sy, + int32_t sw, + int32_t sh) +{ + int16_t sX = (int16_t)(*px); + int16_t sY = (int16_t)(*py); + int16_t sW = (int16_t)(*pw); + int16_t sH = (int16_t)(*ph); + + int16_t sRes = ClipQuiet(&sX, &sY, &sW, &sH, + (int16_t)sx, (int16_t)sy, (int16_t)sw, (int16_t)sh); + + *px = sX; + *py = sY; + *pw = sW; + *ph = sH; + + return sRes; +} + +int16_t CompareModes(PVIDEO_MODE pvm1, PVIDEO_MODE pvm2); + +extern void Disp_Init(void) // Returns nothing. +{ + extern char **_argv; + const int arg = rspCommandLine("resolution"); + if ((arg) && (_argv[arg + 1])) + { + if (SDL_sscanf(_argv[arg + 1], "%dx%d", &RequestedWidth, &RequestedHeight) != 2) + RequestedWidth = RequestedHeight = 0; + } + + if ((RequestedWidth <= 0) || (RequestedHeight <= 0)) + { + if (rspCommandLine("windowed")) + { + RequestedWidth = 1024; + RequestedHeight = 768; + } + else + { + RequestedWidth = 0; + RequestedHeight = 0; + } + } + + // Initialize maps to indentities. + int16_t i; + for (i = 0; i < 256; i++) + { + au8MapRed[i] = i; + au8MapGreen[i] = i; + au8MapBlue[i] = i; + } + + // Never ever ever unlock these. + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; + + slvmModes.SetCompareFunc(CompareModes); +} + +extern void rspSetApplicationName( + char *pszName) // In: Application name +{ + SDL_free(sdlAppName); + sdlAppName = SDL_strdup(pszName); + if (sdlWindow) + SDL_SetWindowTitle(sdlWindow, sdlAppName); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Compares two video modes in order of sColorDepth, sWidth, sHeight, +// sPageFlippage. +// Returns 0 if *pvm1 == *pvm2. +// Returns negative if *pvm1 < *pvm2. +// Returns positive if *pvm1 > *pvm2. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t CompareModes( // Returns as described above. + PVIDEO_MODE pvm1, // First video mode to compare. + PVIDEO_MODE pvm2) // Second video mode to compare. +{ + int16_t sRes = 1; // Assume *pvm1 > *pvm2. + + if (pvm1->sColorDepth == pvm2->sColorDepth) + { + if (pvm1->sWidth == pvm2->sWidth) + { + if (pvm1->sHeight == pvm2->sHeight) + { + if (pvm1->sPages == pvm2->sPages) + { + sRes = 0; + } + else + { + if (pvm1->sPages < pvm2->sPages) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sHeight < pvm2->sHeight) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sWidth < pvm2->sWidth) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sColorDepth < pvm2->sColorDepth) + { + sRes = -1; + } + } + + return sRes; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Attempts to find a mode that is sWidth by sHeight or larger +// with the given color depth. An available mode that closest matches +// the width and height is chosen, if successful. If no mode is found, +// *psWidth, *psHeight. If psPixelDoubling is not NULL and *psPixelDoubling +// is TRUE, a mode may be returned that requires pixel doubling. If a +// mode requires pixel doubling, *psPixelDoubling will be TRUE on return; +// otherwise, it will be FALSE. Passing psPixelDoubling as NULL is +// equivalent to passing *psPixelDoubling with FALSE. +// Utilizes rspQueryVideoMode to find the mode. Does not affect the current +// rspQueryVideoMode. +// This function should not be a part of Blue. It is always implementable +// via rspQueryVideoMode. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspSuggestVideoMode( // Returns 0 if successfull, non-zero otherwise + int16_t sDepth, // In: Required depth + int16_t sWidth, // In: Requested width + int16_t sHeight, // In: Requested height + int16_t sPages, // In: Required pages + int16_t sScaling, // In: Requested scaling + int16_t *psDeviceWidth /*= NULL*/, // Out: Suggested device width (unless NULL) + int16_t *psDeviceHeight /*= NULL*/, // Out: Suggested device height (unless NULL) + int16_t *psScaling /*= NULL*/) // Out: Suggested scaling (unless NULL) +{ + int16_t sRes = 0; // Assume success. + + // Store video mode that the app is currently iterating. + PVIDEO_MODE pvmOldModeQuery = slvmModes.GetCurrent(); + + rspQueryVideoModeReset(); + + // Query results. + int16_t sModeWidth; + int16_t sModeHeight; + int16_t sModeColorDepth; + int16_t sModePages; + + // Best results. + int16_t sBestModeWidth = 16380; + int16_t sBestModeHeight = 16380; + int16_t sModeFound = FALSE; + + while (rspQueryVideoMode(&sModeColorDepth, &sModeWidth, &sModeHeight, &sModePages) == 0) + { + // Must be same color depth. + if (sModeColorDepth == sDepth && sPages == sModePages) + { + // If the desired resolution would fit into this mode . . . + if (sWidth <= sModeWidth && sHeight <= sModeHeight) + { + // If this mode is closer than a previous one . . . + float fFactorOld = ((float)sBestModeWidth * (float)sBestModeHeight) / ((float)sWidth * (float)sHeight); + float fFactorNew = ((float)sModeWidth * (float)sModeHeight) / ((float)sWidth * (float)sHeight); + if (fFactorNew < fFactorOld) + { + sBestModeWidth = sModeWidth; + sBestModeHeight = sModeHeight; + sModeFound = TRUE; + } + } + } + } + + // If we found an acceptable mode . . . + if (sModeFound != FALSE) + { + // If pixel doubling was specified . . . + if (psScaling != NULL) + { + // If pixel doubling is allowed . . . + if (sScaling != FALSE) + { + // If the chosen mode is more than or equal to twice the + // requested mode . . . + if (sWidth * 2 <= sBestModeWidth && sHeight * 2 <= sBestModeHeight) + { + // Okay to pixel double. Leave *psPixelDoubling as TRUE. + // Reduce best width and height appropriately. + sBestModeWidth /= 2; + sBestModeHeight /= 2; + } + else + { + // No pixel doubling possible for this mode. + *psScaling = FALSE; + } + } + } + + *psDeviceWidth = sBestModeWidth; + *psDeviceHeight = sBestModeHeight; + } + else + { + // Failed to find an acceptable mode. + sRes = 1; + } + + return sRes; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Puts parameters about the hardware video mode into your shorts. +// You may call this function even when in "no mode" (e.g., before +// rspSetVideoMode is first called, after it fails, or after rspKillVideMode +// is called). This way you can get information on the user's current mode. +// If in "no mode", psWidth, psHeight, and psPages will receive 0, if not NULL. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspGetVideoMode( + int16_t *psDeviceDepth, // Hardware display color depth returned here + // (unless NULL). + int16_t *psDeviceWidth, // Hardware display width returned here + // (unless NULL). + int16_t *psDeviceHeight, // Hardware display height returned here + // (unless NULL). + int16_t *psDevicePages, // Hardware display back buffers returned here + // (unless NULL). + int16_t *psWidth, // Display area width returned here + // (unless NULL). + int16_t *psHeight, // Display area height returned here + // (unless NULL). + int16_t *psPages /*= NULL*/, // Number of pages (1 to n) returned here + // (unless NULL). More than 1 indicates a + // page flipping scenario. + int16_t *psPixelScaling /*= NULL*/) // Pixel scaling in effect (1) or not (0) + // (unless NULL). +{ + // lie about everything. + SET(psPixelScaling, 0); + SET(psDevicePages, 0); + SET(psPages, 1); + SET(psWidth, FramebufferWidth); + SET(psHeight, FramebufferHeight); + SET(psDeviceDepth, 8); + SET(psDeviceHeight, FramebufferWidth); + SET(psDeviceWidth, FramebufferHeight); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Reset the query process. Must be called before calling QueryVideoModes() +// for the first time. See QueryVideoModes() for more. +// +////////////////////////////////////////////////////////////////////////////// + +static void addMode(int w, int h, int depth) +{ + PVIDEO_MODE pvm; + + if (depth >= 8) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 8; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } + + if (depth >= 16) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 16; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } + + if (depth >= 24) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 32; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } +} + +extern void rspQueryVideoModeReset(void) +{ + static bool enumerated = false; + if (!enumerated) + { + ASSERT(SDL_WasInit(SDL_INIT_VIDEO)); + + // Attempt to grab user's current desktop resolution instead of forcing 640x480 +#ifndef MOBILE + SDL_DisplayMode dm_Mode; + int i_Result = SDL_GetDesktopDisplayMode(0, &dm_Mode); + if (!i_Result) + addMode(dm_Mode.w, dm_Mode.h, 8); + else // Fall back to 640x480 +#endif + addMode(640, 480, 8); + + enumerated = true; + } + + slvmModes.GetHead(); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Query the available video modes. The modes are returned in sorted order +// based on increasing color depth, width, and height, in that order. The +// next time the function is called after the last actual mode was reported, +// it will return non-zero (failure) to indicate that no more modes are +// available, and will continue to do so until QueryVideoReset() is +// called to reset it back to the first video mode. When the return value is +// non-zero, the other parameters are not updated. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspQueryVideoMode( // Returns 0 for each valid mode, then non-zero thereafter + int16_t *psColorDepth, // Color depth (8, 15, 16, 24, 32) + // Unless NULL. + int16_t *psWidth /*= NULL*/, // Width returned here + // Unless NULL. + int16_t *psHeight /*= NULL*/, // Height returned here + // Unless NULL. + int16_t *psPages /*= NULL*/) // Number of video pages possible. +{ + int16_t sRes = 0; // Assume success. + + PVIDEO_MODE pvm = slvmModes.GetCurrent(); + + if (pvm != NULL) + { + SET(psColorDepth, pvm->sColorDepth); + SET(psWidth, pvm->sWidth); + SET(psHeight, pvm->sHeight); + + SET(psPages, pvm->sPages); + + // Goto next video mode. + slvmModes.GetNext(); + } + else + { + sRes = 1; + } + + return sRes; +} + +static SDL_Renderer *createRendererToggleVsync(SDL_Window *window, const int index, bool vsync) +{ + SDL_Renderer *retval = NULL; + +#if defined(SWITCH) || defined(PSP) + fprintf(stderr, ">> Create SDL_RENDERER_SOFTWARE %s\n", SDL_GetError()); + retval = SDL_CreateRenderer(window, index, SDL_RENDERER_SOFTWARE); +#else + if (vsync) + retval = SDL_CreateRenderer(window, index, SDL_RENDERER_PRESENTVSYNC); + if (!retval) + retval = SDL_CreateRenderer(window, index, 0); +#endif + return retval; +} + +static SDL_Renderer *createRendererByName(SDL_Window *window, const char *name) +{ + const bool vsync = !rspCommandLine("novsync"); + if (name == NULL) + return createRendererToggleVsync(window, -1, vsync); + else + { + const int max = SDL_GetNumRenderDrivers(); + for (int i = 0; i < max; i++) + { + SDL_RendererInfo info; + if ((SDL_GetRenderDriverInfo(i, &info) == 0) && (SDL_strcmp(info.name, name) == 0)) + return createRendererToggleVsync(window, i, vsync); + } + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Set a new video mode. Specified color depth, width, and height for the +// device is absolute. If these parameters cannot be met, the function will +// fail. If the requested resolution is higher than the requested display area, +// it will be centered with a black border around it. This function can be +// called multiple times to change modes, but it does not create new +// display areas; instead, the previous buffer is destroyed and a new buffer +// is created to take it's place. +// If pixel doubling is allowed (with rspAllowPixelDoubling) and the requested +// display area is less than or equal to half the requested hardware resolution, +// pixel doubling will be activated. +// If this function fails, you will be in no mode; meaning you may not access +// the display (i.e., call display/palette functions) even if you were in a mode +// before calling this function. See rspKillVideoMode. +// Before this function is called, you may not call functions that manipulate +// the display. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspSetVideoMode( // Returns 0 if successfull, non-zero otherwise + int16_t sDeviceDepth, // Specify required device video depth here. + int16_t sDeviceWidth, // Specify required device resolution width here. + int16_t sDeviceHeight, // Specify required device resolution height here. + int16_t sWidth, // Specify width of display area on screen. + int16_t sHeight, // Specify height of display area on screen. + int16_t sPages /*= 1*/, // Specify number of video pages. More than 1 + // indicates a page flipping scenario. + int16_t sPixelDoubling /*= FALSE*/) +// TRUE indicates to set the video mode +// to twice that indicated by sDeviceWidth, +// sDeviceHeight and double the coordinate +// system and blts. +// FALSE indicates not to use this garbage. +{ + TRACE("rspSetVideoMode(%i, %i, %i, %i, %i, %i, %i)\n", sDeviceDepth, sDeviceWidth, sDeviceHeight, sWidth, sHeight, sPages, sPixelDoubling); + ASSERT(sDeviceDepth == 8); + // ASSERT(sDeviceWidth == 0); + // ASSERT(sDeviceHeight == 0); + // ASSERT(sWidth == 640); + ASSERT(sHeight == 480); + + for (size_t i = 0; i < 256; i++) + apeApp[i].a = 0xFF; + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + + if (sPixelDoubling) + { + fprintf(stderr, "STUBBED: pixel doubling? %s:%d\n", __FILE__, __LINE__); + return -1; + } + + FramebufferWidth = sWidth; + FramebufferHeight = sHeight; + + mouse_grabbed = !rspCommandLine("nomousegrab"); + + Uint32 flags = 0; + if (!rspCommandLine("windowed")) + { + if ((!RequestedWidth) || (!RequestedHeight)) + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + else + flags |= SDL_WINDOW_FULLSCREEN; + } + + if (mouse_grabbed) + flags |= SDL_WINDOW_INPUT_GRABBED; + +#if PLATFORM_IOS + flags |= SDL_WINDOW_BORDERLESS; // don't show the status bar +#endif + TRACE("RequestedWidth %d RequestedHeight %d\n", RequestedWidth, RequestedHeight); + + const char *title = sdlAppName ? sdlAppName : ""; + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sWidth, sHeight, SDL_WINDOW_FULLSCREEN); + if (!sdlWindow) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create window: %s.", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + int w = 0, h = 0; + SDL_GetWindowSize(sdlWindow, &w, &h); + TRACE("SDL Window initialized at %ix%i\n", w, h); + + bool bRequestedRenderer = true; + if (rspCommandLine("direct3d")) + sdlRenderer = createRendererByName(sdlWindow, "direct3d"); + else if (rspCommandLine("opengl")) + sdlRenderer = createRendererByName(sdlWindow, "opengl"); + else if (rspCommandLine("software")) + sdlRenderer = createRendererByName(sdlWindow, "software"); + else + { + bRequestedRenderer = false; + sdlRenderer = createRendererByName(sdlWindow, NULL); + } + + if (!sdlRenderer) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create %s renderer: %s", bRequestedRenderer ? "requested" : "a", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + + TRACE("blah\n"); + + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); +#ifndef MOBILE // Need to remove this for the mouse point to be in the correct place, Android And IOS + // SDL_RenderSetLogicalSize(sdlRenderer, FramebufferWidth, FramebufferHeight); + TRACE("SDL Renderer set: %ix%i\n", FramebufferWidth, FramebufferHeight); + +// https://pspdev.github.io/basic_programs.html +#define BUFFER_WIDTH 512 +#define BUFFER_HEIGHT 272 +#define SCREEN_WIDTH 480 +#define SCREEN_HEIGHT BUFFER_HEIGHT + // setup GU + + pspDebugScreenInit(); + // setupCallbacks(); + + // Setup GU + void *fbp0 = guGetStaticVramBuffer(BUFFER_WIDTH, SCREEN_HEIGHT, GU_PSM_8888); + void *fbp1 = guGetStaticVramBuffer(BUFFER_WIDTH, SCREEN_HEIGHT, GU_PSM_8888); + + sceGuInit(); + + // Set up buffers + sceGuStart(GU_DIRECT, list); + sceGuDrawBuffer(GU_PSM_8888, fbp0, BUFFER_WIDTH); + sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, fbp1, BUFFER_WIDTH); + + // We do not care about the depth buffer in this example + sceGuDepthBuffer(fbp0, 0); // Set depth buffer to a length of 0 + sceGuDisable(GU_DEPTH_TEST); // Disable depth testing + + // Set up viewport + sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2)); + sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT); + sceGuEnable(GU_SCISSOR_TEST); + sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + + // Start a new frame and enable the display + sceGuFinish(); + sceGuDisplay(GU_TRUE); + + TexturePointer = new uint32_t[512 * 512]; + if (!TexturePointer) + { + fprintf(stderr, "Error: Unable to allocate VRAM for texture.\n"); + exit(1); + } + + PalettedTexturePointer = new uint8_t[FramebufferWidth * FramebufferHeight]; + if (!PalettedTexturePointer) + { + fprintf(stderr, "Error: Unable to allocate memory for palette data.\n"); + exit(1); + } + + // init stuff + memset(TexturePointer, 0, FramebufferWidth * FramebufferHeight * sizeof(uint32_t)); + memset(PalettedTexturePointer, 0, FramebufferWidth * FramebufferHeight * sizeof(uint8_t)); + fprintf(stderr, "Texture and palette data successfully initialized.\n"); + +#endif + sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 512, 512); + if (!sdlTexture) + { + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "Couldn't create texture: %s", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyRenderer(sdlRenderer); + sdlRenderer = NULL; + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + + TexturePointer = new Uint32[FramebufferWidth * FramebufferHeight]; + PalettedTexturePointer = new Uint8[FramebufferWidth * FramebufferHeight]; + SDL_memset(TexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof(Uint32)); + SDL_memset(PalettedTexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof(Uint8)); + SDL_UpdateTexture(sdlTexture, NULL, TexturePointer, FramebufferWidth * 4); + + SDL_ShowCursor(0); + // SDL_SetRelativeMouseMode(mouse_grabbed ? SDL_TRUE : SDL_FALSE); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Puts you in a state of not having display access. After this function is +// called (similar to before rspSetVideoMode is called) you may not call +// functions that manipulate the display. This is similar to the situation +// achieved if rspSetVideoMode fails. +// +////////////////////////////////////////////////////////////////////////////// +extern void rspKillVideoMode(void) +{ + /* no-op ... SDL_Quit() will catch this. */ +} + +////////////////////////////////////////////////////////////////////////////// +// +// Frees the memory (and, perhaps, structure(s)) associated with the memory +// stored in system RAM that is allocate rspSetVideoMode. If you are not +// using the system buffer (i.e., you are not calling rspLockVideoBuffer), +// you can call this to free up some additional memory. Calls to +// rspLockVideoBuffer will fail after a call to this function without a +// subsequent call to rspSetVideoMode. +// +////////////////////////////////////////////////////////////////////////////// +extern void rspKillVideoBuffer(void) +{ + /* no-op ... SDL_Quit() will catch this. */ +} + +////////////////////////////////////////////////////////////////////////////// +// +// Variation #1: Update the entire display from the buffer. Includes +// pixel doubling as appropriate - see elsewhere for details. +// +////////////////////////////////////////////////////////////////////////////// + +extern void rspUpdateDisplayRects(void) +{ + // no-op, just blast it all to the GPU. +} + +extern void rspCacheDirtyRect( + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update +{ +} + +bool ValidateFrame(Uint32 *frameBuffer, int width, int height) +{ + // Simple validation logic (customize based on your distortion patterns) + int invalidPixelCount = 0; + const int threshold = (width * height) / 10; // Example: 10% of pixels can be invalid + + for (int i = 0; i < width * height; i++) + { + Uint32 pixel = frameBuffer[i]; + + // Check for corruption (e.g., all pixels are the same or too many black pixels) + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888), &r, &g, &b, &a); + + if (r == 0 && g == 0 && b == 0 && a == 255) + { // Example: fully black pixels + invalidPixelCount++; + } + + if (invalidPixelCount > threshold) + { + return false; // Frame is distorted + } + } + return true; // Frame is valid +} + +SDL_Surface *frameSurface = NULL; +SDL_Surface *scaledSurface = NULL; + +void drawTexture(Texture *texture, float x, float y, float w, float h) +{ + static TextureVertex vertices[2]; + + vertices[0].u = 0.0f; + vertices[0].v = 0.0f; + vertices[0].colour = 0xFFFFFFFF; + vertices[0].x = x; + vertices[0].y = y; + vertices[0].z = 0.0f; + + vertices[1].u = w; + vertices[1].v = h; + vertices[1].colour = 0xFFFFFFFF; + vertices[1].x = x + w; + vertices[1].y = y + h; + vertices[1].z = 0.0f; + + sceGuTexMode(GU_PSM_8888, 0, 0, GU_FALSE); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); + sceGuTexImage(0, texture->width, texture->height, texture->width, texture->data); + + sceGuEnable(GU_TEXTURE_2D); + sceGuDrawArray(GU_SPRITES, GU_COLOR_8888 | GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices); + sceGuDisable(GU_TEXTURE_2D); +} + +extern void rspPresentFrame(void) +{ +if (!sdlWindow) + return; + +ASSERT(sizeof(apeApp[0]) == sizeof(uint32_t)); + +// update texture data +const Uint8 *src = PalettedTexturePointer; +Uint32 *dst = TexturePointer; +for (int y = 0; y < FramebufferHeight; y++) { + for (int x = 0; x < FramebufferWidth; x++, src++, dst++) { + ArgbColor color = apeApp[*src]; + Uint8 r = color.r; + Uint8 g = color.g; + Uint8 b = color.b; + Uint8 a = color.a; + + *dst = (a << 24) | (b << 16) | (g << 8) | r; // BGRA + } +} + +fprintf(stderr, "FramebufferWidth: %d, FramebufferHeight: %d\n", FramebufferWidth, FramebufferHeight); +if (!TexturePointer || !apeApp) { + fprintf(stderr, "Error: TexturePointer or apeApp is NULL.\n"); + return; +} + +// create texture +Texture myTexture = { + .width = FramebufferWidth, + .height = FramebufferHeight, + .data = TexturePointer +}; + +// begin +sceGuStart(GU_DIRECT, list); + +// clear +sceGuClearColor(GU_RGBA(255, 255, 255, 255)); // white +sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT); + +// draw +//drawTexture(&myTexture, SCREEN_WIDTH / 2 - 240, SCREEN_HEIGHT / 2 - 136, 480, 272); +//drawTexture(&myTexture, SCREEN_WIDTH / 2 - myTexture.width / 2, SCREEN_HEIGHT / 2 - myTexture.height / 2, myTexture.width, myTexture.height); +drawTexture(&myTexture, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + + +// swap +sceGuFinish(); +sceGuSync(0, 0); +sceDisplayWaitVblankStart(); +sceGuSwapBuffers(); + + + /* + // !!! FIXME: I imagine this is not fast. Maybe keep the dirty rect code at least? + ASSERT(sizeof (apeApp[0]) == sizeof (Uint32)); + const Uint8 *src = PalettedTexturePointer; + Uint32 *dst = TexturePointer; + for (int y = 0; y < FramebufferHeight; y++) + { + for (int x = 0; x < FramebufferWidth; x++, src++, dst++) + *dst = apeApp[*src].argb; + } + + int srcWidth = 640, srcHeight = 480; + int dstWidth = 480, dstHeight = 272; + + if (!frameSurface) { + frameSurface = SDL_CreateRGBSurfaceFrom( + TexturePointer, srcWidth, srcHeight, 32, + FramebufferWidth * 4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 + ); + if (!frameSurface) { + fprintf(stderr, "Failed to create SDL_Surface: %s\n", SDL_GetError()); + return; + } + } + + if (!scaledSurface) { + scaledSurface = SDL_CreateRGBSurfaceWithFormat(0, dstWidth, dstHeight, 32, SDL_PIXELFORMAT_ARGB8888); + if (!scaledSurface) { + fprintf(stderr, "Failed to create scaled SDL_Surface: %s\n", SDL_GetError()); + SDL_FreeSurface(frameSurface); + return; + } + } + + SDL_Rect srcRect = {0, 0, srcWidth, srcHeight}; + SDL_Rect dstRect = {0, 0, dstWidth, dstHeight}; + if (SDL_BlitScaled(frameSurface, &srcRect, scaledSurface, &dstRect) != 0) { + fprintf(stderr, "Failed to scale SDL_Surface: %s\n", SDL_GetError()); + return; + } + + SDL_Texture* frameTexture = SDL_CreateTextureFromSurface(sdlRenderer, scaledSurface); + if (!frameTexture) { + fprintf(stderr, "Failed to create SDL_Texture: %s\n", SDL_GetError()); + return; + } + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, frameTexture, NULL, NULL); + SDL_RenderPresent(sdlRenderer); + + SDL_DestroyTexture(frameTexture); + */ + static Uint32 lastframeticks = 0; + const Uint32 now = SDL_GetTicks(); + + if ((lastframeticks) && (lastframeticks <= now)) + { + const Uint32 elapsed = (now - lastframeticks); + if (elapsed <= 5) // going WAY too fast, maybe OpenGL (and/or no vsync)? + SDL_Delay(16 - elapsed); // try to get closer to 60fps. + } + + lastframeticks = now; + + // #if 0 + static Uint32 ticks = 0; + static Uint32 frames = 0; + frames++; + if ((now - ticks) > 5000) + { + if (ticks > 0) + printf("fps: %f\n", (((double)frames) / ((double)(now - ticks))) * 1000.0); + ticks = now; + frames = 0; + } + // #endif +} + +extern void rspUpdateDisplay(void) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUpdateDisplay( + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoPage( // Returns 0 if screen memory could be locked. + // Returns non-zero otherwise. + void **ppvMemory, // Pointer to display memory returned here. + // NULL returned if not supported. + int32_t *plPitch) // Pitch of display memory returned here. +{ + /* no-op. */ + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoPage(void) // Returns nothing. +{ + /* no-op. */ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoFlipPage( // Returns 0 if flip screen memory could be + // locked. Returns non-zero otherwise. + void **ppvMemory, // Pointer to flip screen memory returned here. + // NULL returned on failure. + int32_t *plPitch) // Pitch of flip screen memory returned here. +{ + return -1; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoFlipPage(void) // Returns nothing. +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoBuffer( // Returns 0 if system buffer could be locked. + // Returns non-zero otherwise. + void **ppvBuffer, // Pointer to system buffer returned here. + // NULL returned on failure. + int32_t *plPitch) // Pitch of system buffer returned here. +{ + if (!sdlWindow) + return -1; + + *ppvBuffer = PalettedTexturePointer; + *plPitch = FramebufferWidth; + + return (0); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoBuffer(void) // Returns nothing. +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspAllowPageFlip(void) // Returns 0 on success. +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// External Palette module functions. +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// Set several palette entries. Separate pointers to each component +// combined with caller-specified increment for all pointers allows +// use of this function with any (non-packed) arrangement of RGB data. +// Hardware palette is not updated until UpdatePalette() is called. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetPaletteEntries( + int16_t sStartIndex, // Palette entry to start copying to (has no effect on source!) + int16_t sCount, // Number of palette entries to do + uint8_t *pucRed, // Pointer to first red component to copy from + uint8_t *pucGreen, // Pointer to first green component to copy from + uint8_t *pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ + // Set up destination pointers. + uint8_t *pucDstRed = &(apeApp[sStartIndex].r); + uint8_t *pucDstGreen = &(apeApp[sStartIndex].g); + uint8_t *pucDstBlue = &(apeApp[sStartIndex].b); + + // Set up lock pointer. + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + if (*psLock++ == 0) + { + *pucDstRed = *pucRed; + *pucDstGreen = *pucGreen; + *pucDstBlue = *pucBlue; + } + + // Increment source. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + + // Increment destination. + pucDstRed += sizeof(apeApp[0]); + pucDstGreen += sizeof(apeApp[0]); + pucDstBlue += sizeof(apeApp[0]); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Set palette entry. Hardware palette is not updated until +// UpdatePalette() is called. +// +/////////////////////////////////////////////////////////////////////////////// +void rspSetPaletteEntry( + int16_t sEntry, // Palette entry (0 to 255) + uint8_t ucRed, // Red component (0 to 255) + uint8_t ucGreen, // Green component (0 to 255) + uint8_t ucBlue) // Blue component (0 to 255) +{ + ASSERT(sEntry >= 0 && sEntry < 256); + + if (asPalEntryLocks[sEntry] == 0) + { + apeApp[sEntry].r = ucRed; + apeApp[sEntry].g = ucGreen; + apeApp[sEntry].b = ucBlue; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Get palette entry. This reflects the palette that may or may NOT have +// been set by calling rspUpdatePalette. +// +/////////////////////////////////////////////////////////////////////////////// +void rspGetPaletteEntry( + int16_t sEntry, // Palette entry (0 to 255) + int16_t *psRed, // Red component (0 to 255) returned if not NULL. + int16_t *psGreen, // Green component (0 to 255) returned if not NULL. + int16_t *psBlue) // Blue component (0 to 255) returned if not NULL. +{ + ASSERT(sEntry >= 0 && sEntry < 256); + + SET(psRed, apeApp[sEntry].r); + SET(psGreen, apeApp[sEntry].g); + SET(psBlue, apeApp[sEntry].b); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Get several palette entries. Separate pointers to each component +// combined with caller-specified increment for all pointers allows +// use of this function with any (non-packed) arrangement of RGB data. +// This is the palette that may not necessarily be updated yet in the hardware +// (i.e., some may have set the palette and not called UpdatePalette()). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspGetPaletteEntries( + int16_t sStartIndex, // Palette entry to start copying from + int16_t sCount, // Number of palette entries to do + uint8_t *pucRed, // Pointer to first red component to copy to + uint8_t *pucGreen, // Pointer to first green component to copy to + uint8_t *pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ + // Set up source pointers. + uint8_t *pucSrcRed = &(apeApp[sStartIndex].r); + uint8_t *pucSrcGreen = &(apeApp[sStartIndex].g); + uint8_t *pucSrcBlue = &(apeApp[sStartIndex].b); + + while (sCount-- > 0) + { + *pucRed = *pucSrcRed; + *pucGreen = *pucSrcGreen; + *pucBlue = *pucSrcBlue; + // Increment destination. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + + // Increment source. + pucSrcRed += sizeof(apeApp[0]); + pucSrcGreen += sizeof(apeApp[0]); + pucSrcBlue += sizeof(apeApp[0]); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Update hardware palette using information that has been set +// using SetPaletteEntry() and SetPaletteEntries(). +// In the future, this may support optional VBLANK-synced updates. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUpdatePalette(void) +{ +} +/////////////////////////////////////////////////////////////////////////////// +// +// Set entries in the color map used to tweak values set via +// rspSetPaletteEntries(). Those colors' values will be used as indices +// into this map when rspUpdatePalette() is called. The resulting values +// will be updated to the hardware. +// rspGetPaletteEntries/Entry() will still return the original values set +// (not mapped values). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetPaletteMaps( + int16_t sStartIndex, // Map entry to start copying to (has no effect on source!) + int16_t sCount, // Number of map entries to do + uint8_t *pucRed, // Pointer to first red component to copy from + uint8_t *pucGreen, // Pointer to first green component to copy from + uint8_t *pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ + // Set up destination pointers. + uint8_t *pucDstRed = &(au8MapRed[sStartIndex]); + uint8_t *pucDstGreen = &(au8MapGreen[sStartIndex]); + uint8_t *pucDstBlue = &(au8MapBlue[sStartIndex]); + + while (sCount-- > 0) + { + *pucDstRed++ = *pucRed; + *pucDstGreen++ = *pucGreen; + *pucDstBlue++ = *pucBlue; + // Increment source. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Get entries in the color map used to tweak values set via +// rspSetPaletteEntries(). Those colors' values will be used as indices +// into this map when rspUpdatePalette() is called. The resulting values +// will be updated to the hardware. +// rspGetPaletteEntries/Entry() will still return the original values set +// (not mapped values). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspGetPaletteMaps( + int16_t sStartIndex, // Map entry to start copying from (has no effect on dest!) + int16_t sCount, // Number of map entries to do + uint8_t *pucRed, // Pointer to first red component to copy to + uint8_t *pucGreen, // Pointer to first green component to copy to + uint8_t *pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy +{ + // Set up source pointers. + uint8_t *pucSrcRed = &(au8MapRed[sStartIndex]); + uint8_t *pucSrcGreen = &(au8MapGreen[sStartIndex]); + uint8_t *pucSrcBlue = &(au8MapBlue[sStartIndex]); + + while (sCount-- > 0) + { + *pucRed = *pucSrcRed++; + *pucGreen = *pucSrcGreen++; + *pucBlue = *pucSrcBlue++; + // Increment destination. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Lock several palette entries. Locking an entry keeps it from +// being updated by rspSetPaletteEntries() (until it is unlocked +// with rspUnlockPaletteEntries() ). +/////////////////////////////////////////////////////////////////////////////// +extern void rspLockPaletteEntries( + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. +{ + // Set up iterator pointer. + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + *psLock = TRUE; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Unlock several palette entries previously locked by rspLockPaletteEntries(). +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockPaletteEntries( + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. +{ + // Set up iterator pointer. + int16_t *psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + *psLock = FALSE; + } + + // Never ever ever unlock these. + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// Dyna schtuff. +/////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// External Background module functions. +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// Set a callback to be called when the application moves into the background. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetBackgroundCallback( // Returns nothing. + void(BackgroundCall)(void)) // Callback when app processing becomes + // background. NULL to clear. +{ + /* no-op. */ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Set a callback to be called when the application moves into the foreground. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetForegroundCallback( // Returns nothing. + void(ForegroundCall)(void)) // Callback when app processing becomes + // foreground. NULL to clear. +{ + /* no-op. */ +} + +extern int16_t rspIsBackground(void) // Returns TRUE if in background, FALSE otherwise +{ + extern bool GSDLAppIsActive; + return (int16_t)(!GSDLAppIsActive); +} +////////////////////////////////////////////////////////////////////////////// +// EOF +////////////////////////////////////////////////////////////////////////////// diff --git a/source/RSPiX/Src/BLUE/unix/Bdisp_sdl.cpp b/source/RSPiX/Src/BLUE/unix/Bdisp_sdl.cpp new file mode 100644 index 0000000..7527bbb --- /dev/null +++ b/source/RSPiX/Src/BLUE/unix/Bdisp_sdl.cpp @@ -0,0 +1,1341 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 RWS Inc, All Rights Reserved +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of version 2 of the GNU General Public License as published by +// the Free Software Foundation +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +/////////////////////////////////////////////////////////////////////////////// +// +// bdisp.cpp +// +// History: +// 06/04/04 RCG Started. +// +////////////////////////////////////////////////////////////////////////////// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include "SDL.h" +#include "Blue.h" +#include "ORANGE/CDT/slist.h" + +#include +#include + +extern SDL_Window *sdlWindow; +static char *sdlAppName; +static SDL_Renderer *sdlRenderer; +static SDL_Texture *sdlTexture; +static int RequestedWidth = 0; +static int RequestedHeight = 0; +static int FramebufferWidth = 0; +static int FramebufferHeight = 0; +static Uint32 *TexturePointer = NULL; +static Uint8 *PalettedTexturePointer = NULL; + +typedef struct // Stores information on usable video modes. + { + int16_t sWidth; + int16_t sHeight; + int16_t sColorDepth; + int16_t sPages; + } VIDEO_MODE, *PVIDEO_MODE; + +static RSList slvmModes; // List of available video modes. + +typedef union { struct { Uint8 b; Uint8 g; Uint8 r; Uint8 a; }; Uint32 argb; } ArgbColor; +static ArgbColor apeApp[256]; // App's palette. The palette + // entries the App actually set. +//Unused! Why? +//static ArgbColor apeMapped[256]; // Tweaked palette. + // This is the palette updated to + // the hardware. apeApp is trans- + // lated through au8MapRed, Green, + // and Blue and stored here for + // updating to the hardware on + // rspUpdatePalette(). + +static U8 au8MapRed[256]; // Map of red intensities to hardware + // values. Initially an identity + // mapping. +static U8 au8MapGreen[256]; // Map of green intensities to + // hardware values. Initially an + // identity mapping. +static U8 au8MapBlue[256]; // Map of blue intensities to hardware + // values. Initially an identity + // mapping. + +static int16_t asPalEntryLocks[256]; // TRUE, if an indexed entry is locked. + // FALSE, if not. Implemented as + // shorts in case we ever do levels of + // locking. + +extern bool mouse_grabbed; + +////////////////////////////////////////////////////////////////////////////// +// Module specific macros. +////////////////////////////////////////////////////////////////////////////// + +// Only set value if not NULL. +#define SET(ptr, val) ( ((ptr) != NULL) ? *(ptr) = (val) : 0) + + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t Clip( // Returns non-zero if image entirely clipped out. + int16_t* px, // Rectangle to be clipped. + int16_t* py, + int16_t* pw, + int16_t* ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) + { + if (*px < sx) + { + TRACE("Clip(): x too small.\n"); + // Adjust width. + *pw -= sx - *px; + // Adjust x. + *px = sx; + } + + if (*py < sy) + { + TRACE("Clip(): y too small.\n"); + // Adjust height. + *ph -= sy - *py; + // Adjust y. + *py = sy; + } + + if (*px + *pw > sw) + { + TRACE("Clip(): Width or x too large.\n"); + // Adjust width. + *pw -= ((*px + *pw) - sw); + } + + if (*py + *ph > sh) + { + TRACE("Clip(): Height or y too large.\n"); + // Adjust height. + *ph -= ((*py + *ph) - sh); + } + + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); + } + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int16_t* px, // Rectangle to be clipped. + int16_t* py, + int16_t* pw, + int16_t* ph, + int16_t sx, // Bounding rectangle. + int16_t sy, + int16_t sw, + int16_t sh) + { + if (*px < sx) + { + // Adjust width. + *pw -= sx - *px; + // Adjust x. + *px = sx; + } + + if (*py < sy) + { + // Adjust height. + *ph -= sy - *py; + // Adjust y. + *py = sy; + } + + if (*px + *pw > sw) + { + // Adjust width. + *pw -= ((*px + *pw) - sw); + } + + if (*py + *ph > sh) + { + // Adjust height. + *ph -= ((*py + *ph) - sh); + } + + // Return 0 (success) if there's a width and a height left. + return (int16_t)(*pw > 0 && *ph > 0 ? 0 : -1); + } + +////////////////////////////////////////////////////////////////////////////// +// +// Clips [(*px,*py),(*pw,*ph)] into [(sx,sy),(sw, sh)]. +// Uses short version of function ClipQuiet(...). +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t ClipQuiet( // Returns non-zero if image entirely clipped out. + int32_t* px, // Rectangle to be clipped. + int32_t* py, + int32_t* pw, + int32_t* ph, + int32_t sx, // Bounding rectangle. + int32_t sy, + int32_t sw, + int32_t sh) + { + int16_t sX = (int16_t)(*px); + int16_t sY = (int16_t)(*py); + int16_t sW = (int16_t)(*pw); + int16_t sH = (int16_t)(*ph); + + int16_t sRes = ClipQuiet(&sX, &sY, &sW, &sH, + (int16_t)sx, (int16_t)sy, (int16_t)sw, (int16_t)sh); + + *px = sX; + *py = sY; + *pw = sW; + *ph = sH; + + return sRes; + } + + +int16_t CompareModes(PVIDEO_MODE pvm1, PVIDEO_MODE pvm2); + +extern void Disp_Init(void) // Returns nothing. +{ + extern char **_argv; + const int arg = rspCommandLine("resolution"); + if ((arg) && (_argv[arg+1])) + { + if (SDL_sscanf(_argv[arg+1], "%dx%d", &RequestedWidth, &RequestedHeight) != 2) + RequestedWidth = RequestedHeight = 0; + } + + if ((RequestedWidth <= 0) || (RequestedHeight <= 0)) + { + if (rspCommandLine("windowed")) + { + RequestedWidth = 1024; + RequestedHeight = 768; + } + else + { + RequestedWidth = 0; + RequestedHeight = 0; + } + } + + // Initialize maps to indentities. + int16_t i; + for (i = 0; i < 256; i++) + { + au8MapRed[i] = i; + au8MapGreen[i] = i; + au8MapBlue[i] = i; + } + + // Never ever ever unlock these. + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; + + slvmModes.SetCompareFunc(CompareModes); +} + +extern void rspSetApplicationName( + char* pszName) // In: Application name +{ + SDL_free(sdlAppName); + sdlAppName = SDL_strdup(pszName); + if (sdlWindow) + SDL_SetWindowTitle(sdlWindow, sdlAppName); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Compares two video modes in order of sColorDepth, sWidth, sHeight, +// sPageFlippage. +// Returns 0 if *pvm1 == *pvm2. +// Returns negative if *pvm1 < *pvm2. +// Returns positive if *pvm1 > *pvm2. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t CompareModes( // Returns as described above. + PVIDEO_MODE pvm1, // First video mode to compare. + PVIDEO_MODE pvm2) // Second video mode to compare. + { + int16_t sRes = 1; // Assume *pvm1 > *pvm2. + + if (pvm1->sColorDepth == pvm2->sColorDepth) + { + if (pvm1->sWidth == pvm2->sWidth) + { + if (pvm1->sHeight == pvm2->sHeight) + { + if (pvm1->sPages == pvm2->sPages) + { + sRes = 0; + } + else + { + if (pvm1->sPages < pvm2->sPages) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sHeight < pvm2->sHeight) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sWidth < pvm2->sWidth) + { + sRes = -1; + } + } + } + else + { + if (pvm1->sColorDepth < pvm2->sColorDepth) + { + sRes = -1; + } + } + + return sRes; + } + + + +////////////////////////////////////////////////////////////////////////////// +// +// Attempts to find a mode that is sWidth by sHeight or larger +// with the given color depth. An available mode that closest matches +// the width and height is chosen, if successful. If no mode is found, +// *psWidth, *psHeight. If psPixelDoubling is not NULL and *psPixelDoubling +// is TRUE, a mode may be returned that requires pixel doubling. If a +// mode requires pixel doubling, *psPixelDoubling will be TRUE on return; +// otherwise, it will be FALSE. Passing psPixelDoubling as NULL is +// equivalent to passing *psPixelDoubling with FALSE. +// Utilizes rspQueryVideoMode to find the mode. Does not affect the current +// rspQueryVideoMode. +// This function should not be a part of Blue. It is always implementable +// via rspQueryVideoMode. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspSuggestVideoMode( // Returns 0 if successfull, non-zero otherwise + int16_t sDepth, // In: Required depth + int16_t sWidth, // In: Requested width + int16_t sHeight, // In: Requested height + int16_t sPages, // In: Required pages + int16_t sScaling, // In: Requested scaling + int16_t* psDeviceWidth /*= NULL*/, // Out: Suggested device width (unless NULL) + int16_t* psDeviceHeight /*= NULL*/, // Out: Suggested device height (unless NULL) + int16_t* psScaling /*= NULL*/) // Out: Suggested scaling (unless NULL) + { + int16_t sRes = 0; // Assume success. + + // Store video mode that the app is currently iterating. + PVIDEO_MODE pvmOldModeQuery = slvmModes.GetCurrent(); + + rspQueryVideoModeReset(); + + // Query results. + int16_t sModeWidth; + int16_t sModeHeight; + int16_t sModeColorDepth; + int16_t sModePages; + + // Best results. + int16_t sBestModeWidth = 16380; + int16_t sBestModeHeight = 16380; + int16_t sModeFound = FALSE; + + while (rspQueryVideoMode(&sModeColorDepth, &sModeWidth, &sModeHeight, &sModePages) == 0) + { + // Must be same color depth. + if (sModeColorDepth == sDepth && sPages == sModePages) + { + // If the desired resolution would fit into this mode . . . + if (sWidth <= sModeWidth && sHeight <= sModeHeight) + { + // If this mode is closer than a previous one . . . + float fFactorOld = ((float)sBestModeWidth * (float)sBestModeHeight) + / ((float)sWidth * (float)sHeight); + float fFactorNew = ((float)sModeWidth * (float)sModeHeight) + / ((float)sWidth * (float)sHeight); + if (fFactorNew < fFactorOld) + { + sBestModeWidth = sModeWidth; + sBestModeHeight = sModeHeight; + sModeFound = TRUE; + } + } + } + } + + // If we found an acceptable mode . . . + if (sModeFound != FALSE) + { + // If pixel doubling was specified . . . + if (psScaling != NULL) + { + // If pixel doubling is allowed . . . + if (sScaling != FALSE) + { + // If the chosen mode is more than or equal to twice the + // requested mode . . . + if (sWidth * 2 <= sBestModeWidth + && sHeight * 2 <= sBestModeHeight) + { + // Okay to pixel double. Leave *psPixelDoubling as TRUE. + // Reduce best width and height appropriately. + sBestModeWidth /= 2; + sBestModeHeight /= 2; + } + else + { + // No pixel doubling possible for this mode. + *psScaling = FALSE; + } + } + } + + *psDeviceWidth = sBestModeWidth; + *psDeviceHeight = sBestModeHeight; + } + else + { + // Failed to find an acceptable mode. + sRes = 1; + } + + return sRes; + } + +////////////////////////////////////////////////////////////////////////////// +// +// Puts parameters about the hardware video mode into your shorts. +// You may call this function even when in "no mode" (e.g., before +// rspSetVideoMode is first called, after it fails, or after rspKillVideMode +// is called). This way you can get information on the user's current mode. +// If in "no mode", psWidth, psHeight, and psPages will receive 0, if not NULL. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspGetVideoMode( + int16_t* psDeviceDepth, // Hardware display color depth returned here + // (unless NULL). + int16_t* psDeviceWidth, // Hardware display width returned here + // (unless NULL). + int16_t* psDeviceHeight, // Hardware display height returned here + // (unless NULL). + int16_t* psDevicePages, // Hardware display back buffers returned here + // (unless NULL). + int16_t* psWidth, // Display area width returned here + // (unless NULL). + int16_t* psHeight, // Display area height returned here + // (unless NULL). + int16_t* psPages/*= NULL*/, // Number of pages (1 to n) returned here + // (unless NULL). More than 1 indicates a + // page flipping scenario. + int16_t* psPixelScaling/*= NULL*/) // Pixel scaling in effect (1) or not (0) + // (unless NULL). +{ + // lie about everything. + SET(psPixelScaling, 0); + SET(psDevicePages, 0); + SET(psPages, 1); + SET(psWidth, FramebufferWidth); + SET(psHeight, FramebufferHeight); + SET(psDeviceDepth, 8); + SET(psDeviceHeight, FramebufferWidth); + SET(psDeviceWidth, FramebufferHeight); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Reset the query process. Must be called before calling QueryVideoModes() +// for the first time. See QueryVideoModes() for more. +// +////////////////////////////////////////////////////////////////////////////// + +static void addMode(int w, int h, int depth) +{ + PVIDEO_MODE pvm; + + if (depth >= 8) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 8; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } + + if (depth >= 16) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 16; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } + + if (depth >= 24) + { + pvm = new VIDEO_MODE; + pvm->sWidth = w; + pvm->sHeight = h; + pvm->sColorDepth = 32; + pvm->sPages = 1; + slvmModes.Insert(pvm); + } +} + +extern void rspQueryVideoModeReset(void) +{ + static bool enumerated = false; + if (!enumerated) + { + ASSERT(SDL_WasInit(SDL_INIT_VIDEO)); + + // Attempt to grab user's current desktop resolution instead of forcing 640x480 +#ifndef MOBILE + SDL_DisplayMode dm_Mode; + int i_Result = SDL_GetDesktopDisplayMode(0, &dm_Mode); + if (!i_Result) + addMode(dm_Mode.w, dm_Mode.h, 8); + else // Fall back to 640x480 +#endif + addMode(640, 480, 8); + + enumerated = true; + } + + slvmModes.GetHead(); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Query the available video modes. The modes are returned in sorted order +// based on increasing color depth, width, and height, in that order. The +// next time the function is called after the last actual mode was reported, +// it will return non-zero (failure) to indicate that no more modes are +// available, and will continue to do so until QueryVideoReset() is +// called to reset it back to the first video mode. When the return value is +// non-zero, the other parameters are not updated. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspQueryVideoMode( // Returns 0 for each valid mode, then non-zero thereafter + int16_t* psColorDepth, // Color depth (8, 15, 16, 24, 32) + // Unless NULL. + int16_t* psWidth /*= NULL*/, // Width returned here + // Unless NULL. + int16_t* psHeight /*= NULL*/, // Height returned here + // Unless NULL. + int16_t* psPages /*= NULL*/) // Number of video pages possible. + { + int16_t sRes = 0; // Assume success. + + PVIDEO_MODE pvm = slvmModes.GetCurrent(); + + if (pvm != NULL) + { + SET(psColorDepth, pvm->sColorDepth); + SET(psWidth, pvm->sWidth); + SET(psHeight, pvm->sHeight); + + SET(psPages, pvm->sPages); + + // Goto next video mode. + slvmModes.GetNext(); + } + else + { + sRes = 1; + } + + return sRes; + } + + +static SDL_Renderer *createRendererToggleVsync(SDL_Window *window, const int index, bool vsync) +{ + SDL_Renderer *retval = NULL; + +#if defined(SWITCH) || defined(PSP) + fprintf(stderr, ">> Create SDL_RENDERER_SOFTWARE %s\n", SDL_GetError()); + retval = SDL_CreateRenderer(window, index, SDL_RENDERER_SOFTWARE); +#else + if (vsync) + retval = SDL_CreateRenderer(window, index, SDL_RENDERER_PRESENTVSYNC); + if (!retval) + retval = SDL_CreateRenderer(window, index, 0); +#endif + return retval; +} + +static SDL_Renderer *createRendererByName(SDL_Window *window, const char *name) +{ + const bool vsync = !rspCommandLine("novsync"); + if (name == NULL) + return createRendererToggleVsync(window, -1, vsync); + else + { + const int max = SDL_GetNumRenderDrivers(); + for (int i = 0; i < max; i++) + { + SDL_RendererInfo info; + if ((SDL_GetRenderDriverInfo(i, &info) == 0) && (SDL_strcmp(info.name, name) == 0)) + return createRendererToggleVsync(window, i, vsync); + } + } + return NULL; +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Set a new video mode. Specified color depth, width, and height for the +// device is absolute. If these parameters cannot be met, the function will +// fail. If the requested resolution is higher than the requested display area, +// it will be centered with a black border around it. This function can be +// called multiple times to change modes, but it does not create new +// display areas; instead, the previous buffer is destroyed and a new buffer +// is created to take it's place. +// If pixel doubling is allowed (with rspAllowPixelDoubling) and the requested +// display area is less than or equal to half the requested hardware resolution, +// pixel doubling will be activated. +// If this function fails, you will be in no mode; meaning you may not access +// the display (i.e., call display/palette functions) even if you were in a mode +// before calling this function. See rspKillVideoMode. +// Before this function is called, you may not call functions that manipulate +// the display. +// +////////////////////////////////////////////////////////////////////////////// +extern int16_t rspSetVideoMode( // Returns 0 if successfull, non-zero otherwise + int16_t sDeviceDepth, // Specify required device video depth here. + int16_t sDeviceWidth, // Specify required device resolution width here. + int16_t sDeviceHeight, // Specify required device resolution height here. + int16_t sWidth, // Specify width of display area on screen. + int16_t sHeight, // Specify height of display area on screen. + int16_t sPages /*= 1*/, // Specify number of video pages. More than 1 + // indicates a page flipping scenario. + int16_t sPixelDoubling /*= FALSE*/) + // TRUE indicates to set the video mode + // to twice that indicated by sDeviceWidth, + // sDeviceHeight and double the coordinate + // system and blts. + // FALSE indicates not to use this garbage. + { + TRACE("rspSetVideoMode(%i, %i, %i, %i, %i, %i, %i)\n", sDeviceDepth, sDeviceWidth, sDeviceHeight, sWidth, sHeight, sPages, sPixelDoubling); + ASSERT(sDeviceDepth == 8); + //ASSERT(sDeviceWidth == 0); + //ASSERT(sDeviceHeight == 0); + //ASSERT(sWidth == 640); + ASSERT(sHeight == 480); + + for (size_t i = 0; i < 256; i++) + apeApp[i].a = 0xFF; + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + + if (sPixelDoubling) + { + fprintf(stderr, "STUBBED: pixel doubling? %s:%d\n", __FILE__, __LINE__); + return -1; + } + + FramebufferWidth = sWidth; + FramebufferHeight = sHeight; + + mouse_grabbed = !rspCommandLine("nomousegrab"); + + Uint32 flags = 0; + if (!rspCommandLine("windowed")) + { + if ((!RequestedWidth) || (!RequestedHeight)) + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + else + flags |= SDL_WINDOW_FULLSCREEN; + } + + if (mouse_grabbed) + flags |= SDL_WINDOW_INPUT_GRABBED; + +#if PLATFORM_IOS + flags |= SDL_WINDOW_BORDERLESS; // don't show the status bar +#endif + TRACE("RequestedWidth %d RequestedHeight %d\n",RequestedWidth,RequestedHeight); + + const char *title = sdlAppName ? sdlAppName : ""; + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sWidth, sHeight, SDL_WINDOW_FULLSCREEN); + if (!sdlWindow) + { + char buf[128]; + SDL_snprintf(buf, sizeof (buf), "Couldn't create window: %s.", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + int w = 0, h = 0; + SDL_GetWindowSize(sdlWindow, &w, &h); + TRACE("SDL Window initialized at %ix%i\n", w, h); + + bool bRequestedRenderer = true; + if (rspCommandLine("direct3d")) + sdlRenderer = createRendererByName(sdlWindow, "direct3d"); + else if (rspCommandLine("opengl")) + sdlRenderer = createRendererByName(sdlWindow, "opengl"); + else if (rspCommandLine("software")) + sdlRenderer = createRendererByName(sdlWindow, "software"); + else + { + bRequestedRenderer = false; + sdlRenderer = createRendererByName(sdlWindow, NULL); + } + + if (!sdlRenderer) + { + char buf[128]; + SDL_snprintf(buf, sizeof (buf), "Couldn't create %s renderer: %s", bRequestedRenderer ? "requested" : "a", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + + +TRACE("blah\n"); + + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); + SDL_RenderClear(sdlRenderer); + SDL_RenderPresent(sdlRenderer); +#ifndef MOBILE //Need to remove this for the mouse point to be in the correct place, Android And IOS + //SDL_RenderSetLogicalSize(sdlRenderer, FramebufferWidth, FramebufferHeight); + TRACE("SDL Renderer set: %ix%i\n", FramebufferWidth, FramebufferHeight); +#endif + sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 512, 512); + if (!sdlTexture) + { + char buf[128]; + SDL_snprintf(buf, sizeof (buf), "Couldn't create texture: %s", SDL_GetError()); + fprintf(stderr, "POSTAL: %s\n", buf); + SDL_DestroyRenderer(sdlRenderer); + sdlRenderer = NULL; + SDL_DestroyWindow(sdlWindow); + sdlWindow = NULL; + SDL_Quit(); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "POSTAL", buf, NULL); + exit(1); + } + + TexturePointer = new Uint32[FramebufferWidth * FramebufferHeight]; + PalettedTexturePointer = new Uint8[FramebufferWidth * FramebufferHeight]; + SDL_memset(TexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof (Uint32)); + SDL_memset(PalettedTexturePointer, '\0', FramebufferWidth * FramebufferHeight * sizeof (Uint8)); + SDL_UpdateTexture(sdlTexture, NULL, TexturePointer, FramebufferWidth * 4); + + SDL_ShowCursor(0); + //SDL_SetRelativeMouseMode(mouse_grabbed ? SDL_TRUE : SDL_FALSE); + + return 0; + } + +////////////////////////////////////////////////////////////////////////////// +// +// Puts you in a state of not having display access. After this function is +// called (similar to before rspSetVideoMode is called) you may not call +// functions that manipulate the display. This is similar to the situation +// achieved if rspSetVideoMode fails. +// +////////////////////////////////////////////////////////////////////////////// +extern void rspKillVideoMode(void) + { + /* no-op ... SDL_Quit() will catch this. */ + } + +////////////////////////////////////////////////////////////////////////////// +// +// Frees the memory (and, perhaps, structure(s)) associated with the memory +// stored in system RAM that is allocate rspSetVideoMode. If you are not +// using the system buffer (i.e., you are not calling rspLockVideoBuffer), +// you can call this to free up some additional memory. Calls to +// rspLockVideoBuffer will fail after a call to this function without a +// subsequent call to rspSetVideoMode. +// +////////////////////////////////////////////////////////////////////////////// +extern void rspKillVideoBuffer(void) + { + /* no-op ... SDL_Quit() will catch this. */ + } + +////////////////////////////////////////////////////////////////////////////// +// +// Variation #1: Update the entire display from the buffer. Includes +// pixel doubling as appropriate - see elsewhere for details. +// +////////////////////////////////////////////////////////////////////////////// + +extern void rspUpdateDisplayRects(void) +{ + // no-op, just blast it all to the GPU. +} + +extern void rspCacheDirtyRect( + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update +{ +} + +bool ValidateFrame(Uint32* frameBuffer, int width, int height) { + // Simple validation logic (customize based on your distortion patterns) + int invalidPixelCount = 0; + const int threshold = (width * height) / 10; // Example: 10% of pixels can be invalid + + for (int i = 0; i < width * height; i++) { + Uint32 pixel = frameBuffer[i]; + + // Check for corruption (e.g., all pixels are the same or too many black pixels) + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888), &r, &g, &b, &a); + + if (r == 0 && g == 0 && b == 0 && a == 255) { // Example: fully black pixels + invalidPixelCount++; + } + + if (invalidPixelCount > threshold) { + return false; // Frame is distorted + } + } + return true; // Frame is valid +} + +SDL_Surface* frameSurface = NULL; +SDL_Surface* scaledSurface = NULL; +extern void rspPresentFrame(void) +{ + if (!sdlWindow) return; + + // !!! FIXME: I imagine this is not fast. Maybe keep the dirty rect code at least? + ASSERT(sizeof (apeApp[0]) == sizeof (Uint32)); + const Uint8 *src = PalettedTexturePointer; + Uint32 *dst = TexturePointer; + for (int y = 0; y < FramebufferHeight; y++) + { + for (int x = 0; x < FramebufferWidth; x++, src++, dst++) + *dst = apeApp[*src].argb; + } + + int srcWidth = 640, srcHeight = 480; + int dstWidth = 480, dstHeight = 272; + + if (!frameSurface) { + frameSurface = SDL_CreateRGBSurfaceFrom( + TexturePointer, srcWidth, srcHeight, 32, + FramebufferWidth * 4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 + ); + if (!frameSurface) { + fprintf(stderr, "Failed to create SDL_Surface: %s\n", SDL_GetError()); + return; + } + } + + if (!scaledSurface) { + scaledSurface = SDL_CreateRGBSurfaceWithFormat(0, dstWidth, dstHeight, 32, SDL_PIXELFORMAT_ARGB8888); + if (!scaledSurface) { + fprintf(stderr, "Failed to create scaled SDL_Surface: %s\n", SDL_GetError()); + SDL_FreeSurface(frameSurface); + return; + } + } + + SDL_Rect srcRect = {0, 0, srcWidth, srcHeight}; + SDL_Rect dstRect = {0, 0, dstWidth, dstHeight}; + if (SDL_BlitScaled(frameSurface, &srcRect, scaledSurface, &dstRect) != 0) { + fprintf(stderr, "Failed to scale SDL_Surface: %s\n", SDL_GetError()); + return; + } + + SDL_Texture* frameTexture = SDL_CreateTextureFromSurface(sdlRenderer, scaledSurface); + if (!frameTexture) { + fprintf(stderr, "Failed to create SDL_Texture: %s\n", SDL_GetError()); + return; + } + + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, frameTexture, NULL, NULL); + SDL_RenderPresent(sdlRenderer); + + SDL_DestroyTexture(frameTexture); + + static Uint32 lastframeticks = 0; + const Uint32 now = SDL_GetTicks(); + + if ((lastframeticks) && (lastframeticks <= now)) + { + const Uint32 elapsed = (now - lastframeticks); + if (elapsed <= 5) // going WAY too fast, maybe OpenGL (and/or no vsync)? + SDL_Delay(16 - elapsed); // try to get closer to 60fps. + } + + lastframeticks = now; + + //#if 0 + static Uint32 ticks = 0; + static Uint32 frames = 0; + frames++; + if ((now - ticks) > 5000) + { + if (ticks > 0) + printf("fps: %f\n", (((double) frames) / ((double) (now - ticks))) * 1000.0); + ticks = now; + frames = 0; + } + //#endif +} + +extern void rspUpdateDisplay(void) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUpdateDisplay( + int16_t sX, // x coord of upper-left corner of area to update + int16_t sY, // y coord of upper-left corner of area to update + int16_t sWidth, // Width of area to update + int16_t sHeight) // Height of area to update +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoPage( // Returns 0 if screen memory could be locked. + // Returns non-zero otherwise. + void** ppvMemory, // Pointer to display memory returned here. + // NULL returned if not supported. + int32_t* plPitch) // Pitch of display memory returned here. + { + /* no-op. */ + return 1; + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoPage(void) // Returns nothing. + { + /* no-op. */ + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoFlipPage( // Returns 0 if flip screen memory could be + // locked. Returns non-zero otherwise. + void** ppvMemory, // Pointer to flip screen memory returned here. + // NULL returned on failure. + int32_t* plPitch) // Pitch of flip screen memory returned here. + { + return -1; + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoFlipPage(void) // Returns nothing. + { + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspLockVideoBuffer( // Returns 0 if system buffer could be locked. + // Returns non-zero otherwise. + void** ppvBuffer, // Pointer to system buffer returned here. + // NULL returned on failure. + int32_t* plPitch) // Pitch of system buffer returned here. + { + if (!sdlWindow) + return -1; + + *ppvBuffer = PalettedTexturePointer; + *plPitch = FramebufferWidth; + + return(0); + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockVideoBuffer(void) // Returns nothing. + { + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Maps calls to API that matches display type. +// See function comment in appropriate CPP (BGDisp/BXDisp). +// +/////////////////////////////////////////////////////////////////////////////// +extern int16_t rspAllowPageFlip(void) // Returns 0 on success. + { + return 0; + } + +////////////////////////////////////////////////////////////////////////////// +// External Palette module functions. +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// Set several palette entries. Separate pointers to each component +// combined with caller-specified increment for all pointers allows +// use of this function with any (non-packed) arrangement of RGB data. +// Hardware palette is not updated until UpdatePalette() is called. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetPaletteEntries( + int16_t sStartIndex, // Palette entry to start copying to (has no effect on source!) + int16_t sCount, // Number of palette entries to do + uint8_t* pucRed, // Pointer to first red component to copy from + uint8_t* pucGreen, // Pointer to first green component to copy from + uint8_t* pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy + { + // Set up destination pointers. + uint8_t* pucDstRed = &(apeApp[sStartIndex].r); + uint8_t* pucDstGreen = &(apeApp[sStartIndex].g); + uint8_t* pucDstBlue = &(apeApp[sStartIndex].b); + + // Set up lock pointer. + int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + if (*psLock++ == 0) + { + *pucDstRed = *pucRed; + *pucDstGreen = *pucGreen; + *pucDstBlue = *pucBlue; + } + + // Increment source. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + + // Increment destination. + pucDstRed += sizeof(apeApp[0]); + pucDstGreen += sizeof(apeApp[0]); + pucDstBlue += sizeof(apeApp[0]); + } + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Set palette entry. Hardware palette is not updated until +// UpdatePalette() is called. +// +/////////////////////////////////////////////////////////////////////////////// +void rspSetPaletteEntry( + int16_t sEntry, // Palette entry (0 to 255) + uint8_t ucRed, // Red component (0 to 255) + uint8_t ucGreen, // Green component (0 to 255) + uint8_t ucBlue) // Blue component (0 to 255) + { + ASSERT(sEntry >= 0 && sEntry < 256); + + if (asPalEntryLocks[sEntry] == 0) + { + apeApp[sEntry].r = ucRed; + apeApp[sEntry].g = ucGreen; + apeApp[sEntry].b = ucBlue; + } + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Get palette entry. This reflects the palette that may or may NOT have +// been set by calling rspUpdatePalette. +// +/////////////////////////////////////////////////////////////////////////////// +void rspGetPaletteEntry( + int16_t sEntry, // Palette entry (0 to 255) + int16_t* psRed, // Red component (0 to 255) returned if not NULL. + int16_t* psGreen, // Green component (0 to 255) returned if not NULL. + int16_t* psBlue) // Blue component (0 to 255) returned if not NULL. + { + ASSERT(sEntry >= 0 && sEntry < 256); + + SET(psRed, apeApp[sEntry].r); + SET(psGreen, apeApp[sEntry].g); + SET(psBlue, apeApp[sEntry].b); + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Get several palette entries. Separate pointers to each component +// combined with caller-specified increment for all pointers allows +// use of this function with any (non-packed) arrangement of RGB data. +// This is the palette that may not necessarily be updated yet in the hardware +// (i.e., some may have set the palette and not called UpdatePalette()). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspGetPaletteEntries( + int16_t sStartIndex, // Palette entry to start copying from + int16_t sCount, // Number of palette entries to do + uint8_t* pucRed, // Pointer to first red component to copy to + uint8_t* pucGreen, // Pointer to first green component to copy to + uint8_t* pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy + { + // Set up source pointers. + uint8_t* pucSrcRed = &(apeApp[sStartIndex].r); + uint8_t* pucSrcGreen = &(apeApp[sStartIndex].g); + uint8_t* pucSrcBlue = &(apeApp[sStartIndex].b); + + while (sCount-- > 0) + { + *pucRed = *pucSrcRed; + *pucGreen = *pucSrcGreen; + *pucBlue = *pucSrcBlue; + // Increment destination. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + + // Increment source. + pucSrcRed += sizeof(apeApp[0]); + pucSrcGreen += sizeof(apeApp[0]); + pucSrcBlue += sizeof(apeApp[0]); + } + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Update hardware palette using information that has been set +// using SetPaletteEntry() and SetPaletteEntries(). +// In the future, this may support optional VBLANK-synced updates. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspUpdatePalette(void) + { + } +/////////////////////////////////////////////////////////////////////////////// +// +// Set entries in the color map used to tweak values set via +// rspSetPaletteEntries(). Those colors' values will be used as indices +// into this map when rspUpdatePalette() is called. The resulting values +// will be updated to the hardware. +// rspGetPaletteEntries/Entry() will still return the original values set +// (not mapped values). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetPaletteMaps( + int16_t sStartIndex, // Map entry to start copying to (has no effect on source!) + int16_t sCount, // Number of map entries to do + uint8_t* pucRed, // Pointer to first red component to copy from + uint8_t* pucGreen, // Pointer to first green component to copy from + uint8_t* pucBlue, // Pointer to first blue component to copy from + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy + { + // Set up destination pointers. + uint8_t* pucDstRed = &(au8MapRed[sStartIndex]); + uint8_t* pucDstGreen = &(au8MapGreen[sStartIndex]); + uint8_t* pucDstBlue = &(au8MapBlue[sStartIndex]); + + while (sCount-- > 0) + { + *pucDstRed++ = *pucRed; + *pucDstGreen++ = *pucGreen; + *pucDstBlue++ = *pucBlue; + // Increment source. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + } + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Get entries in the color map used to tweak values set via +// rspSetPaletteEntries(). Those colors' values will be used as indices +// into this map when rspUpdatePalette() is called. The resulting values +// will be updated to the hardware. +// rspGetPaletteEntries/Entry() will still return the original values set +// (not mapped values). +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspGetPaletteMaps( + int16_t sStartIndex, // Map entry to start copying from (has no effect on dest!) + int16_t sCount, // Number of map entries to do + uint8_t* pucRed, // Pointer to first red component to copy to + uint8_t* pucGreen, // Pointer to first green component to copy to + uint8_t* pucBlue, // Pointer to first blue component to copy to + int32_t lIncBytes) // Number of bytes by which to increment pointers after each copy + { + // Set up source pointers. + uint8_t* pucSrcRed = &(au8MapRed[sStartIndex]); + uint8_t* pucSrcGreen = &(au8MapGreen[sStartIndex]); + uint8_t* pucSrcBlue = &(au8MapBlue[sStartIndex]); + + while (sCount-- > 0) + { + *pucRed = *pucSrcRed++; + *pucGreen = *pucSrcGreen++; + *pucBlue = *pucSrcBlue++; + // Increment destination. + pucRed += lIncBytes; + pucGreen += lIncBytes; + pucBlue += lIncBytes; + } + } + +/////////////////////////////////////////////////////////////////////////////// +// Lock several palette entries. Locking an entry keeps it from +// being updated by rspSetPaletteEntries() (until it is unlocked +// with rspUnlockPaletteEntries() ). +/////////////////////////////////////////////////////////////////////////////// +extern void rspLockPaletteEntries( + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. + { + // Set up iterator pointer. + int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + *psLock = TRUE; + } + } + +/////////////////////////////////////////////////////////////////////////////// +// Unlock several palette entries previously locked by rspLockPaletteEntries(). +/////////////////////////////////////////////////////////////////////////////// +extern void rspUnlockPaletteEntries( + int16_t sStartIndex, // Palette entry at which to start locking. + int16_t sCount) // Number of palette entries to lock. + { + // Set up iterator pointer. + int16_t* psLock = &(asPalEntryLocks[sStartIndex]); + + while (sCount-- > 0) + { + *psLock = FALSE; + } + + // Never ever ever unlock these. + asPalEntryLocks[0] = TRUE; + asPalEntryLocks[255] = TRUE; + } + +/////////////////////////////////////////////////////////////////////////////// +// Dyna schtuff. +/////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +// External Background module functions. +////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// Set a callback to be called when the application moves into the background. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetBackgroundCallback( // Returns nothing. + void (BackgroundCall)(void)) // Callback when app processing becomes + // background. NULL to clear. + { + /* no-op. */ + } + +/////////////////////////////////////////////////////////////////////////////// +// +// Set a callback to be called when the application moves into the foreground. +// +/////////////////////////////////////////////////////////////////////////////// +extern void rspSetForegroundCallback( // Returns nothing. + void (ForegroundCall)(void)) // Callback when app processing becomes + // foreground. NULL to clear. + { + /* no-op. */ + } + +extern int16_t rspIsBackground(void) // Returns TRUE if in background, FALSE otherwise + { + extern bool GSDLAppIsActive; + return (int16_t) (!GSDLAppIsActive); + } +////////////////////////////////////////////////////////////////////////////// +// EOF +////////////////////////////////////////////////////////////////////////////// + diff --git a/source/RSPiX/Src/GREEN/BLiT/BLIT.cpp b/source/RSPiX/Src/GREEN/BLiT/BLIT.cpp index 386b8aa..689f5bc 100644 --- a/source/RSPiX/Src/GREEN/BLiT/BLIT.cpp +++ b/source/RSPiX/Src/GREEN/BLiT/BLIT.cpp @@ -372,7 +372,8 @@ inline void _BLiT(PIXSIZE* pSrc,PIXSIZE* pDst,int32_t lSrcPitch, int32_t lDstPit inline void _BLiT_MA(uint8_t* pSrc,uint8_t* pDst,int32_t lSrcPitch, int32_t lDstPitch, int16_t sHeight,int16_t sWidth) { -#ifdef __ARM_NEON__ +#if defined(__ARM_NEON__) || defined(PSP) + //fprintf(stderr, ">> _BLiT_MA\n"); while (sHeight--) { memcpy(pDst, pSrc, sWidth); diff --git a/source/SND0.AT3 b/source/SND0.AT3 new file mode 100644 index 0000000..c29be92 Binary files /dev/null and b/source/SND0.AT3 differ diff --git a/source/game.cpp b/source/game.cpp index 3bf7f68..f2e0e53 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -1437,7 +1437,7 @@ static int16_t GameCore(void) // Returns 0 on success. // a game or two along the way. If there's no user input for a // certain amount of time, automatically run the self-playing demo. RInputEvent ie; - memset(&ie, '\0', sizeof (ie)); // fix valgrind complaining... --ryan. + memset(&ie, '\0', sizeof (ie)); // fix valgrind complaining... --ryan. while (sResult == 0) { // Clear the end of game flag each time just to be safe, it only needs diff --git a/source/main.cpp b/source/main.cpp index db166a5..a0bd005 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -777,6 +777,7 @@ int main(int argc, char **argv) fprintf(stderr, "Overclocking PSP\n"); scePowerSetClockFrequency(333, 333, 166); mkdir("ms0:/PSP/GAME/postal/savegame", 0777); + fprintf(stderr, "Current CPU Clock PSP: %d\n", scePowerGetCpuClockFrequency()); #endif assert_types_are_sane(); diff --git a/source/play.cpp b/source/play.cpp index 10ede53..9200e52 100644 --- a/source/play.cpp +++ b/source/play.cpp @@ -1392,7 +1392,7 @@ class CPlayGroup // Update the portion of the display. rspCacheDirtyRect(pdr->sX, pdr->sY, pdr->sW, pdr->sH); - fprintf(stderr, ">> rspCacheDirtyRect: %d, %d, %d, %d\n", pdr->sX, pdr->sY, pdr->sW, pdr->sH); + //fprintf(stderr, ">> rspCacheDirtyRect: %d, %d, %d, %d\n", pdr->sX, pdr->sY, pdr->sW, pdr->sH); pinfo->m_lSumUpdateDisplayTimes += (rspGetMilliseconds() - lTime); diff --git a/source/res/SND0.mp3 b/source/res/SND0.mp3 new file mode 100644 index 0000000..596d901 Binary files /dev/null and b/source/res/SND0.mp3 differ diff --git a/source/res/SND0.wav b/source/res/SND0.wav new file mode 100644 index 0000000..3a6fbe8 Binary files /dev/null and b/source/res/SND0.wav differ diff --git a/source/res/convert.bat b/source/res/convert.bat new file mode 100644 index 0000000..05d3e83 --- /dev/null +++ b/source/res/convert.bat @@ -0,0 +1 @@ +.\at3tool -e -wholeloop SND0.mp3 SND0.AT3 \ No newline at end of file diff --git a/source/res/title/logo2.bmp b/source/res/title/logo2.bmp new file mode 100644 index 0000000..12df1ca Binary files /dev/null and b/source/res/title/logo2.bmp differ