changeset 2308:b7768c58f0da

Initial stab at DPI scaling support
author Michael Pavone <pavone@retrodev.com>
date Sun, 26 Mar 2023 22:39:18 -0700
parents a8080240cb92
children 5e34369ed6be
files nuklear_ui/blastem_nuklear.c nuklear_ui/nuklear_sdl_gles2.h render.h render_sdl.c
diffstat 4 files changed, 72 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/nuklear_ui/blastem_nuklear.c	Thu Mar 23 22:38:51 2023 -0700
+++ b/nuklear_ui/blastem_nuklear.c	Sun Mar 26 22:39:18 2023 -0700
@@ -2327,11 +2327,6 @@
 	}
 }
 
-static void fb_resize(void)
-{
-	nk_rawfb_resize_fb(fb_context, NULL, render_width(), render_height(), 0);
-}
-
 #ifndef DISABLE_OPENGL
 static struct nk_image load_image_texture(uint32_t *buf, uint32_t width, uint32_t height)
 {
@@ -2418,10 +2413,26 @@
 	context->style.combo.button.text_hover = context->style.property.inc_button.text_hover;
 }
 
+static void fb_resize(void)
+{
+	nk_rawfb_resize_fb(fb_context, NULL, render_width(), render_height(), 0);
+	style_init();
+	texture_init();
+}
+
 static void context_created(void)
 {
 	context = nk_sdl_init(render_get_window());
-	nk_sdl_device_create();
+#ifndef DISABLE_OPENGL
+	if (render_has_gl()) {
+		nk_sdl_device_create();
+	} else {
+#endif
+		fb_context = nk_rawfb_init(NULL, context, render_width(), render_height(), 0);
+		render_set_ui_fb_resize_handler(fb_resize);
+#ifndef DISABLE_OPENGL
+	}
+#endif
 	style_init();
 	texture_init();
 }
--- a/nuklear_ui/nuklear_sdl_gles2.h	Thu Mar 23 22:38:51 2023 -0700
+++ b/nuklear_ui/nuklear_sdl_gles2.h	Sun Mar 26 22:39:18 2023 -0700
@@ -23,6 +23,7 @@
 #include <GL/glew.h>
 #endif
 #endif
+#include "../render.h"
 
 
 NK_API struct nk_context*   nk_sdl_init(SDL_Window *win);
@@ -118,7 +119,7 @@
         "}\n";
 
     struct nk_sdl_device *dev = &sdl.ogl;
-    
+
     nk_buffer_init_default(&dev->cmds);
     dev->prog = glCreateProgram();
     dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
@@ -148,7 +149,7 @@
         dev->vp = offsetof(struct nk_sdl_vertex, position);
         dev->vt = offsetof(struct nk_sdl_vertex, uv);
         dev->vc = offsetof(struct nk_sdl_vertex, col);
-        
+
         /* Allocate buffers */
         glGenBuffers(1, &dev->vbo);
         glGenBuffers(1, &dev->ebo);
@@ -233,7 +234,7 @@
         /* Bind buffers */
         glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-        
+
         {
             /* buffer setup */
             glEnableVertexAttribArray((GLuint)dev->attrib_pos);
@@ -445,7 +446,7 @@
     } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
         /* mouse button */
         int down = evt->type == SDL_MOUSEBUTTONDOWN;
-        const int x = evt->button.x, y = evt->button.y;
+        const int x = render_ui_to_pixels_x(evt->button.x), y = render_ui_to_pixels_y(evt->button.y);
         if (evt->button.button == SDL_BUTTON_LEFT) {
             if (evt->button.clicks > 1)
                 nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
@@ -458,9 +459,9 @@
     } else if (evt->type == SDL_MOUSEMOTION) {
         /* mouse motion */
         if (ctx->input.mouse.grabbed) {
-            int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
-            nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
-        } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+            int x = render_ui_to_pixels_x((int)ctx->input.mouse.prev.x), y = render_ui_to_pixels_y((int)ctx->input.mouse.prev.y);
+            nk_input_motion(ctx, x + render_ui_to_pixels_x(evt->motion.xrel), y + render_ui_to_pixels_y(evt->motion.yrel));
+        } else nk_input_motion(ctx, render_ui_to_pixels_x(evt->motion.x), render_ui_to_pixels_y(evt->motion.y));
         return 1;
     } else if (evt->type == SDL_TEXTINPUT) {
         /* text input */
--- a/render.h	Thu Mar 23 22:38:51 2023 -0700
+++ b/render.h	Sun Mar 26 22:39:18 2023 -0700
@@ -146,6 +146,8 @@
 void render_set_external_sync(uint8_t ext_sync_on);
 void render_reset_mappings(void);
 void render_update_display(void);
+int render_ui_to_pixels_x(int ui);
+int render_ui_to_pixels_y(int ui);
 #ifndef IS_LIB
 uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data);
 #endif
--- a/render_sdl.c	Thu Mar 23 22:38:51 2023 -0700
+++ b/render_sdl.c	Sun Mar 26 22:39:18 2023 -0700
@@ -297,9 +297,9 @@
 	}
 }
 
+static int tex_width, tex_height;
 #ifndef DISABLE_OPENGL
 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, un_texsize, at_pos;
