Path: blob/master/RSDKv5/RSDK/Graphics/SDL2/SDL2RenderDevice.cpp
1163 views
1SDL_Window *RenderDevice::window = nullptr;2SDL_Renderer *RenderDevice::renderer = nullptr;3SDL_Texture *RenderDevice::screenTexture[SCREEN_COUNT];45SDL_Texture *RenderDevice::imageTexture = nullptr;67uint32 RenderDevice::displayModeIndex = 0;8int32 RenderDevice::displayModeCount = 0;910unsigned long long RenderDevice::targetFreq = 0;11unsigned long long RenderDevice::curTicks = 0;12unsigned long long RenderDevice::prevTicks = 0;1314RenderVertex RenderDevice::vertexBuffer[!RETRO_REV02 ? 24 : 60];1516uint8 RenderDevice::lastTextureFormat = -1;1718#define NORMALIZE(val, minVal, maxVal) ((float)(val) - (float)(minVal)) / ((float)(maxVal) - (float)(minVal))1920bool RenderDevice::Init()21{22const char *gameTitle = gameVerInfo.gameTitle;2324SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS);2526uint8 flags = 0;2728#if RETRO_PLATFORM == RETRO_ANDROID29videoSettings.windowed = false;30SDL_DisplayMode dm;31SDL_GetDesktopDisplayMode(0, &dm);32float hdp = 0, vdp = 0;3334bool landscape = dm.h < dm.w;35int32 h = landscape ? dm.w : dm.h;36int32 w = landscape ? dm.h : dm.w;3738videoSettings.windowWidth = ((float)SCREEN_YSIZE * h / w);3940#elif RETRO_PLATFORM == RETRO_SWITCH41videoSettings.windowed = false;42videoSettings.windowWidth = 1920;43videoSettings.windowHeight = 1080;44flags |= SDL_WINDOW_FULLSCREEN;45#endif4647SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");48SDL_SetHint(SDL_HINT_RENDER_VSYNC, videoSettings.vsync ? "1" : "0");4950window = SDL_CreateWindow(gameTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, videoSettings.windowWidth, videoSettings.windowHeight,51SDL_WINDOW_ALLOW_HIGHDPI | flags);5253if (!window) {54PrintLog(PRINT_NORMAL, "ERROR: failed to create window!");55return false;56}5758if (!videoSettings.windowed) {59SDL_RestoreWindow(window);60SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);61SDL_ShowCursor(SDL_FALSE);62}6364if (!videoSettings.bordered) {65SDL_RestoreWindow(window);66SDL_SetWindowBordered(window, SDL_FALSE);67}6869PrintLog(PRINT_NORMAL, "w: %d h: %d windowed: %d", videoSettings.windowWidth, videoSettings.windowHeight, videoSettings.windowed);7071if (!SetupRendering() || !AudioDevice::Init())72return false;7374InitInputDevices();75return true;76}7778void RenderDevice::CopyFrameBuffer()79{80int32 pitch = 0;81uint16 *pixels = NULL;8283for (int32 s = 0; s < videoSettings.screenCount; ++s) {84SDL_LockTexture(screenTexture[s], NULL, (void **)&pixels, &pitch);8586uint16 *frameBuffer = screens[s].frameBuffer;87for (int32 y = 0; y < SCREEN_YSIZE; ++y) {88memcpy(pixels, frameBuffer, screens[s].size.x * sizeof(uint16));89frameBuffer += screens[s].pitch;90pixels += pitch / sizeof(uint16);91}9293SDL_UnlockTexture(screenTexture[s]);94}95}9697void RenderDevice::FlipScreen()98{99if (windowRefreshDelay > 0) {100windowRefreshDelay--;101if (!windowRefreshDelay)102UpdateGameWindow();103return;104}105106float dimAmount = videoSettings.dimMax * videoSettings.dimPercent;107108// Clear the screen. This is needed to keep the109// pillarboxes in fullscreen from displaying garbage data.110SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);111SDL_RenderClear(renderer);112113#if (SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2, 0, 18))114int32 startVert = 0;115switch (videoSettings.screenCount) {116default:117case 0:118#if RETRO_REV02119startVert = 54;120#else121startVert = 18;122#endif123SDL_RenderGeometryRaw(renderer, imageTexture, &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),124(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,125sizeof(RenderVertex), 6, NULL, 0, 0);126break;127128case 1:129startVert = 0;130SDL_RenderGeometryRaw(renderer, screenTexture[0], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),131(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,132sizeof(RenderVertex), 6, NULL, 0, 0);133break;134135case 2:136#if RETRO_REV02137startVert = startVertex_2P[0];138#else139startVert = 6;140#endif141SDL_RenderGeometryRaw(renderer, screenTexture[0], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),142(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,143sizeof(RenderVertex), 6, NULL, 0, 0);144145#if RETRO_REV02146startVert = startVertex_2P[1];147#else148startVert = 12;149#endif150SDL_RenderGeometryRaw(renderer, screenTexture[1], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),151(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,152sizeof(RenderVertex), 6, NULL, 0, 0);153break;154155#if RETRO_REV02156case 3:157startVert = startVertex_3P[0];158SDL_RenderGeometryRaw(renderer, screenTexture[0], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),159(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,160sizeof(RenderVertex), 6, NULL, 0, 0);161162startVert = startVertex_3P[1];163SDL_RenderGeometryRaw(renderer, screenTexture[1], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),164(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,165sizeof(RenderVertex), 6, NULL, 0, 0);166167startVert = startVertex_3P[2];168SDL_RenderGeometryRaw(renderer, screenTexture[2], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),169(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,170sizeof(RenderVertex), 6, NULL, 0, 0);171break;172173case 4:174startVert = 30;175SDL_RenderGeometryRaw(renderer, screenTexture[0], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),176(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,177sizeof(RenderVertex), 6, NULL, 0, 0);178179startVert = 36;180SDL_RenderGeometryRaw(renderer, screenTexture[1], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),181(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,182sizeof(RenderVertex), 6, NULL, 0, 0);183184startVert = 42;185SDL_RenderGeometryRaw(renderer, screenTexture[2], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),186(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,187sizeof(RenderVertex), 6, NULL, 0, 0);188189startVert = 48;190SDL_RenderGeometryRaw(renderer, screenTexture[3], &vertexBuffer[startVert].pos.x, sizeof(RenderVertex),191(SDL_Color *)&vertexBuffer[startVert].color, sizeof(RenderVertex), &vertexBuffer[startVert].tex.x,192sizeof(RenderVertex), 6, NULL, 0, 0);193break;194#endif195}196#else197int32 startVert = 0;198SDL_Rect src, dst;199200// some cheating for today201#define _SET_RECTS \202dst.x = vertexBuffer[startVert].pos.x; \203dst.y = vertexBuffer[startVert].pos.y; \204dst.w = vertexBuffer[startVert + 2].pos.x - dst.x; \205dst.h = vertexBuffer[startVert + 2].pos.y - dst.y; \206src.x = vertexBuffer[startVert].tex.x * textureSize.x; \207src.y = vertexBuffer[startVert].tex.y * textureSize.y; \208src.w = vertexBuffer[startVert + 2].tex.x * textureSize.x - src.x; \209src.h = vertexBuffer[startVert + 2].tex.y * textureSize.y - src.y;210211switch (videoSettings.screenCount) {212default:213case 0:214#if RETRO_REV02215startVert = 54;216#else217startVert = 18;218#endif219_SET_RECTS;220src.w = vertexBuffer[startVert + 2].tex.x * 1024 - src.x;221src.h = vertexBuffer[startVert + 2].tex.y * 512 - src.y;222SDL_RenderCopy(renderer, imageTexture, &src, &dst);223break;224225case 1:226startVert = 0;227_SET_RECTS;228229SDL_RenderCopy(renderer, screenTexture[0], &src, &dst);230break;231232case 2:233#if RETRO_REV02234startVert = startVertex_2P[0];235#else236startVert = 6;237#endif238_SET_RECTS;239240SDL_RenderCopy(renderer, screenTexture[0], &src, &dst);241242#if RETRO_REV02243startVert = startVertex_2P[1];244#else245startVert = 12;246#endif247_SET_RECTS;248249SDL_RenderCopy(renderer, screenTexture[1], &src, &dst);250break;251252#if RETRO_REV02253case 3:254startVert = startVertex_3P[0];255_SET_RECTS;256257SDL_RenderCopy(renderer, screenTexture[0], &src, &dst);258259startVert = startVertex_3P[1];260_SET_RECTS;261262SDL_RenderCopy(renderer, screenTexture[1], &src, &dst);263264startVert = startVertex_3P[2];265_SET_RECTS;266267SDL_RenderCopy(renderer, screenTexture[2], &src, &dst);268269break;270271case 4:272startVert = 30;273_SET_RECTS;274275SDL_RenderCopy(renderer, screenTexture[0], &src, &dst);276277startVert = 36;278_SET_RECTS;279280SDL_RenderCopy(renderer, screenTexture[1], &src, &dst);281282startVert = 42;283_SET_RECTS;284285SDL_RenderCopy(renderer, screenTexture[2], &src, &dst);286287startVert = 48;288_SET_RECTS;289290SDL_RenderCopy(renderer, screenTexture[3], &src, &dst);291292break;293#endif294}295#endif296if (dimAmount < 1.0f) {297SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF - (dimAmount * 0xFF));298SDL_RenderFillRect(renderer, NULL);299}300// no change here301SDL_RenderPresent(renderer);302}303304void RenderDevice::Release(bool32 isRefresh)305{306for (int32 s = 0; s < SCREEN_COUNT; ++s) {307if (screenTexture[s])308SDL_DestroyTexture(screenTexture[s]);309screenTexture[s] = NULL;310}311312if (imageTexture)313SDL_DestroyTexture(imageTexture);314imageTexture = NULL;315316if (!isRefresh) {317if (displayInfo.displays)318free(displayInfo.displays);319displayInfo.displays = NULL;320}321322if (!isRefresh && renderer)323SDL_DestroyRenderer(renderer);324325if (!isRefresh && window)326SDL_DestroyWindow(window);327328if (!isRefresh)329SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_EVENTS);330331if (!isRefresh) {332if (scanlines)333free(scanlines);334scanlines = NULL;335}336}337338void RenderDevice::RefreshWindow()339{340videoSettings.windowState = WINDOWSTATE_UNINITIALIZED;341342Release(true);343344SDL_HideWindow(window);345346if (videoSettings.windowed && videoSettings.bordered)347SDL_SetWindowBordered(window, SDL_TRUE);348else349SDL_SetWindowBordered(window, SDL_FALSE);350351GetDisplays();352353SDL_Rect winRect;354winRect.x = SDL_WINDOWPOS_CENTERED;355winRect.y = SDL_WINDOWPOS_CENTERED;356if (videoSettings.windowed || !videoSettings.exclusiveFS) {357int32 currentWindowDisplay = SDL_GetWindowDisplayIndex(window);358SDL_DisplayMode displayMode;359SDL_GetCurrentDisplayMode(currentWindowDisplay, &displayMode);360361if (videoSettings.windowed) {362if (videoSettings.windowWidth >= displayMode.w || videoSettings.windowHeight >= displayMode.h) {363videoSettings.windowWidth = (displayMode.h / 480 * videoSettings.pixWidth);364videoSettings.windowHeight = displayMode.h / 480 * videoSettings.pixHeight;365}366367winRect.w = videoSettings.windowWidth;368winRect.h = videoSettings.windowHeight;369SDL_SetWindowFullscreen(window, SDL_FALSE);370SDL_ShowCursor(SDL_FALSE);371}372else {373winRect.w = displayMode.w;374winRect.h = displayMode.h;375SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);376SDL_ShowCursor(SDL_TRUE);377}378379SDL_SetWindowSize(window, winRect.w, winRect.h);380SDL_SetWindowPosition(window, winRect.x, winRect.y);381}382383SDL_ShowWindow(window);384385if (!InitGraphicsAPI() || !InitShaders())386return;387388videoSettings.windowState = WINDOWSTATE_ACTIVE;389}390391void RenderDevice::InitFPSCap()392{393targetFreq = SDL_GetPerformanceFrequency() / videoSettings.refreshRate;394curTicks = 0;395prevTicks = 0;396}397bool RenderDevice::CheckFPSCap()398{399curTicks = SDL_GetPerformanceCounter();400if (curTicks >= prevTicks + targetFreq)401return true;402403return false;404}405void RenderDevice::UpdateFPSCap() { prevTicks = curTicks; }406407void RenderDevice::InitVertexBuffer()408{409RenderVertex vertBuffer[sizeof(rsdkVertexBuffer) / sizeof(RenderVertex)];410memcpy(vertBuffer, rsdkVertexBuffer, sizeof(rsdkVertexBuffer));411412// ignore the last 6 verts, they're scaled to the 1024x512 textures already!413int32 vertCount = (RETRO_REV02 ? 60 : 24) - 6;414415// Regular in-game screen de-normalization stuff416for (int32 v = 0; v < vertCount; ++v) {417RenderVertex *vertex = &vertBuffer[v];418vertex->pos.x = NORMALIZE(vertex->pos.x, -1.0, 1.0) * videoSettings.pixWidth;419vertex->pos.y = (1.0 - NORMALIZE(vertex->pos.y, -1.0, 1.0)) * SCREEN_YSIZE;420421if (vertex->tex.x)422vertex->tex.x = screens[0].size.x * (1.0 / textureSize.x);423424if (vertex->tex.y)425vertex->tex.y = screens[0].size.y * (1.0 / textureSize.y);426}427428// Fullscreen Image/Video de-normalization stuff429for (int32 v = 0; v < 6; ++v) {430RenderVertex *vertex = &vertBuffer[vertCount + v];431vertex->pos.x = NORMALIZE(vertex->pos.x, -1.0, 1.0) * videoSettings.pixWidth;432vertex->pos.y = (1.0 - NORMALIZE(vertex->pos.y, -1.0, 1.0)) * SCREEN_YSIZE;433434// Set the texture to fill the entire screen with all 1024x512 pixels435if (vertex->tex.x)436vertex->tex.x = 1.0f;437438if (vertex->tex.y)439vertex->tex.y = 1.0f;440}441442memcpy(vertexBuffer, vertBuffer, sizeof(vertBuffer));443}444445bool RenderDevice::InitGraphicsAPI()446{447videoSettings.shaderSupport = false;448449viewSize.x = 0;450viewSize.y = 0;451452if (videoSettings.windowed || !videoSettings.exclusiveFS) {453if (videoSettings.windowed) {454viewSize.x = videoSettings.windowWidth;455viewSize.y = videoSettings.windowHeight;456}457else {458viewSize.x = displayWidth[displayModeIndex];459viewSize.y = displayHeight[displayModeIndex];460}461}462else {463int32 bufferWidth = videoSettings.fsWidth;464int32 bufferHeight = videoSettings.fsHeight;465if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {466bufferWidth = displayWidth[displayModeIndex];467bufferHeight = displayHeight[displayModeIndex];468}469470viewSize.x = bufferWidth;471viewSize.y = bufferHeight;472}473474SDL_SetWindowSize(window, viewSize.x, viewSize.y);475SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);476477int32 maxPixHeight = 0;478#if !RETRO_USE_ORIGINAL_CODE479int32 screenWidth = 0;480#endif481for (int32 s = 0; s < 4; ++s) {482if (videoSettings.pixHeight > maxPixHeight)483maxPixHeight = videoSettings.pixHeight;484485screens[s].size.y = videoSettings.pixHeight;486487float viewAspect = viewSize.x / viewSize.y;488#if !RETRO_USE_ORIGINAL_CODE489screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;490#else491int32 screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;492#endif493if (screenWidth < videoSettings.pixWidth)494screenWidth = videoSettings.pixWidth;495496#if !RETRO_USE_ORIGINAL_CODE497if (customSettings.maxPixWidth && screenWidth > customSettings.maxPixWidth)498screenWidth = customSettings.maxPixWidth;499#else500if (screenWidth > DEFAULT_PIXWIDTH)501screenWidth = DEFAULT_PIXWIDTH;502#endif503504memset(&screens[s].frameBuffer, 0, sizeof(screens[s].frameBuffer));505SetScreenSize(s, screenWidth, screens[s].size.y);506}507508pixelSize.x = screens[0].size.x;509pixelSize.y = screens[0].size.y;510511SDL_RenderSetLogicalSize(renderer, videoSettings.pixWidth, SCREEN_YSIZE);512SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);513514#if !RETRO_USE_ORIGINAL_CODE515if (screenWidth <= 512 && maxPixHeight <= 256) {516#else517if (maxPixHeight <= 256) {518#endif519textureSize.x = 512.0;520textureSize.y = 256.0;521}522else {523textureSize.x = 1024.0;524textureSize.y = 512.0;525}526SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");527for (int32 s = 0; s < SCREEN_COUNT; ++s) {528screenTexture[s] = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, textureSize.x, textureSize.y);529530if (!screenTexture[s]) {531PrintLog(PRINT_NORMAL, "ERROR: failed to create screen buffer!\nerror msg: %s", SDL_GetError());532return 0;533}534}535SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");536imageTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H);537if (!imageTexture)538return false;539SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");540541lastShaderID = -1;542InitVertexBuffer();543engine.inFocus = 1;544videoSettings.viewportX = 0;545videoSettings.viewportY = 0;546videoSettings.viewportW = 1.0 / viewSize.x;547videoSettings.viewportH = 1.0 / viewSize.y;548549return true;550}551552void RenderDevice::LoadShader(const char *fileName, bool32 linear) { PrintLog(PRINT_NORMAL, "This render device does not support shaders!"); }553554bool RenderDevice::InitShaders()555{556int32 maxShaders = 0;557#if RETRO_USE_MOD_LOADER558// who knows maybe SDL3 will have shaders559shaderCount = 0;560#endif561562if (videoSettings.shaderSupport) {563LoadShader("None", false);564LoadShader("Clean", true);565LoadShader("CRT-Yeetron", true);566LoadShader("CRT-Yee64", true);567568#if RETRO_USE_MOD_LOADER569// a place for mods to load custom shaders570RunModCallbacks(MODCB_ONSHADERLOAD, NULL);571userShaderCount = shaderCount;572#endif573574LoadShader("YUV-420", true);575LoadShader("YUV-422", true);576LoadShader("YUV-444", true);577LoadShader("RGB-Image", true);578maxShaders = shaderCount;579}580else {581for (int32 s = 0; s < SHADER_COUNT; ++s) shaderList[s].linear = true;582583shaderList[0].linear = videoSettings.windowed ? false : shaderList[0].linear;584maxShaders = 1;585shaderCount = 1;586}587588videoSettings.shaderID = videoSettings.shaderID >= maxShaders ? 0 : videoSettings.shaderID;589590return true;591}592593bool RenderDevice::SetupRendering()594{595renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);596597if (!renderer) {598PrintLog(PRINT_NORMAL, "ERROR: failed to create renderer!");599return false;600}601602GetDisplays();603604if (!InitGraphicsAPI() || !InitShaders())605return false;606607int32 size = videoSettings.pixWidth >= SCREEN_YSIZE ? videoSettings.pixWidth : SCREEN_YSIZE;608scanlines = (ScanlineInfo *)malloc(size * sizeof(ScanlineInfo));609memset(scanlines, 0, size * sizeof(ScanlineInfo));610611videoSettings.windowState = WINDOWSTATE_ACTIVE;612videoSettings.dimMax = 1.0;613videoSettings.dimPercent = 1.0;614615return true;616}617618void RenderDevice::GetDisplays()619{620int32 currentWindowDisplay = SDL_GetWindowDisplayIndex(window);621622int32 dispCount = SDL_GetNumVideoDisplays();623624SDL_DisplayMode currentDisplay;625SDL_GetCurrentDisplayMode(currentWindowDisplay, ¤tDisplay);626627displayModeIndex = 0;628for (int32 a = 0; a < dispCount; ++a) {629SDL_DisplayMode displayMode;630631SDL_GetCurrentDisplayMode(currentWindowDisplay, &displayMode);632displayWidth[a] = displayMode.w;633displayHeight[a] = displayMode.h;634635if (memcmp(¤tDisplay, &displayMode, sizeof(displayMode)) == 0) {636displayModeIndex = a;637}638}639640displayCount = SDL_GetNumDisplayModes(currentWindowDisplay);641if (displayInfo.displays)642free(displayInfo.displays);643644displayInfo.displays = (decltype(displayInfo.displays))malloc(sizeof(SDL_DisplayMode) * displayCount);645int32 newDisplayCount = 0;646bool32 foundFullScreenDisplay = false;647648for (int32 d = displayCount - 1; d >= 0; --d) {649SDL_GetDisplayMode(currentWindowDisplay, d, &displayInfo.displays[newDisplayCount].internal);650651int32 refreshRate = displayInfo.displays[newDisplayCount].refresh_rate;652if (refreshRate >= 59 && (refreshRate <= 60 || refreshRate >= 120) && displayInfo.displays[newDisplayCount].height >= (SCREEN_YSIZE * 2)) {653if (newDisplayCount != 0 && refreshRate == 60 && displayInfo.displays[newDisplayCount - 1].refresh_rate == 59) {654memcpy(&displayInfo.displays[newDisplayCount - 1], &displayInfo.displays[newDisplayCount], sizeof(displayInfo.displays[0]));655--newDisplayCount;656}657658if (videoSettings.fsWidth == displayInfo.displays[newDisplayCount].width659&& videoSettings.fsHeight == displayInfo.displays[newDisplayCount].height)660foundFullScreenDisplay = true;661662++newDisplayCount;663}664}665666displayCount = newDisplayCount;667if (!foundFullScreenDisplay) {668videoSettings.fsWidth = 0;669videoSettings.fsHeight = 0;670videoSettings.refreshRate = 60; // 0;671}672}673674void RenderDevice::GetWindowSize(int32 *width, int32 *height)675{676if (!videoSettings.windowed) {677SDL_GetRendererOutputSize(renderer, width, height);678}679else {680int32 currentWindowDisplay = SDL_GetWindowDisplayIndex(window);681682SDL_DisplayMode display;683SDL_GetCurrentDisplayMode(currentWindowDisplay, &display);684685if (width)686*width = display.w;687688if (height)689*height = display.h;690}691}692693void RenderDevice::ProcessEvent(SDL_Event event)694{695switch (event.type) {696case SDL_WINDOWEVENT:697switch (event.window.event) {698case SDL_WINDOWEVENT_MAXIMIZED: {699SDL_RestoreWindow(window);700SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);701SDL_ShowCursor(SDL_FALSE);702videoSettings.windowed = false;703break;704}705706case SDL_WINDOWEVENT_CLOSE: isRunning = false; break;707708case SDL_WINDOWEVENT_FOCUS_GAINED:709#if RETRO_REV02710SKU::userCore->focusState = 0;711#endif712break;713714case SDL_WINDOWEVENT_FOCUS_LOST:715#if RETRO_REV02716SKU::userCore->focusState = 1;717#endif718break;719}720break;721722case SDL_CONTROLLERDEVICEADDED: {723SDL_GameController *game_controller = SDL_GameControllerOpen(event.cdevice.which);724725if (game_controller != NULL) {726uint32 id;727char idBuffer[0x20];728sprintf_s(idBuffer, sizeof(idBuffer), "SDLDevice%d", SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(game_controller)));729GenerateHashCRC(&id, idBuffer);730731if (SKU::InitSDL2InputDevice(id, game_controller) == NULL)732SDL_GameControllerClose(game_controller);733}734735break;736}737738case SDL_CONTROLLERDEVICEREMOVED: {739uint32 id;740char idBuffer[0x20];741sprintf_s(idBuffer, sizeof(idBuffer), "SDLDevice%d", event.cdevice.which);742GenerateHashCRC(&id, idBuffer);743744RemoveInputDevice(InputDeviceFromID(id));745break;746}747748case SDL_APP_WILLENTERFOREGROUND:749#if RETRO_REV02750SKU::userCore->focusState = 0;751#endif752break;753754case SDL_APP_WILLENTERBACKGROUND:755#if RETRO_REV02756SKU::userCore->focusState = 1;757#endif758break;759760case SDL_APP_TERMINATING: isRunning = false; break;761762case SDL_MOUSEBUTTONDOWN:763switch (event.button.button) {764case SDL_BUTTON_LEFT: touchInfo.down[0] = true; touchInfo.count = 1;765#if !RETRO_REV02766RSDK::SKU::buttonDownCount++;767#endif768break;769770case SDL_BUTTON_RIGHT:771#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD772RSDK::SKU::specialKeyStates[3] = true;773RSDK::SKU::buttonDownCount++;774#endif775break;776}777break;778779case SDL_MOUSEBUTTONUP:780switch (event.button.button) {781case SDL_BUTTON_LEFT: touchInfo.down[0] = false; touchInfo.count = 0;782#if !RETRO_REV02783RSDK::SKU::buttonDownCount--;784#endif785break;786787case SDL_BUTTON_RIGHT:788#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD789RSDK::SKU::specialKeyStates[3] = false;790RSDK::SKU::buttonDownCount--;791#endif792break;793}794break;795796case SDL_FINGERMOTION:797case SDL_FINGERDOWN:798case SDL_FINGERUP: {799int32 count = SDL_GetNumTouchFingers(event.tfinger.touchId);800touchInfo.count = 0;801for (int32 i = 0; i < count; i++) {802SDL_Finger *finger = SDL_GetTouchFinger(event.tfinger.touchId, i);803if (finger) {804touchInfo.down[touchInfo.count] = true;805touchInfo.x[touchInfo.count] = finger->x;806touchInfo.y[touchInfo.count] = finger->y;807touchInfo.count++;808}809}810break;811}812813case SDL_KEYDOWN:814#if !RETRO_REV02815++RSDK::SKU::buttonDownCount;816#endif817switch (event.key.keysym.scancode) {818case SDL_SCANCODE_RETURN:819if (event.key.keysym.mod & KMOD_LALT) {820videoSettings.windowed ^= 1;821UpdateGameWindow();822changedVideoSettings = false;823break;824}825826#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD827RSDK::SKU::specialKeyStates[1] = true;828#endif829// [fallthrough]830831default:832#if RETRO_INPUTDEVICE_KEYBOARD833SKU::UpdateKeyState(event.key.keysym.scancode);834#endif835break;836837case SDL_SCANCODE_ESCAPE:838if (engine.devMenu) {839#if RETRO_REV0U840if (sceneInfo.state == ENGINESTATE_DEVMENU || RSDK::Legacy::gameMode == RSDK::Legacy::ENGINE_DEVMENU)841#else842if (sceneInfo.state == ENGINESTATE_DEVMENU)843#endif844CloseDevMenu();845else846OpenDevMenu();847}848else {849#if RETRO_INPUTDEVICE_KEYBOARD850SKU::UpdateKeyState(event.key.keysym.scancode);851#endif852}853854#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD855RSDK::SKU::specialKeyStates[0] = true;856#endif857break;858859#if !RETRO_USE_ORIGINAL_CODE860case SDL_SCANCODE_F1:861if (engine.devMenu) {862sceneInfo.listPos--;863while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart864|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd865|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {866sceneInfo.activeCategory--;867if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {868sceneInfo.activeCategory = sceneInfo.categoryCount - 1;869}870sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd - 1;871}872873#if RETRO_REV0U874switch (engine.version) {875default: break;876case 5: LoadScene(); break;877case 4:878case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;879}880#else881LoadScene();882#endif883}884break;885886case SDL_SCANCODE_F2:887if (engine.devMenu) {888sceneInfo.listPos++;889while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart890|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd891|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {892sceneInfo.activeCategory++;893if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {894sceneInfo.activeCategory = 0;895}896sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart;897}898899#if RETRO_REV0U900switch (engine.version) {901default: break;902case 5: LoadScene(); break;903case 4:904case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;905}906#else907LoadScene();908#endif909}910break;911#endif912913case SDL_SCANCODE_F3:914if (userShaderCount)915videoSettings.shaderID = (videoSettings.shaderID + 1) % userShaderCount;916break;917918#if !RETRO_USE_ORIGINAL_CODE919case SDL_SCANCODE_F4:920if (engine.devMenu)921engine.showEntityInfo ^= 1;922break;923924case SDL_SCANCODE_F5:925if (engine.devMenu) {926// Quick-Reload927#if RETRO_USE_MOD_LOADER928if (event.key.keysym.mod & KMOD_LCTRL)929RefreshModFolders();930#endif931932#if RETRO_REV0U933switch (engine.version) {934default: break;935case 5: LoadScene(); break;936case 4:937case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;938}939#else940LoadScene();941#endif942}943break;944945case SDL_SCANCODE_F6:946if (engine.devMenu && videoSettings.screenCount > 1)947videoSettings.screenCount--;948break;949950case SDL_SCANCODE_F7:951if (engine.devMenu && videoSettings.screenCount < SCREEN_COUNT)952videoSettings.screenCount++;953break;954955case SDL_SCANCODE_F8:956if (engine.devMenu)957engine.showUpdateRanges ^= 1;958break;959960case SDL_SCANCODE_F9:961if (engine.devMenu)962showHitboxes ^= 1;963break;964965case SDL_SCANCODE_F10:966if (engine.devMenu)967engine.showPaletteOverlay ^= 1;968break;969#endif970case SDL_SCANCODE_BACKSPACE:971if (engine.devMenu)972engine.gameSpeed = engine.fastForwardSpeed;973break;974975case SDL_SCANCODE_F11:976case SDL_SCANCODE_INSERT:977if (engine.devMenu)978engine.frameStep = true;979break;980981case SDL_SCANCODE_F12:982case SDL_SCANCODE_PAUSE:983if (engine.devMenu) {984#if RETRO_REV0U985switch (engine.version) {986default: break;987case 5:988if (sceneInfo.state != ENGINESTATE_NONE)989sceneInfo.state ^= ENGINESTATE_STEPOVER;990break;991case 4:992case 3:993if (RSDK::Legacy::stageMode != ENGINESTATE_NONE)994RSDK::Legacy::stageMode ^= RSDK::Legacy::STAGEMODE_STEPOVER;995break;996}997#else998if (sceneInfo.state != ENGINESTATE_NONE)999sceneInfo.state ^= ENGINESTATE_STEPOVER;1000#endif1001}1002break;1003}1004break;10051006case SDL_KEYUP:1007#if !RETRO_REV021008--RSDK::SKU::buttonDownCount;1009#endif1010switch (event.key.keysym.scancode) {1011default:1012#if RETRO_INPUTDEVICE_KEYBOARD1013SKU::ClearKeyState(event.key.keysym.scancode);1014#endif1015break;10161017#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1018case SDL_SCANCODE_ESCAPE:1019RSDK::SKU::specialKeyStates[0] = false;1020SKU::ClearKeyState(event.key.keysym.scancode);1021break;10221023case SDL_SCANCODE_RETURN:1024RSDK::SKU::specialKeyStates[1] = false;1025SKU::ClearKeyState(event.key.keysym.scancode);1026break;1027#endif1028case SDL_SCANCODE_BACKSPACE: engine.gameSpeed = 1; break;1029}1030break;10311032case SDL_QUIT: isRunning = false; break;1033}1034}10351036bool RenderDevice::ProcessEvents()1037{1038SDL_Event sdlEvent;10391040while (SDL_PollEvent(&sdlEvent)) {1041ProcessEvent(sdlEvent);10421043if (!isRunning)1044return false;1045}10461047return isRunning;1048}10491050void RenderDevice::SetupImageTexture(int32 width, int32 height, uint8 *imagePixels)1051{1052if (lastTextureFormat != SHADER_RGB_IMAGE) {1053if (imageTexture)1054SDL_DestroyTexture(imageTexture);1055SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");10561057imageTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);1058SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");10591060lastTextureFormat = SHADER_RGB_IMAGE;1061}10621063int32 texPitch = 0;1064uint32 *pixels = NULL;1065SDL_LockTexture(imageTexture, NULL, (void **)&pixels, &texPitch);10661067int32 pitch = (texPitch >> 2) - width;1068uint32 *imagePixels32 = (uint32 *)imagePixels;1069for (int32 y = 0; y < height; ++y) {1070for (int32 x = 0; x < width; ++x) {1071*pixels++ = *imagePixels32++;1072}10731074pixels += pitch;1075}10761077SDL_UnlockTexture(imageTexture);1078}10791080void RenderDevice::SetupVideoTexture_YUV420(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1081int32 strideV)1082{1083if (lastTextureFormat != SHADER_YUV_420) {1084if (imageTexture)1085SDL_DestroyTexture(imageTexture);1086SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");10871088imageTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, width, height);10891090SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");1091lastTextureFormat = SHADER_YUV_420;1092}10931094SDL_UpdateYUVTexture(imageTexture, NULL, yPlane, strideY, uPlane, strideU, vPlane, strideV);1095}1096void RenderDevice::SetupVideoTexture_YUV422(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1097int32 strideV)1098{1099if (lastTextureFormat != SHADER_YUV_422) {1100if (imageTexture)1101SDL_DestroyTexture(imageTexture);1102SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");11031104imageTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, width, height);11051106SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");1107lastTextureFormat = SHADER_YUV_422;1108}11091110SDL_UpdateYUVTexture(imageTexture, NULL, yPlane, strideY, uPlane, strideU, vPlane, strideV);1111}1112void RenderDevice::SetupVideoTexture_YUV444(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,1113int32 strideV)1114{1115if (lastTextureFormat != SHADER_YUV_444) {1116if (imageTexture)1117SDL_DestroyTexture(imageTexture);1118SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");11191120imageTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, width, height);11211122SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");1123lastTextureFormat = SHADER_YUV_444;1124}11251126SDL_UpdateYUVTexture(imageTexture, NULL, yPlane, strideY, uPlane, strideU, vPlane, strideV);1127}112811291130