Path: blob/master/RSDKv5/RSDK/Graphics/GLFW/GLFWRenderDevice.cpp
1163 views
#ifndef _GLVERSION1#define _GLVERSION 202//#define _GLVERSION 333#endif45#if _GLVERSION > 306#define _GLSLVERSION "#version 130\n#define in_V in\n#define in_F in\n"7#else8#define _GLSLVERSION "#version 110\n#define in_V attribute\n#define out varying\n#define in_F varying\n"9#endif1011#if RETRO_REV0212#define _GLDEFINE "#define RETRO_REV02 (1)\n"13#else14#define _GLDEFINE "\n"15#endif1617const GLchar *backupVertex = R"aa(18in_V vec3 in_pos;19in_V vec2 in_UV;20out vec4 ex_color;21out vec2 ex_UV;2223void main()24{25gl_Position = vec4(in_pos, 1.0);26ex_color = vec4(1.0);27ex_UV = in_UV;28}29)aa";3031const GLchar *backupFragment = R"aa(32in_F vec2 ex_UV;33in_F vec4 ex_color;3435uniform sampler2D texDiffuse;3637void main()38{39gl_FragColor = texture2D(texDiffuse, ex_UV);40}41)aa";4243GLFWwindow *RenderDevice::window;44GLuint RenderDevice::VAO;45GLuint RenderDevice::VBO;4647GLuint RenderDevice::screenTextures[SCREEN_COUNT];48GLuint RenderDevice::imageTexture;4950double RenderDevice::lastFrame;51double RenderDevice::targetFreq;5253int32 RenderDevice::monitorIndex;5455uint32 *RenderDevice::videoBuffer;5657// Creates a window using the video settings58GLFWwindow *RenderDevice::CreateGLFWWindow(void)59{60GLFWwindow *win;61GLFWmonitor *monitor = NULL;62int32 w, h;6364glfwWindowHint(GLFW_DECORATED, videoSettings.bordered);6566if (videoSettings.windowed) {67w = videoSettings.windowWidth;68h = videoSettings.windowHeight;69}70else if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {71monitor = glfwGetPrimaryMonitor();72const GLFWvidmode *mode = glfwGetVideoMode(monitor);73w = mode->width;74h = mode->height;75}76else {77monitor = glfwGetPrimaryMonitor();78w = videoSettings.fsWidth;79h = videoSettings.fsHeight;80}8182win = glfwCreateWindow(w, h, gameVerInfo.gameTitle, monitor, NULL);83if (!win) {84PrintLog(PRINT_NORMAL, "ERROR: [GLFW] window creation failed");85return NULL;86}87if (videoSettings.windowed) {88// Center the window89monitor = glfwGetPrimaryMonitor();90const GLFWvidmode *mode = glfwGetVideoMode(monitor);91int x, y;92glfwGetMonitorPos(monitor, &x, &y);93// Get scaling for HiDPI screens94float xscale, yscale;95glfwGetMonitorContentScale(monitor, &xscale, &yscale);96int xpos = x + (mode->width - (int)((float)videoSettings.windowWidth * xscale)) / 2;97int ypos = y + (mode->height - (int)((float)videoSettings.windowHeight * yscale)) / 2;98glfwSetWindowPos(win, xpos, ypos);99}100glfwShowWindow(win);101PrintLog(PRINT_NORMAL, "w: %d h: %d windowed: %d", w, h, videoSettings.windowed);102103glfwSetKeyCallback(win, ProcessKeyEvent);104glfwSetMouseButtonCallback(win, ProcessMouseEvent);105glfwSetWindowFocusCallback(win, ProcessFocusEvent);106glfwSetWindowMaximizeCallback(win, ProcessMaximizeEvent);107108return win;109}110111bool RenderDevice::Init()112{113glfwInit();114glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, _GLVERSION / 10);115glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, _GLVERSION % 10);116glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);117glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);118glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);119glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // HiDPI scaling support120#if GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 4121// Disable framebuffer scaling which (surprisingly) makes the framebuffer scale correctly on Wayland122glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);123#endif124125if ((window = CreateGLFWWindow()) == NULL)126return false;127128glfwSetJoystickCallback(ProcessJoystickEvent);129130if (!SetupRendering() || !AudioDevice::Init())131return false;132133InitInputDevices();134return true;135}136137bool RenderDevice::SetupRendering()138{139glfwMakeContextCurrent(window);140GLenum err = glewInit();141// Wayland workaround, see https://github.com/nigels-com/glew/issues/172142if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {143PrintLog(PRINT_NORMAL, "ERROR: failed to initialize GLEW: %s", glewGetErrorString(err));144return false;145}146147glfwSwapInterval(videoSettings.vsync ? 1 : 0);148149GetDisplays();150151if (!InitGraphicsAPI() || !InitShaders())152return false;153154int32 size = videoSettings.pixWidth >= SCREEN_YSIZE ? videoSettings.pixWidth : SCREEN_YSIZE;155scanlines = (ScanlineInfo *)malloc(size * sizeof(ScanlineInfo));156memset(scanlines, 0, size * sizeof(ScanlineInfo));157158videoSettings.windowState = WINDOWSTATE_ACTIVE;159videoSettings.dimMax = 1.0;160videoSettings.dimPercent = 1.0;161162return true;163}164165void RenderDevice::GetDisplays()166{167GLFWmonitor *monitor = glfwGetWindowMonitor(window);168if (!monitor)169monitor = glfwGetPrimaryMonitor();170const GLFWvidmode *displayMode = glfwGetVideoMode(monitor);171int32 monitorCount;172GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);173174for (int32 m = 0; m < monitorCount; ++m) {175const GLFWvidmode *vidMode = glfwGetVideoMode(monitors[m]);176displayWidth[m] = vidMode->width;177displayHeight[m] = vidMode->height;178if (!memcmp(vidMode, displayMode, sizeof(GLFWvidmode))) {179monitorIndex = m;180}181}182183const GLFWvidmode *displayModes = glfwGetVideoModes(monitor, &displayCount);184if (displayInfo.displays)185free(displayInfo.displays);186187displayInfo.displays = (decltype(displayInfo.displays))malloc(sizeof(GLFWvidmode) * displayCount);188int32 newDisplayCount = 0;189bool32 foundFullScreenDisplay = false;190191for (int32 d = 0; d < displayCount; ++d) {192memcpy(&displayInfo.displays[newDisplayCount].internal, &displayModes[d], sizeof(GLFWvidmode));193194int32 refreshRate = displayInfo.displays[newDisplayCount].refresh_rate;195if (refreshRate >= 59 && (refreshRate <= 60 || refreshRate >= 120) && displayInfo.displays[newDisplayCount].height >= (SCREEN_YSIZE * 2)) {196if (d && refreshRate == 60 && displayInfo.displays[newDisplayCount - 1].refresh_rate == 59)197--newDisplayCount;198199if (videoSettings.fsWidth == displayInfo.displays[newDisplayCount].width200&& videoSettings.fsHeight == displayInfo.displays[newDisplayCount].height)201foundFullScreenDisplay = true;202203++newDisplayCount;204}205}206207displayCount = newDisplayCount;208if (!foundFullScreenDisplay) {209videoSettings.fsWidth = 0;210videoSettings.fsHeight = 0;211videoSettings.refreshRate = 60; // 0;212}213}214215bool RenderDevice::InitGraphicsAPI()216{217glClearColor(0.0, 0.0, 0.0, 1.0);218glDisable(GL_DEPTH_TEST);219glDisable(GL_DITHER);220glDisable(GL_BLEND);221glDisable(GL_SCISSOR_TEST);222glDisable(GL_CULL_FACE);223224// setup buffers225226#if _GLVERSION > 30227glGenVertexArrays(1, &VAO);228glBindVertexArray(VAO);229#endif230231glGenBuffers(1, &VBO);232glBindBuffer(GL_ARRAY_BUFFER, VBO);233glBufferData(GL_ARRAY_BUFFER, sizeof(RenderVertex) * (!RETRO_REV02 ? 24 : 60), NULL, GL_DYNAMIC_DRAW);234235glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(RenderVertex), 0);236glEnableVertexAttribArray(0);237// glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(RenderVertex), (void *)offsetof(RenderVertex, color));238// glEnableVertexAttribArray(1);239glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RenderVertex), (void *)offsetof(RenderVertex, tex));240glEnableVertexAttribArray(1);241242if (videoSettings.windowed || !videoSettings.exclusiveFS) {243if (videoSettings.windowed) {244viewSize.x = videoSettings.windowWidth;245viewSize.y = videoSettings.windowHeight;246}247else {248viewSize.x = displayWidth[monitorIndex];249viewSize.y = displayHeight[monitorIndex];250}251}252else {253int32 bufferWidth = videoSettings.fsWidth;254int32 bufferHeight = videoSettings.fsHeight;255if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {256bufferWidth = displayWidth[monitorIndex];257bufferHeight = displayHeight[monitorIndex];258}259viewSize.x = bufferWidth;260viewSize.y = bufferHeight;261}262263int32 maxPixHeight = 0;264#if !RETRO_USE_ORIGINAL_CODE265int32 screenWidth = 0;266#endif267for (int32 s = 0; s < SCREEN_COUNT; ++s) {268if (videoSettings.pixHeight > maxPixHeight)269maxPixHeight = videoSettings.pixHeight;270271screens[s].size.y = videoSettings.pixHeight;272273float viewAspect = viewSize.x / viewSize.y;274#if !RETRO_USE_ORIGINAL_CODE275screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;276#else277int32 screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;278#endif279if (screenWidth < videoSettings.pixWidth)280screenWidth = videoSettings.pixWidth;281282#if !RETRO_USE_ORIGINAL_CODE283if (customSettings.maxPixWidth && screenWidth > customSettings.maxPixWidth)284screenWidth = customSettings.maxPixWidth;285#else286if (screenWidth > DEFAULT_PIXWIDTH)287screenWidth = DEFAULT_PIXWIDTH;288#endif289290memset(&screens[s].frameBuffer, 0, sizeof(screens[s].frameBuffer));291SetScreenSize(s, screenWidth, screens[s].size.y);292}293294pixelSize.x = screens[0].size.x;295pixelSize.y = screens[0].size.y;296float pixAspect = pixelSize.x / pixelSize.y;297298Vector2 viewportPos{};299Vector2 lastViewSize;300301glfwGetWindowSize(window, &lastViewSize.x, &lastViewSize.y);302Vector2 viewportSize = lastViewSize;303304if ((viewSize.x / viewSize.y) <= ((pixelSize.x / pixelSize.y) + 0.1)) {305if ((pixAspect - 0.1) > (viewSize.x / viewSize.y)) {306viewSize.y = (pixelSize.y / pixelSize.x) * viewSize.x;307viewportPos.y = (lastViewSize.y >> 1) - (viewSize.y * 0.5);308viewportSize.y = viewSize.y;309}310}311else {312viewSize.x = pixAspect * viewSize.y;313viewportPos.x = (lastViewSize.x >> 1) - ((pixAspect * viewSize.y) * 0.5);314viewportSize.x = (pixAspect * viewSize.y);315}316317#if !RETRO_USE_ORIGINAL_CODE318if (screenWidth <= 512 && maxPixHeight <= 256) {319#else320if (maxPixHeight <= 256) {321#endif322textureSize.x = 512.0;323textureSize.y = 256.0;324}325else {326textureSize.x = 1024.0;327textureSize.y = 512.0;328}329330glViewport(viewportPos.x, viewportPos.y, viewportSize.x, viewportSize.y);331332glActiveTexture(GL_TEXTURE0);333glGenTextures(SCREEN_COUNT, screenTextures);334335for (int32 i = 0; i < SCREEN_COUNT; ++i) {336glBindTexture(GL_TEXTURE_2D, screenTextures[i]);337glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureSize.x, textureSize.y, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);338339glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);340glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);341glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);342glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);343}344glGenTextures(1, &imageTexture);345glBindTexture(GL_TEXTURE_2D, imageTexture);346glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);347348glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);349glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);350glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);351glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);352353videoBuffer = new uint32[RETRO_VIDEO_TEXTURE_W * RETRO_VIDEO_TEXTURE_H];354355lastShaderID = -1;356InitVertexBuffer();357engine.inFocus = 1;358videoSettings.viewportX = viewportPos.x;359videoSettings.viewportY = viewportPos.y;360videoSettings.viewportW = 1.0 / viewSize.x;361videoSettings.viewportH = 1.0 / viewSize.y;362363return true;364}365366// CUSTOM BUFFER FOR SHENANIGAN PURPOSES367// GL hates us and it's coordinate system is reverse of DX368// for shader output equivalency, we havee to flip everything369// X and Y are negated, some verts are specifically moved to match370// U and V are 0/1s and flipped from what it was originally371// clang-format off372#if RETRO_REV02373const RenderVertex rsdkGLVertexBuffer[60] = {374// 1 Screen (0)375{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },376{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },377{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },378{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },379{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },380{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },381382// 2 Screens - Bordered (Top Screen) (6)383{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },384{ { +0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },385{ { -0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },386{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },387{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },388{ { -0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },389390// 2 Screens - Bordered (Bottom Screen) (12)391{ { +0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },392{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },393{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },394{ { +0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },395{ { -0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },396{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },397398// 2 Screens - Stretched (Top Screen) (18)399{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },400{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },401{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },402{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },403{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },404{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },405406// 2 Screens - Stretched (Bottom Screen) (24)407{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },408{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },409{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },410{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },411{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },412{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },413414// 4 Screens (Top-Left) (30)415{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },416{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },417{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },418{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },419{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },420{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },421422// 4 Screens (Top-Right) (36)423{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },424{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },425{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },426{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },427{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },428{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },429430// 4 Screens (Bottom-Right) (42)431{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },432{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },433{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },434{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },435{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },436{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },437438// 4 Screens (Bottom-Left) (48)439{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },440{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },441{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },442{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },443{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },444{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },445446// Image/Video (54)447{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },448{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },449{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },450{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },451{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },452{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }453};454#else455const RenderVertex rsdkGLVertexBuffer[24] =456{457// 1 Screen (0)458{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },459{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },460{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },461{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },462{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },463{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },464465// 2 Screens - Stretched (Top Screen) (6)466{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },467{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },468{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },469{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },470{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },471{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },472473// 2 Screens - Stretched (Bottom Screen) (12)474{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },475{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },476{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },477{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },478{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },479{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },480481// Image/Video (18)482{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },483{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },484{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },485{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },486{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },487{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }488};489#endif490491492void RenderDevice::InitVertexBuffer()493{494RenderVertex vertBuffer[sizeof(rsdkGLVertexBuffer) / sizeof(RenderVertex)];495memcpy(vertBuffer, rsdkGLVertexBuffer, sizeof(rsdkGLVertexBuffer));496497float x = 0.5 / (float)viewSize.x;498float y = 0.5 / (float)viewSize.y;499500// ignore the last 6 verts, they're scaled to the 1024x512 textures already!501int32 vertCount = (RETRO_REV02 ? 60 : 24) - 6;502for (int32 v = 0; v < vertCount; ++v) {503RenderVertex *vertex = &vertBuffer[v];504vertex->pos.x = vertex->pos.x + x;505vertex->pos.y = vertex->pos.y - y;506507if (vertex->tex.x)508vertex->tex.x = screens[0].size.x * (1.0 / textureSize.x);509510if (vertex->tex.y)511vertex->tex.y = screens[0].size.y * (1.0 / textureSize.y);512}513514glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(RenderVertex) * (!RETRO_REV02 ? 24 : 60), vertBuffer);515}516517void RenderDevice::InitFPSCap()518{519lastFrame = glfwGetTime();520targetFreq = 1.0 / videoSettings.refreshRate;521}522bool RenderDevice::CheckFPSCap()523{524if (lastFrame + targetFreq < glfwGetTime())525return true;526527return false;528}529void RenderDevice::UpdateFPSCap() { lastFrame = glfwGetTime(); }530531void RenderDevice::CopyFrameBuffer()532{533for (int32 s = 0; s < videoSettings.screenCount; ++s) {534glBindTexture(GL_TEXTURE_2D, screenTextures[s]);535glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, screens[s].pitch, SCREEN_YSIZE, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, screens[s].frameBuffer);536}537}538539bool RenderDevice::ProcessEvents()540{541glfwPollEvents();542if (glfwWindowShouldClose(window))543isRunning = false;544return false;545}546547void RenderDevice::FlipScreen()548{549if (lastShaderID != videoSettings.shaderID) {550lastShaderID = videoSettings.shaderID;551552SetLinear(shaderList[videoSettings.shaderID].linear);553554if (videoSettings.shaderSupport)555glUseProgram(shaderList[videoSettings.shaderID].programID);556}557558if (windowRefreshDelay > 0) {559windowRefreshDelay--;560if (!windowRefreshDelay)561UpdateGameWindow();562return;563}564565glClear(GL_COLOR_BUFFER_BIT);566if (videoSettings.shaderSupport) {567glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "textureSize"), 1, &textureSize.x);568glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "pixelSize"), 1, &pixelSize.x);569glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "viewSize"), 1, &viewSize.x);570glUniform1f(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "screenDim"), videoSettings.dimMax * videoSettings.dimPercent);571}572573int32 startVert = 0;574switch (videoSettings.screenCount) {575default:576case 0:577#if RETRO_REV02578startVert = 54;579#else580startVert = 18;581#endif582glBindTexture(GL_TEXTURE_2D, imageTexture);583glDrawArrays(GL_TRIANGLES, startVert, 6);584585break;586587case 1:588glBindTexture(GL_TEXTURE_2D, screenTextures[0]);589glDrawArrays(GL_TRIANGLES, 0, 6);590break;591592case 2:593#if RETRO_REV02594startVert = startVertex_2P[0];595#else596startVert = 6;597#endif598glBindTexture(GL_TEXTURE_2D, screenTextures[0]);599glDrawArrays(GL_TRIANGLES, startVert, 6);600601#if RETRO_REV02602startVert = startVertex_2P[1];603#else604startVert = 12;605#endif606glBindTexture(GL_TEXTURE_2D, screenTextures[1]);607glDrawArrays(GL_TRIANGLES, startVert, 6);608break;609610#if RETRO_REV02611case 3:612// also flipped613glBindTexture(GL_TEXTURE_2D, screenTextures[0]);614glDrawArrays(GL_TRIANGLES, startVertex_3P[0], 6);615616glBindTexture(GL_TEXTURE_2D, screenTextures[1]);617glDrawArrays(GL_TRIANGLES, startVertex_3P[1], 6);618619glBindTexture(GL_TEXTURE_2D, screenTextures[2]);620glDrawArrays(GL_TRIANGLES, startVertex_3P[2], 6);621break;622623case 4:624// this too625glBindTexture(GL_TEXTURE_2D, screenTextures[0]);626glDrawArrays(GL_TRIANGLES, 30, 6);627glBindTexture(GL_TEXTURE_2D, screenTextures[1]);628glDrawArrays(GL_TRIANGLES, 36, 6);629630glBindTexture(GL_TEXTURE_2D, screenTextures[2]);631glDrawArrays(GL_TRIANGLES, 42, 6);632633glBindTexture(GL_TEXTURE_2D, screenTextures[3]);634glDrawArrays(GL_TRIANGLES, 48, 6);635break;636#endif637}638639glFlush();640glfwSwapBuffers(window);641}642643void RenderDevice::Release(bool32 isRefresh)644{645glDeleteTextures(SCREEN_COUNT, screenTextures);646glDeleteTextures(1, &imageTexture);647if (videoBuffer)648delete[] videoBuffer;649for (int32 i = 0; i < shaderCount; ++i) {650glDeleteProgram(shaderList[i].programID);651}652653#if _GLVERSION > 30654glDeleteVertexArrays(1, &VAO);655glDeleteBuffers(1, &VBO);656#endif657658shaderCount = 0;659#if RETRO_USE_MOD_LOADER660userShaderCount = 0;661#endif662663glfwDestroyWindow(window);664665if (!isRefresh) {666if (displayInfo.displays)667free(displayInfo.displays);668displayInfo.displays = NULL;669670if (scanlines)671free(scanlines);672scanlines = NULL;673674glfwTerminate();675}676}677678bool RenderDevice::InitShaders()679{680videoSettings.shaderSupport = true;681int32 maxShaders = 0;682#if RETRO_USE_MOD_LOADER683shaderCount = 0;684#endif685686LoadShader("None", false);687LoadShader("Clean", true);688LoadShader("CRT-Yeetron", true);689LoadShader("CRT-Yee64", true);690691#if RETRO_USE_MOD_LOADER692// a place for mods to load custom shaders693RunModCallbacks(MODCB_ONSHADERLOAD, NULL);694userShaderCount = shaderCount;695#endif696697LoadShader("YUV-420", true);698LoadShader("YUV-422", true);699LoadShader("YUV-444", true);700LoadShader("RGB-Image", true);701maxShaders = shaderCount;702703// no shaders == no support704if (!maxShaders) {705ShaderEntry *shader = &shaderList[0];706videoSettings.shaderSupport = false;707708// let's load709maxShaders = 1;710shaderCount = 1;711712GLint success;713char infoLog[0x1000];714715716GLuint vert, frag;717const GLchar *vchar[] = { _GLSLVERSION, _GLDEFINE, backupVertex };718vert = glCreateShader(GL_VERTEX_SHADER);719glShaderSource(vert, 3, vchar, NULL);720glCompileShader(vert);721722const GLchar *fchar[] = { _GLSLVERSION, _GLDEFINE, backupFragment };723frag = glCreateShader(GL_FRAGMENT_SHADER);724glShaderSource(frag, 3, fchar, NULL);725glCompileShader(frag);726727glGetShaderiv(vert, GL_COMPILE_STATUS, &success);728if (!success) {729glGetShaderInfoLog(vert, 0x1000, NULL, infoLog);730PrintLog(PRINT_NORMAL, "BACKUP vertex shader compiling failed:\n%s", infoLog);731}732733glGetShaderiv(frag, GL_COMPILE_STATUS, &success);734if (!success) {735glGetShaderInfoLog(frag, 0x1000, NULL, infoLog);736PrintLog(PRINT_NORMAL, "BACKUP fragment shader compiling failed:\n%s", infoLog);737}738shader->programID = glCreateProgram();739glAttachShader(shader->programID, vert);740glAttachShader(shader->programID, frag);741742glBindAttribLocation(shader->programID, 0, "in_pos");743//glBindAttribLocation(shader->programID, 1, "in_color");744glBindAttribLocation(shader->programID, 1, "in_UV");745746glLinkProgram(shader->programID);747glDeleteShader(vert);748glDeleteShader(frag);749750glUseProgram(shader->programID);751752shader->linear = videoSettings.windowed ? false : shader->linear;753}754755videoSettings.shaderID = MAX(videoSettings.shaderID >= maxShaders ? 0 : videoSettings.shaderID, 0);756SetLinear(shaderList[videoSettings.shaderID].linear || videoSettings.screenCount > 1);757758return true;759}760761void RenderDevice::LoadShader(const char *fileName, bool32 linear)762{763char fullFilePath[0x100];764FileInfo info;765766for (int32 i = 0; i < shaderCount; ++i) {767if (strcmp(shaderList[i].name, fileName) == 0)768return;769}770771if (shaderCount == SHADER_COUNT)772return;773774ShaderEntry *shader = &shaderList[shaderCount];775sprintf_s(shader->name, sizeof(shader->name), "%s", fileName);776777GLint success;778char infoLog[0x1000];779GLuint vert, frag;780sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/OGL/None.vs");781InitFileInfo(&info);782if (LoadFile(&info, fullFilePath, FMODE_RB)) {783uint8 *fileData = NULL;784AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);785ReadBytes(&info, fileData, info.fileSize);786fileData[info.fileSize] = 0;787CloseFile(&info);788789const GLchar *glchar[] = { _GLSLVERSION, _GLDEFINE, (const GLchar *)fileData };790vert = glCreateShader(GL_VERTEX_SHADER);791glShaderSource(vert, 3, glchar, NULL);792glCompileShader(vert);793RemoveStorageEntry((void **)&fileData);794795glGetShaderiv(vert, GL_COMPILE_STATUS, &success);796if (!success) {797glGetShaderInfoLog(vert, 0x1000, NULL, infoLog);798PrintLog(PRINT_NORMAL, "Vertex shader compiling failed:\n%s", infoLog);799return;800}801}802else803return;804805sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/OGL/%s.fs", fileName);806InitFileInfo(&info);807if (LoadFile(&info, fullFilePath, FMODE_RB)) {808uint8 *fileData = NULL;809AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);810ReadBytes(&info, fileData, info.fileSize);811fileData[info.fileSize] = 0;812CloseFile(&info);813814const GLchar *glchar[] = { _GLSLVERSION, _GLDEFINE, (const GLchar *)fileData };815frag = glCreateShader(GL_FRAGMENT_SHADER);816glShaderSource(frag, 3, glchar, NULL);817glCompileShader(frag);818RemoveStorageEntry((void **)&fileData);819820glGetShaderiv(frag, GL_COMPILE_STATUS, &success);821if (!success) {822glGetShaderInfoLog(frag, 0x1000, NULL, infoLog);823PrintLog(PRINT_NORMAL, "Fragment shader compiling failed:\n%s", infoLog);824return;825}826}827else828return;829830shader->linear = linear;831832shader->programID = glCreateProgram();833glAttachShader(shader->programID, vert);834glAttachShader(shader->programID, frag);835836glBindAttribLocation(shader->programID, 0, "in_pos");837//glBindAttribLocation(shader->programID, 1, "in_color");838glBindAttribLocation(shader->programID, 1, "in_UV");839840glLinkProgram(shader->programID);841glGetProgramiv(shader->programID, GL_LINK_STATUS, &success);842if (!success) {843glGetProgramInfoLog(shader->programID, 0x1000, NULL, infoLog);844PrintLog(PRINT_NORMAL, "OpenGL shader linking failed:\n%s", infoLog);845return;846}847glDeleteShader(vert);848glDeleteShader(frag);849850shaderCount++;851};852853void RenderDevice::RefreshWindow()854{855videoSettings.windowState = WINDOWSTATE_UNINITIALIZED;856857Release(true);858859if ((window = CreateGLFWWindow()) == NULL)860return;861862glfwMakeContextCurrent(window);863864if (!InitGraphicsAPI() || !InitShaders())865return;866867videoSettings.windowState = WINDOWSTATE_ACTIVE;868}869870void RenderDevice::GetWindowSize(int32 *width, int32 *height)871{872int32 widest = 0, highest = 0, count = 0;873GLFWmonitor **monitors = glfwGetMonitors(&count);874for (int32 i = 0; i < count; i++) {875const GLFWvidmode *mode = glfwGetVideoMode(monitors[i]);876if (mode->height > highest) {877highest = mode->height;878widest = mode->width;879}880}881if (width)882*width = widest;883if (height)884*height = highest;885}886887void RenderDevice::SetupImageTexture(int32 width, int32 height, uint8 *imagePixels)888{889if (imagePixels) {890glBindTexture(GL_TEXTURE_2D, imageTexture);891glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, imagePixels);892}893}894895void RenderDevice::SetupVideoTexture_YUV420(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,896int32 strideV)897{898uint32 *pixels = videoBuffer;899uint32 *preY = pixels;900int32 pitch = RETRO_VIDEO_TEXTURE_W - width;901902if (videoSettings.shaderSupport) {903for (int32 y = 0; y < height; ++y) {904for (int32 x = 0; x < width; ++x) {905*pixels++ = (yPlane[x] << 16) | 0xFF000000;906}907908pixels += pitch;909yPlane += strideY;910}911912pixels = preY;913pitch = RETRO_VIDEO_TEXTURE_W - (width >> 1);914for (int32 y = 0; y < (height >> 1); ++y) {915for (int32 x = 0; x < (width >> 1); ++x) {916*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;917}918919pixels += pitch;920uPlane += strideU;921vPlane += strideV;922}923}924else {925// No shader support means no YUV support! at least use the brightness to show it in grayscale!926for (int32 y = 0; y < height; ++y) {927for (int32 x = 0; x < width; ++x) {928int32 brightness = yPlane[x];929*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;930}931932pixels += pitch;933yPlane += strideY;934}935}936glBindTexture(GL_TEXTURE_2D, imageTexture);937glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);938}939940void RenderDevice::SetupVideoTexture_YUV422(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,941int32 strideV)942{943uint32 *pixels = videoBuffer;944uint32 *preY = pixels;945int32 pitch = RETRO_VIDEO_TEXTURE_W - width;946947if (videoSettings.shaderSupport) {948for (int32 y = 0; y < height; ++y) {949for (int32 x = 0; x < width; ++x) {950*pixels++ = (yPlane[x] << 16) | 0xFF000000;951}952953pixels += pitch;954yPlane += strideY;955}956957pixels = preY;958pitch = RETRO_VIDEO_TEXTURE_W - (width >> 1);959for (int32 y = 0; y < height; ++y) {960for (int32 x = 0; x < (width >> 1); ++x) {961*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;962}963964pixels += pitch;965uPlane += strideU;966vPlane += strideV;967}968}969else {970// No shader support means no YUV support! at least use the brightness to show it in grayscale!971for (int32 y = 0; y < height; ++y) {972for (int32 x = 0; x < width; ++x) {973int32 brightness = yPlane[x];974*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;975}976977pixels += pitch;978yPlane += strideY;979}980}981982glBindTexture(GL_TEXTURE_2D, imageTexture);983glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);984}985void RenderDevice::SetupVideoTexture_YUV444(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,986int32 strideV)987{988uint32 *pixels = videoBuffer;989int32 pitch = RETRO_VIDEO_TEXTURE_W - width;990991if (videoSettings.shaderSupport) {992for (int32 y = 0; y < height; ++y) {993int32 pos1 = yPlane - vPlane;994int32 pos2 = uPlane - vPlane;995uint8 *pixV = vPlane;996for (int32 x = 0; x < width; ++x) {997*pixels++ = pixV[0] | (pixV[pos2] << 8) | (pixV[pos1] << 16) | 0xFF000000;998pixV++;999}10001001pixels += pitch;1002yPlane += strideY;1003uPlane += strideU;1004vPlane += strideV;1005}1006}1007else {1008// No shader support means no YUV support! at least use the brightness to show it in grayscale!1009for (int32 y = 0; y < height; ++y) {1010for (int32 x = 0; x < width; ++x) {1011int32 brightness = yPlane[x];1012*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;1013}10141015pixels += pitch;1016yPlane += strideY;1017}1018}1019glBindTexture(GL_TEXTURE_2D, imageTexture);1020glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);1021}10221023void RenderDevice::ProcessKeyEvent(GLFWwindow *, int32 key, int32 scancode, int32 action, int32 mods)1024{1025switch (action) {1026case GLFW_PRESS: {1027#if !RETRO_REV021028++RSDK::SKU::buttonDownCount;1029#endif1030switch (key) {1031case GLFW_KEY_ENTER:1032if (mods & GLFW_MOD_ALT) {1033videoSettings.windowed ^= 1;1034UpdateGameWindow();1035changedVideoSettings = false;1036break;1037}10381039#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1040RSDK::SKU::specialKeyStates[1] = true;1041#endif10421043// [fallthrough]10441045default:1046#if RETRO_INPUTDEVICE_KEYBOARD1047SKU::UpdateKeyState(key);1048#endif1049break;10501051case GLFW_KEY_ESCAPE:1052if (engine.devMenu) {1053#if RETRO_REV0U1054if (sceneInfo.state == ENGINESTATE_DEVMENU || RSDK::Legacy::gameMode == RSDK::Legacy::ENGINE_DEVMENU)1055#else1056if (sceneInfo.state == ENGINESTATE_DEVMENU)1057#endif1058CloseDevMenu();1059else1060OpenDevMenu();1061}1062else {1063#if RETRO_INPUTDEVICE_KEYBOARD1064SKU::UpdateKeyState(key);1065#endif1066}10671068#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1069RSDK::SKU::specialKeyStates[0] = true;1070#endif1071break;10721073#if !RETRO_USE_ORIGINAL_CODE1074case GLFW_KEY_F1:1075if (engine.devMenu) {1076sceneInfo.listPos--;1077while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart1078|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd1079|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {1080sceneInfo.activeCategory--;1081if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {1082sceneInfo.activeCategory = sceneInfo.categoryCount - 1;1083}1084sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd - 1;1085}10861087#if RETRO_REV0U1088switch (engine.version) {1089default: break;1090case 5: LoadScene(); break;1091case 4:1092case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1093}1094#else1095LoadScene();1096#endif1097}1098break;10991100case GLFW_KEY_F2:1101if (engine.devMenu) {1102sceneInfo.listPos++;1103while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart1104|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd1105|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {1106sceneInfo.activeCategory++;1107if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {1108sceneInfo.activeCategory = 0;1109}1110sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart;1111}11121113#if RETRO_REV0U1114switch (engine.version) {1115default: break;1116case 5: LoadScene(); break;1117case 4:1118case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1119}1120#else1121LoadScene();1122#endif1123}1124break;1125#endif11261127case GLFW_KEY_F3:1128if (userShaderCount)1129videoSettings.shaderID = (videoSettings.shaderID + 1) % userShaderCount;1130break;11311132#if !RETRO_USE_ORIGINAL_CODE1133case GLFW_KEY_F4:1134if (engine.devMenu)1135engine.showEntityInfo ^= 1;1136break;11371138case GLFW_KEY_F5:1139if (engine.devMenu) {1140// Quick-Reload1141#if RETRO_USE_MOD_LOADER1142if (mods & GLFW_MOD_CONTROL)1143RefreshModFolders();1144#endif11451146#if RETRO_REV0U1147switch (engine.version) {1148default: break;1149case 5: LoadScene(); break;1150case 4:1151case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;1152}1153#else1154LoadScene();1155#endif1156}1157break;11581159case GLFW_KEY_F6:1160if (engine.devMenu && videoSettings.screenCount > 1)1161videoSettings.screenCount--;1162break;11631164case GLFW_KEY_F7:1165if (engine.devMenu && videoSettings.screenCount < SCREEN_COUNT)1166videoSettings.screenCount++;1167break;11681169case GLFW_KEY_F8:1170if (engine.devMenu)1171engine.showUpdateRanges ^= 1;1172break;11731174case GLFW_KEY_F9:1175if (engine.devMenu)1176showHitboxes ^= 1;1177break;11781179case GLFW_KEY_F10:1180if (engine.devMenu)1181engine.showPaletteOverlay ^= 1;1182break;1183#endif1184case GLFW_KEY_BACKSPACE:1185if (engine.devMenu)1186engine.gameSpeed = engine.fastForwardSpeed;1187break;11881189case GLFW_KEY_F11:1190case GLFW_KEY_INSERT:1191if (engine.devMenu)1192engine.frameStep = true;1193break;11941195case GLFW_KEY_F12:1196case GLFW_KEY_PAUSE:1197if (engine.devMenu) {1198#if RETRO_REV0U1199switch (engine.version) {1200default: break;1201case 5:1202if (sceneInfo.state != ENGINESTATE_NONE)1203sceneInfo.state ^= ENGINESTATE_STEPOVER;1204break;1205case 4:1206case 3:1207if (RSDK::Legacy::stageMode != ENGINESTATE_NONE)1208RSDK::Legacy::stageMode ^= RSDK::Legacy::STAGEMODE_STEPOVER;1209break;1210}1211#else1212if (sceneInfo.state != ENGINESTATE_NONE)1213sceneInfo.state ^= ENGINESTATE_STEPOVER;1214#endif1215}1216break;1217}1218break;1219}1220case GLFW_RELEASE: {1221#if !RETRO_REV021222--RSDK::SKU::buttonDownCount;1223#endif1224switch (key) {1225default:1226#if RETRO_INPUTDEVICE_KEYBOARD1227SKU::ClearKeyState(key);1228#endif1229break;12301231#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1232case GLFW_KEY_ESCAPE:1233RSDK::SKU::specialKeyStates[0] = false;1234SKU::ClearKeyState(key);1235break;12361237case GLFW_KEY_ENTER:1238RSDK::SKU::specialKeyStates[1] = false;1239SKU::ClearKeyState(key);1240break;1241#endif1242case GLFW_KEY_BACKSPACE: engine.gameSpeed = 1; break;1243}1244break;1245}1246}1247}1248void RenderDevice::ProcessFocusEvent(GLFWwindow *, int32 focused)1249{1250if (!focused) {1251#if RETRO_REV021252SKU::userCore->focusState = 1;1253#endif1254}1255else {1256#if RETRO_REV021257SKU::userCore->focusState = 0;1258#endif1259}1260}1261void RenderDevice::ProcessMouseEvent(GLFWwindow *, int32 button, int32 action, int32 mods)1262{1263switch (action) {1264case GLFW_PRESS: {1265switch (button) {1266case GLFW_MOUSE_BUTTON_LEFT: touchInfo.down[0] = true; touchInfo.count = 1;1267#if !RETRO_REV021268RSDK::SKU::buttonDownCount++;1269#endif1270break;12711272case GLFW_MOUSE_BUTTON_RIGHT:1273#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1274RSDK::SKU::specialKeyStates[3] = true;1275RSDK::SKU::buttonDownCount++;1276#endif1277break;1278}1279break;1280}12811282case GLFW_RELEASE: {1283switch (button) {1284case GLFW_MOUSE_BUTTON_LEFT: touchInfo.down[0] = false; touchInfo.count = 0;1285#if !RETRO_REV021286RSDK::SKU::buttonDownCount--;1287#endif1288break;12891290case GLFW_MOUSE_BUTTON_RIGHT:1291#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD1292RSDK::SKU::specialKeyStates[3] = false;1293RSDK::SKU::buttonDownCount--;1294#endif1295break;1296}1297break;1298}1299}1300}1301void RenderDevice::ProcessJoystickEvent(int32 ID, int32 event)1302{1303#if RETRO_INPUTDEVICE_GLFW1304if (!glfwJoystickIsGamepad(ID))1305return;1306uint32 hash;1307char idBuffer[0x20];1308sprintf_s(idBuffer, sizeof(idBuffer), "%s%d", "GLFWDevice", ID);1309GenerateHashCRC(&hash, idBuffer);13101311if (event == GLFW_CONNECTED)1312SKU::InitGLFWInputDevice(hash, ID);1313else1314RemoveInputDevice(InputDeviceFromID(hash));1315#endif1316}1317void RenderDevice::ProcessMaximizeEvent(GLFWwindow *, int32 maximized)1318{1319// i don't know why this is a thing1320if (maximized) {1321// set fullscreen idk about the specifics rn1322}1323}13241325void RenderDevice::SetLinear(bool32 linear)1326{1327for (int32 i = 0; i < SCREEN_COUNT; ++i) {1328glBindTexture(GL_TEXTURE_2D, screenTextures[i]);1329glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);1330glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);1331}1332}133313341335