Maelstrom: Render to texture to adapt to any physical screen resolution.

https://github.com/libsdl-org/Maelstrom/commit/0c2d978df971500b6e004ed733dc6bf17f6e825d

From 0c2d978df971500b6e004ed733dc6bf17f6e825d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 21 Jun 2012 10:26:55 -0400
Subject: [PATCH] Render to texture to adapt to any physical screen resolution.

---
 screenlib/SDL_FrameBuf.cpp | 72 +++++++++++++++++++------------
 screenlib/SDL_FrameBuf.h   | 86 ++++++--------------------------------
 2 files changed, 58 insertions(+), 100 deletions(-)

diff --git a/screenlib/SDL_FrameBuf.cpp b/screenlib/SDL_FrameBuf.cpp
index 3f519b28..ab47ff58 100644
--- a/screenlib/SDL_FrameBuf.cpp
+++ b/screenlib/SDL_FrameBuf.cpp
@@ -37,6 +37,7 @@ FrameBuf:: FrameBuf() : ErrorBase()
 	/* Initialize various variables to null state */
 	window = NULL;
 	renderer = NULL;
+	texture = NULL;
 	faded = 0;
 }
 
@@ -46,11 +47,6 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 {
 	int w, h;
 
-#ifdef HACK_RESOLUTION
-	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
-#endif
-	AdjustCoordinates(width, height);
-
 #ifdef FAST_ITERATION
 	window_flags &= ~SDL_WINDOW_FULLSCREEN;
 #endif
@@ -67,24 +63,35 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 		return(-1);
 	}
 
+	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width, height);
+	if (!texture) {
+		SetError("Couldn't create target texture: %s", SDL_GetError());
+		return(-1);
+	}
+
+	if (SDL_SetRenderTarget(renderer, texture) < 0) {
+		SetError("Couldn't set render target: %s", SDL_GetError());
+		return(-1);
+	}
+
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+
 	/* Set the icon, if any */
 	if ( icon ) {
 		SDL_SetWindowIcon(window, icon);
 	}
 
-	/* Set the UI area */
+	/* Set the output area */
 	SDL_GetWindowSize(window, &w, &h);
