shithub: cstory

Download patch

ref: 7bc028f5d8949cb206eb8fa1f5e7b27ef47e764b
parent: aa3cd55b432649bb2e61a5176c3ee53ae345c2f1
author: Clownacy <Clownacy@users.noreply.github.com>
date: Sun Sep 13 13:56:28 EDT 2020

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.

--- 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,7 +37,10 @@
 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;
 
 static void RectToSDLRect(const RenderBackend_Rect *rect, SDL_Rect *sdl_rect)
@@ -64,7 +70,7 @@
 			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 @@
 				framebuffer.width = screen_width;
 				framebuffer.height = screen_height;
 
+				RenderBackend_HandleWindowResize(screen_width, screen_height);
+
 				Backend_PostWindowCreation();
 
 				return &framebuffer;
@@ -132,12 +140,23 @@
 
 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_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;
 }