-static int tex_width, tex_height;
 
 static GLfloat vertex_data_default[] = {
 	-1.0f, -1.0f,
@@ -810,6 +810,17 @@
 	return desired_index;
 }
 
+static float ui_scale_x = 1.0f, ui_scale_y = 1.0f;
+int render_ui_to_pixels_x(int ui)
+{
+	return ui * ui_scale_x + 0.5f;
+}
+
+int render_ui_to_pixels_y(int ui)
+{
+	return ui * ui_scale_y + 0.5f;
+}
+
 static int32_t handle_event(SDL_Event *event)
 {
 	if (custom_event_handler) {
@@ -868,7 +879,7 @@
 		break;
 	}
 	case SDL_MOUSEMOTION:
-		handle_mouse_moved(event->motion.which, event->motion.x, event->motion.y + overscan_top[video_standard], event->motion.xrel, event->motion.yrel);
+		handle_mouse_moved(event->motion.which, event->motion.x * ui_scale_x + 0.5f, event->motion.y * ui_scale_y + 0.5f + overscan_top[video_standard], event->motion.xrel, event->motion.yrel);
 		break;
 	case SDL_MOUSEBUTTONDOWN:
 		handle_mousedown(event->button.which, event->button.button);
@@ -883,10 +894,7 @@
 			if (!main_window) {
 				break;
 			}
-			main_width = event->window.data1;
-			main_height = event->window.data2;
 			need_ui_fb_resize = 1;
-			update_aspect();
 #ifndef DISABLE_OPENGL
 			if (render_gl) {
 				if (on_context_destroyed) {
@@ -895,12 +903,26 @@
 				gl_teardown();
 				SDL_GL_DeleteContext(main_context);
 				main_context = SDL_GL_CreateContext(main_window);
+				SDL_GL_GetDrawableSize(main_window, &main_width, &main_height);
+				update_aspect();
 				gl_setup();
 				if (on_context_created) {
 					on_context_created();
 				}
+			} else {
+#endif
+				SDL_GetRendererOutputSize(main_renderer, &main_width, &main_height);
+				update_aspect();
+#ifndef DISABLE_OPENGL
 			}
 #endif
+			if (main_width != event->window.data1 || main_height != event->window.data2) {
+				debug_message("Window resized - UI units %dx%d, pixels %dx%d\n", event->window.data1, event->window.data2, main_width, main_height);
+			} else {
+				debug_message("Window resized: %dx%d\n", main_width, main_height);
+			}
+			ui_scale_x = (float)main_width / (float)event->window.data1;
+			ui_scale_y = (float)main_height / (float)event->window.data2;
 			break;
 		case SDL_WINDOWEVENT_CLOSE:
 			if (main_window && SDL_GetWindowID(main_window) == event->window.windowID) {
@@ -1002,7 +1024,7 @@
 
 void window_setup(void)
 {
-	uint32_t flags = SDL_WINDOW_RESIZABLE;
+	uint32_t flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
 	if (is_fullscreen) {
 		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 	}
@@ -1089,6 +1111,9 @@
 	if (!main_window) {
 		fatal_error("Unable to create SDL window: %s\n", SDL_GetError());
 	}
+	SDL_GetWindowSize(main_window, &main_width, &main_height);
+	debug_message("Window created with size: %d x %d\n", main_width, main_height);
+	int orig_width = main_width, orig_height = main_height;
 #ifndef DISABLE_OPENGL
 	if (gl_enabled)
 	{
@@ -1123,6 +1148,7 @@
 #endif
 				}
 			}
+			SDL_GL_GetDrawableSize(main_window, &main_width, &main_height);
 		} else {
 			warning("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n");
 		}
@@ -1138,6 +1164,7 @@
 		if (!main_renderer) {
 			fatal_error("unable to create SDL renderer: %s\n", SDL_GetError());
 		}
+		SDL_GetRendererOutputSize(main_renderer, &main_width, &main_height);
 		SDL_RendererInfo rinfo;
 		SDL_GetRendererInfo(main_renderer, &rinfo);
 		debug_message("SDL2 Render Driver: %s\n", rinfo.name);
@@ -1148,8 +1175,13 @@
 	}
 #endif
 
-	SDL_GetWindowSize(main_window, &main_width, &main_height);
-	debug_message("Window created with size: %d x %d\n", main_width, main_height);
+	if (main_width != orig_width || main_height != orig_height) {
+		debug_message("True window resolution %d x %d\n", main_width, main_height);
+	}
+	ui_scale_x = (float)main_width / (float)orig_width;
+	ui_scale_y = (float)main_height / (float)orig_height;
+
+
 	update_aspect();
 	render_alloc_surfaces();
 	def.ptrval = "off";
@@ -1158,6 +1190,11 @@
 
 void render_init(int width, int height, char * title, uint8_t fullscreen)
 {
+#ifdef SDL_HINT_WINDOWS_DPI_SCALING
+	//In some ways, the other DPI scaling option for SDL2 on Windows is better for BlastEm's needs,
+	//but setting this makes it more consistent with how high DPI support works on other platforms
+	SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "1");
+#endif
 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
 		fatal_error("Unable to init SDL: %s\n", SDL_GetError());
 	}