diff --git a/core/nullDC.cpp b/core/nullDC.cpp index 89c637803..844e38ba9 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -313,7 +313,9 @@ int dc_start_game(const char *path) #if DC_PLATFORM == DC_PLATFORM_DREAMCAST if (!settings.bios.UseReios) #endif - LoadRomFiles(get_readonly_data_path(DATA_PATH)); + if (!LoadRomFiles(get_readonly_data_path(DATA_PATH))) + return -5; + #if DC_PLATFORM == DC_PLATFORM_DREAMCAST if (path == NULL) { @@ -513,6 +515,7 @@ void InitSettings() settings.rend.CustomTextures = false; settings.rend.DumpTextures = false; settings.rend.ScreenScaling = 100; + settings.rend.ScreenStretching = 100; settings.rend.Fog = true; settings.pvr.ta_skip = 0; @@ -596,6 +599,7 @@ void LoadSettings(bool game_specific) settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures); settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling); settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100); + settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching); settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog); settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip); @@ -720,6 +724,7 @@ void SaveSettings() cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures); cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures); cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling); + cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching); cfgSaveBool("config", "rend.Fog", settings.rend.Fog); cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip); cfgSaveInt("config", "pvr.rend", settings.pvr.rend); diff --git a/core/rend/gl4/gldraw.cpp b/core/rend/gl4/gldraw.cpp index 447a97461..75ad7eda9 100644 --- a/core/rend/gl4/gldraw.cpp +++ b/core/rend/gl4/gldraw.cpp @@ -697,11 +697,15 @@ void gl4DrawFramebuffer(float w, float h) bool gl4_render_output_framebuffer() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, screen_width, screen_height); - if (gl.ofbo.tex == 0) + glcache.Disable(GL_SCISSOR_TEST); + if (gl.ofbo.fbo == 0) return false; - - gl4_draw_quad_texture(gl.ofbo.tex, true); + glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height, + 0, 0, screen_width, screen_height, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return true; } diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index ecda63dec..93700f20b 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -662,14 +662,15 @@ static bool RenderFrame() Handle Dc to screen scaling */ float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f; + float screen_stretching = settings.rend.ScreenStretching / 100.f; + float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); - dc2s_scale_h *= screen_scaling; - float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2); + float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2); //-1 -> too much to left - gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); + gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 - gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling); + gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1); gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; @@ -763,7 +764,7 @@ static bool RenderFrame() { if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) { - output_fbo = init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling); + output_fbo = init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f); } else { @@ -826,21 +827,21 @@ static bool RenderFrame() if (!is_rtt) { // Add x offset for aspect ratio > 4/3 - min_x = min_x * dc2s_scale_h + ds2s_offs_x; + min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling; // Invert y coordinates when rendering to screen - min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h; - width *= dc2s_scale_h; - height *= dc2s_scale_h; + min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling; + width *= dc2s_scale_h * screen_scaling * screen_stretching; + height *= dc2s_scale_h * screen_scaling; if (ds2s_offs_x > 0) { - float rounded_offs_x = ds2s_offs_x + 0.5f; + float scaled_offs_x = ds2s_offs_x * screen_scaling; glcache.ClearColor(0.f, 0.f, 0.f, 0.f); glcache.Enable(GL_SCISSOR_TEST); - glScissor(0, 0, rounded_offs_x, screen_height); + glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f); glClear(GL_COLOR_BUFFER_BIT); - glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height); + glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f); glClear(GL_COLOR_BUFFER_BIT); } } diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index d337848cb..618a3e33f 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -1141,17 +1141,27 @@ void DrawFramebuffer(float w, float h) bool render_output_framebuffer() { -#if HOST_OS != OS_DARWIN - //Fix this in a proper way - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif - glViewport(0, 0, screen_width, screen_height); - if (gl.ofbo.tex == 0) - return false; - - float scl = 480.f / screen_height; - float tx = (screen_width * scl - 640.f) / 2; - DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0); - + glcache.Disable(GL_SCISSOR_TEST); + if (gl.gl_major < 3) + { + glViewport(0, 0, screen_width, screen_height); + if (gl.ofbo.tex == 0) + return false; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + float scl = 480.f / screen_height; + float tx = (screen_width * scl - 640.f) / 2; + DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0); + } + else + { + if (gl.ofbo.fbo == 0) + return false; + glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height, + 0, 0, screen_width, screen_height, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } return true; } diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index b243a6ffc..fad89106d 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1678,15 +1678,16 @@ bool RenderFrame() /* Handle Dc to screen scaling */ - float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f; + float screen_stretching = settings.rend.ScreenStretching / 100.f; + float screen_scaling = settings.rend.ScreenScaling / 100.f; + float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); - dc2s_scale_h *= screen_scaling; - float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2); + float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2); //-1 -> too much to left - ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); + ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 - ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling); + ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / screen_width; ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1); @@ -1791,7 +1792,7 @@ bool RenderFrame() { if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) { - init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling); + init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f); } else { @@ -1857,21 +1858,21 @@ bool RenderFrame() if (!is_rtt) { // Add x offset for aspect ratio > 4/3 - min_x = min_x * dc2s_scale_h + ds2s_offs_x; + min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling; // Invert y coordinates when rendering to screen - min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h; - width *= dc2s_scale_h; - height *= dc2s_scale_h; + min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling; + width *= dc2s_scale_h * screen_scaling * screen_stretching; + height *= dc2s_scale_h * screen_scaling; if (ds2s_offs_x > 0) { - float rounded_offs_x = ds2s_offs_x + 0.5f; + float scaled_offs_x = ds2s_offs_x * screen_scaling; glcache.ClearColor(0.f, 0.f, 0.f, 0.f); glcache.Enable(GL_SCISSOR_TEST); - glScissor(0, 0, rounded_offs_x, screen_height); + glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f); glClear(GL_COLOR_BUFFER_BIT); - glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height); + glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f); glClear(GL_COLOR_BUFFER_BIT); } } diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index c6339b802..7e0cec3cb 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -120,6 +120,7 @@ struct gl_ctx struct { GLuint depthb; + GLuint colorb; GLuint tex; GLuint fbo; int width; diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 5bf3b45eb..1a3802fb7 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -996,13 +996,7 @@ GLuint init_output_framebuffer(int width, int height) { if (width != gl.ofbo.width || height != gl.ofbo.height) { - if (gl.ofbo.fbo != 0) - { - glDeleteFramebuffers(1, &gl.ofbo.fbo); - gl.ofbo.fbo = 0; - glDeleteRenderbuffers(1, &gl.ofbo.depthb); - glcache.DeleteTextures(1, &gl.ofbo.tex); - } + free_output_framebuffer(); gl.ofbo.width = width; gl.ofbo.height = height; } @@ -1026,15 +1020,25 @@ GLuint init_output_framebuffer(int width, int height) else glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - // Create a texture for rendering to - gl.ofbo.tex = glcache.GenTexture(); - glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex); + if (gl.gl_major < 3) + { + // Create a texture for rendering to + gl.ofbo.tex = glcache.GenTexture(); + glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + { + // Use a renderbuffer and glBlitFramebuffer + glGenRenderbuffers(1, &gl.ofbo.colorb); + glBindRenderbuffer(GL_RENDERBUFFER, gl.ofbo.colorb); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + } // Create the framebuffer glGenFramebuffers(1, &gl.ofbo.fbo); @@ -1046,13 +1050,20 @@ GLuint init_output_framebuffer(int width, int height) if (!gl.is_gles || gl.GL_OES_packed_depth_stencil_supported) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb); - // Attach the texture to the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0); + // Attach the texture/renderbuffer to the FBO + if (gl.gl_major < 3) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0); + else + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gl.ofbo.colorb); // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); verify(uStatus == GL_FRAMEBUFFER_COMPLETE); + + glcache.Disable(GL_SCISSOR_TEST); + glcache.ClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); } else glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo); @@ -1071,7 +1082,15 @@ void free_output_framebuffer() gl.ofbo.fbo = 0; glDeleteRenderbuffers(1, &gl.ofbo.depthb); gl.ofbo.depthb = 0; - glcache.DeleteTextures(1, &gl.ofbo.tex); - gl.ofbo.tex = 0; + if (gl.ofbo.tex != 0) + { + glcache.DeleteTextures(1, &gl.ofbo.tex); + gl.ofbo.tex = 0; + } + if (gl.ofbo.colorb != 0) + { + glDeleteRenderbuffers(1, &gl.ofbo.colorb); + gl.ofbo.colorb = 0; + } } } diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index cfc134cbc..6c096d755 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -952,6 +952,9 @@ static void gui_display_settings() ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100); ImGui::SameLine(); ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better"); + ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150); + ImGui::SameLine(); + ShowHelpMarker("Stretch the screen horizontally"); ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6); ImGui::SameLine(); ShowHelpMarker("Number of frames to skip between two actually rendered frames"); @@ -1251,6 +1254,7 @@ static void gui_start_game(const std::string& path) { gui_state = Main; game_started = false; + cfgSetVirtual("config", "image", ""); switch (rc) { case -3: error_msg = "Audio/video initialization failed"; diff --git a/core/types.h b/core/types.h index a9a835ac1..bfd779ef8 100644 --- a/core/types.h +++ b/core/types.h @@ -632,7 +632,8 @@ struct settings_t f32 ExtraDepthScale; bool CustomTextures; bool DumpTextures; - int ScreenScaling; // in percent. 50 means half the native resolution + int ScreenScaling; // in percent. 50 means half the native resolution + int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3 bool Fog; } rend;