-	rect.x = (w - width) / 2;
-	rect.y = (h - height) / 2;
-	rect.w = width;
-	rect.h = height;
-	SDL_RenderSetViewport(renderer, &rect);
-
-	/* Set the blit clipping rectangle */
-	clip.x = 0;
-	clip.y = 0;
-	clip.w = AdjustCoordinateX(width, true);
-	clip.h = AdjustCoordinateY(height, true);
+	output.w = w;
+	output.h = (height * w)/width;
+	output.x = (w - output.w) / 2;
+	output.y = (h - output.h) / 2;
+
+	clip.x = rect.x = 0;
+	clip.y = rect.y = 0;
+	clip.w = rect.w = width;
+	clip.h = rect.h = height;
 
 	/* Copy the image colormap */
 	if ( colors ) {
@@ -96,6 +103,9 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 
 FrameBuf:: ~FrameBuf()
 {
+	if (texture) {
+		SDL_DestroyTexture(texture);
+	}
 	if (renderer) {
 		SDL_DestroyRenderer(renderer);
 	}
@@ -118,16 +128,15 @@ FrameBuf:: SetPalette(SDL_Color *colors)
 bool
 FrameBuf::ConvertTouchCoordinates(const SDL_TouchFingerEvent &finger, int *x, int *y)
 {
-	int w, h;
 	SDL_Touch* inTouch = SDL_GetTouch(finger.touchId);
 	if (inTouch == NULL) {
 		return false;
 	}
 
-	SDL_GetWindowSize(window, &w, &h);
-	*x = (int)((((float)finger.x)/inTouch->xres)*w) - rect.x;
-	*y = (int)((((float)finger.y)/inTouch->yres)*h) - rect.y;
-	AdjustCoordinates(*x, *y, true);
+	*x = (int)((((float)finger.x)/inTouch->xres)*output.w) - output.x;
+	*y = (int)((((float)finger.y)/inTouch->yres)*output.h) - output.y;
+	*x = (*x * rect.w) / output.w;
+	*y = (*y * rect.h) / output.h;
 	return true;
 }
 
@@ -184,11 +193,22 @@ FrameBuf:: QueueBlit(int dstx, int dsty, SDL_Texture *src,
 		srcrect.w = dstrect.w;
 		srcrect.h = dstrect.h;
 	}
-	AdjustCoordinates(dstrect.x, dstrect.y);
-	AdjustCoordinates(dstrect.w, dstrect.h);
 	SDL_RenderCopy(renderer, src, &srcrect, &dstrect);
 }
 
+void
+FrameBuf:: Update(void)
+{
+	/* Copy from our render texture to the screen and show it! */
+	SDL_SetRenderTarget(renderer, NULL);
+	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+	SDL_RenderClear(renderer);
+	SDL_RenderCopy(renderer, texture, NULL, &output);
+	SDL_RenderPresent(renderer);
+
+	SDL_SetRenderTarget(renderer, texture);
+}
+
 void
 FrameBuf:: Fade(void)
 {
@@ -208,7 +228,7 @@ FrameBuf:: Fade(void)
 	}
 	faded = !faded;
 
-        if ( faded ) {
+	if ( faded ) {
 		for ( int i = 0; i < 256; i++ ) {
 			ramp[i] = 0;
 		}
@@ -245,8 +265,6 @@ FrameBuf:: ScreenDump(const char *prefix, int x, int y, int w, int h)
 	if (!h) {
 		h = Height();
 	}
-	AdjustCoordinates(x, y);
-	AdjustCoordinates(w, h);
 	rect.x = x;
 	rect.y = y;
 	rect.w = w;
diff --git a/screenlib/SDL_FrameBuf.h b/screenlib/SDL_FrameBuf.h
index 508c3824..6fc827b5 100644
--- a/screenlib/SDL_FrameBuf.h
+++ b/screenlib/SDL_FrameBuf.h
@@ -31,25 +31,6 @@
 // Define this if you're rapidly iterating on UI screens
 //#define FAST_ITERATION
 
-// Define these if you want to try out the quick resolution hacks
-//#define HACK_1024x768
-//#define HACK_400x300
-
-#ifdef HACK_1024x768
-#define HACK_RESOLUTION
-#define HACK_RESOLUTION_X 1024
-#define HACK_RESOLUTION_Y 768
-#endif
-#ifdef HACK_400x300
-#define HACK_RESOLUTION
-#define HACK_RESOLUTION_X 400
-#define HACK_RESOLUTION_Y 300
-#endif
-#ifdef HACK_RESOLUTION
-#define ORIG_RESOLUTION_X 640
-#define ORIG_RESOLUTION_Y 480
-#endif
-
 #include <stdio.h>
 
 #include "SDL.h"
@@ -68,31 +49,6 @@ class FrameBuf : public ErrorBase {
 			SDL_Color *colors = NULL, SDL_Surface *icon = NULL);
 	virtual ~FrameBuf();
 
-	int AdjustCoordinateX(int &x, bool invert = false) const {
-#ifdef HACK_RESOLUTION
-		if (invert) {
-			x = (x*ORIG_RESOLUTION_X)/HACK_RESOLUTION_X;
-		} else {
-			x = (x*HACK_RESOLUTION_X)/ORIG_RESOLUTION_X;
-		}
-#endif
-		return x;
-	}
-	int AdjustCoordinateY(int &y, bool invert = false) const {
-#ifdef HACK_RESOLUTION
-		if (invert) {
-			y = (y*ORIG_RESOLUTION_Y)/HACK_RESOLUTION_Y;
-		} else {
-			y = (y*HACK_RESOLUTION_Y)/ORIG_RESOLUTION_Y;
-		}
-#endif
-		return y;
-	}
-	void AdjustCoordinates(int &x, int &y, bool invert = false) const {
-		AdjustCoordinateX(x, invert);
-		AdjustCoordinateY(y, invert);
-	}
-
 	/* Setup routines */
 	/* Set the image palette -- 256 entries */
 	void SetPalette(SDL_Color *colors);
@@ -128,17 +84,17 @@ class FrameBuf : public ErrorBase {
 	void ProcessEvent(SDL_Event *event) {
 		switch (event->type) {
 			case SDL_MOUSEMOTION:
-				event->motion.x -= rect.x;
-				event->motion.y -= rect.y;
-				AdjustCoordinates(event->motion.x,
-						  event->motion.y, true);
+				event->motion.x -= output.x;
+				event->motion.y -= output.y;
+				event->motion.x = (event->motion.x * rect.w) / output.w;
+				event->motion.y = (event->motion.y * rect.h) / output.h;
 				break;
 			case SDL_MOUSEBUTTONDOWN:
 			case SDL_MOUSEBUTTONUP:
-				event->button.x -= rect.x;
-				event->button.y -= rect.y;
-				AdjustCoordinates(event->button.x,
-						  event->button.y, true);
+				event->button.x -= output.x;
+				event->button.y -= output.y;
+				event->motion.x = (event->motion.x * rect.w) / output.w;
+				event->motion.y = (event->motion.y * rect.h) / output.h;
 				break;
 		}
 	}
@@ -157,12 +113,10 @@ class FrameBuf : public ErrorBase {
 
 	/* Information routines */
 	int Width() const {
-		int w = rect.w;
-		return AdjustCoordinateX(w, true);
+		return rect.w;
 	}
 	int Height() const {
-		int h = rect.h;
-		return AdjustCoordinateY(h, true);
+		return rect.h;
 	}
 
 	/* Blit and update routines */
@@ -173,9 +127,7 @@ class FrameBuf : public ErrorBase {
 		SDL_QueryTexture(src, NULL, NULL, &w, &h);
 		QueueBlit(x, y, src, 0, 0, w, h, do_clip);
 	}
-	void Update() {
-		SDL_RenderPresent(renderer);
-	}
+	void Update(void);
 	void FadeOut(void) {
 		if (!faded) {
 			Fade();
@@ -190,9 +142,6 @@ class FrameBuf : public ErrorBase {
 
 	/* Drawing routines */
 	void Clear(int x, int y, int w, int h) {
-		AdjustCoordinates(x, y);
-		AdjustCoordinates(w, h);
-
 		FillRect(x, y, w, h, 0);
 	}
 	void Clear(void) {
@@ -200,24 +149,16 @@ class FrameBuf : public ErrorBase {
 		SDL_RenderClear(renderer);
 	}
 	void DrawPoint(int x, int y, Uint32 color) {
-		AdjustCoordinates(x, y);
-
 		UpdateDrawColor(color);
 		SDL_RenderDrawPoint(renderer, x, y);
 	}
 	void DrawLine(int x1, int y1, int x2, int y2, Uint32 color) {
-		AdjustCoordinates(x1, y1);
-		AdjustCoordinates(x2, y2);
-
 		UpdateDrawColor(color);
 		SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
 	}
 	void DrawRect(int x1, int y1, int w, int h, Uint32 color) {
 		UpdateDrawColor(color);
 
-		AdjustCoordinates(x1, y1);
-		AdjustCoordinates(w, h);
-
 		SDL_Rect rect;
 		rect.x = x1;
 		rect.y = y1;
@@ -228,9 +169,6 @@ class FrameBuf : public ErrorBase {
 	void FillRect(int x1, int y1, int w, int h, Uint32 color) {
 		UpdateDrawColor(color);
 
-		AdjustCoordinates(x1, y1);
-		AdjustCoordinates(w, h);
-
 		SDL_Rect rect;
 		rect.x = x1;
 		rect.y = y1;
@@ -273,10 +211,12 @@ class FrameBuf : public ErrorBase {
 	/* The current display */
 	SDL_Window *window;
 	SDL_Renderer *renderer;
+	SDL_Texture *texture;
 	Uint32 image_map[256];
 	int faded;
 	SDL_Rect rect;
 	SDL_Rect clip;
+	SDL_Rect output;
 
 	void UpdateDrawColor(Uint32 color) {
 		Uint8 r, g, b;