From 7bc028f5d8949cb206eb8fa1f5e7b27ef47e764b Mon Sep 17 00:00:00 2001 From: Clownacy Date: Sun, 13 Sep 2020 17:56:28 +0100 Subject: [PATCH] Enable window-resizing in the SDLTexture renderer Previously, the window was a fixed size just like the original. This change highlights a weird issue in CSE2: this doesn't exactly match the behaviour of the original game, so why did I change it? Simple: monitors had much lower pixel-densities back in the early 2000s, meaning that 320x240 and 640x480 weren't as laughably small as they are today. I like to think of CSE2's portable branch as Cave Story's equivalent to Chocolate Doom: the point isn't to replicate the game's behaviour 100% - that's the accurate branch's job - no, the point of the portable branch is to replicate the *experience* of the game, as it was back in 2004. This means no commically-small windows. This is the same reason font anti-aliasing is disabled, even in versions of Windows later than XP. Sidenote: the OpenGL3/OpenGLES2 renderers already had this feature, but they used linear-filtering, causing the screen to be extremely blurry in 320x240 mode. This renderer uses a better method, which does apply slight blurring at the edges of pixels at resolutions that aren't an exact multiple of 320x240/640x480, but otherwise it resembles nearest-neighbour. This is way nicer to look at, and fits the game's aesthetic. This feature will be ported to the other renderers soon. --- src/Backends/Rendering/SDLTexture.cpp | 59 ++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/Backends/Rendering/SDLTexture.cpp b/src/Backends/Rendering/SDLTexture.cpp index fbe8aaac..160b6f99 100644 --- a/src/Backends/Rendering/SDLTexture.cpp +++ b/src/Backends/Rendering/SDLTexture.cpp @@ -12,6 +12,9 @@ #include "../Misc.h" #include "../Shared/SDL2.h" +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + typedef struct RenderBackend_Surface { SDL_Texture *texture; @@ -34,6 +37,9 @@ SDL_Window *window; static SDL_Renderer *renderer; static RenderBackend_Surface framebuffer; +static RenderBackend_Surface upscaled_framebuffer; + +static SDL_Rect upscaled_framebuffer_rect; static RenderBackend_Surface *surface_list_head; @@ -64,7 +70,7 @@ RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t scree Backend_PrintInfo("%s", info.name); } - window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, 0); + window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, SDL_WINDOW_RESIZABLE); if (window != NULL) { @@ -93,6 +99,8 @@ RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t scree framebuffer.width = screen_width; framebuffer.height = screen_height; + RenderBackend_HandleWindowResize(screen_width, screen_height); + Backend_PostWindowCreation(); return &framebuffer; @@ -132,11 +140,22 @@ void RenderBackend_Deinit(void) void RenderBackend_DrawScreen(void) { + if (SDL_SetRenderTarget(renderer, upscaled_framebuffer.texture) < 0) + Backend_PrintError("Couldn't set upscaled framebuffer as the current rendering target: %s", SDL_GetError()); + + if (SDL_RenderCopy(renderer, framebuffer.texture, NULL, NULL) < 0) + Backend_PrintError("Failed to copy framebuffer texture to upscaled framebuffer: %s", SDL_GetError()); + if (SDL_SetRenderTarget(renderer, NULL) < 0) Backend_PrintError("Couldn't set default render target as the current rendering target: %s", SDL_GetError()); - if (SDL_RenderCopy(renderer, framebuffer.texture, NULL, NULL) < 0) - Backend_PrintError("Failed to copy framebuffer texture to default render target: %s", SDL_GetError()); + if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF) < 0) + Backend_PrintError("Couldn't set color for drawing operations: %s", SDL_GetError()); + + SDL_RenderClear(renderer); + + if (SDL_RenderCopy(renderer, upscaled_framebuffer.texture, NULL, &upscaled_framebuffer_rect) < 0) + Backend_PrintError("Failed to copy upscaled framebuffer texture to default render target: %s", SDL_GetError()); SDL_RenderPresent(renderer); } @@ -418,8 +437,36 @@ void RenderBackend_HandleRenderTargetLoss(void) void RenderBackend_HandleWindowResize(size_t width, size_t height) { - (void)width; - (void)height; + size_t upscale_factor = MAX(1, MIN((width + framebuffer.width / 2) / framebuffer.width, (height + framebuffer.height / 2) / framebuffer.height)); - // No problem for us + upscaled_framebuffer.width = framebuffer.width * upscale_factor; + upscaled_framebuffer.height = framebuffer.height * upscale_factor; + + if (upscaled_framebuffer.texture != NULL) + SDL_DestroyTexture(upscaled_framebuffer.texture); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + upscaled_framebuffer.texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, upscaled_framebuffer.width, upscaled_framebuffer.height * upscale_factor); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); + + if (upscaled_framebuffer.texture == NULL) + Backend_PrintError("Couldn't regenerate upscaled framebuffer"); + + // Create rect that forces 4:3 no matter what size the window is + float window_ratio = (float)width / height; + float framebuffer_ratio = (float)upscaled_framebuffer.width / upscaled_framebuffer.height; + + if (window_ratio >= framebuffer_ratio) + { + upscaled_framebuffer_rect.w = height * framebuffer_ratio; + upscaled_framebuffer_rect.h = height; + } + else + { + upscaled_framebuffer_rect.w = width; + upscaled_framebuffer_rect.h = width / framebuffer_ratio; + } + + upscaled_framebuffer_rect.x = (width - upscaled_framebuffer_rect.w) / 2; + upscaled_framebuffer_rect.y = (height - upscaled_framebuffer_rect.h) / 2; }