shithub: zelda3

Download patch

ref: d24e3f0e4233ad6e203811d960c30113e988497e
parent: 7fee491ba0fe826afcf6e2d02d610984b2419deb
author: Snesrev <[email protected]>
date: Wed Aug 31 23:30:43 EDT 2022

Support different zoom levels and borderless mode. Fixes #30

- Change zoom level with Ctrl+MouseWheel
- Ctrl+Drag to drag window
- Shift+DoubleClick to remove window border

Thanks Nutzzz.

--- a/main.c
+++ b/main.c
@@ -41,6 +41,8 @@
 static void HandleGamepadInput(int button, bool pressed);
 static void HandleGamepadAxisInput(int gamepad_id, int axis, int value);
 static void OpenOneGamepad(int i);
+static inline int IntMin(int a, int b) { return a < b ? a : b; }
+static inline int IntMax(int a, int b) { return a > b ? a : b; }
 
 static int input1_current_state;
 
@@ -58,6 +60,58 @@
   }
 }
 
+enum {
+  kRenderWidth = 512,
+  kRenderHeight = 480,
+  kDefaultZoom = 2,
+};
+
+static int current_zoom = kDefaultZoom;
+
+void DoZoom(SDL_Window *window, SDL_Renderer *renderer, int zoom_step) {
+  int screen = SDL_GetWindowDisplayIndex(window);
+  if (screen < 0) screen = 0;
+  int max_zoom = kDefaultZoom * 5;
+  SDL_Rect bounds;
+  int bt = -1, bl, bb, br;
+  // note this takes into effect Windows display scaling, i.e., resolution is divided by scale factor
+  if (SDL_GetDisplayUsableBounds(screen, &bounds) == 0) {
+    // this call may take a while before it is reported by Windows (or not at all in my testing)
+    if (SDL_GetWindowBordersSize(window, &bt, &bl, &bb, &br) != 0) {
+      // guess based on Windows 10/11 defaults
+      bl = br = bb = 1;
+      bt = 31;
+    }
+    // Allow a zoom level slightly above the max that fits on screen
+    int mw = (bounds.w - bl - br + (kRenderWidth / kDefaultZoom) / 4) / (kRenderWidth / kDefaultZoom);
+    int mh = (bounds.h - bt - bb + (kRenderHeight / kDefaultZoom) / 4) / (kRenderHeight / kDefaultZoom);
+    max_zoom = IntMin(mw, mh);
+  }
+  int new_zoom = IntMax(IntMin(current_zoom + zoom_step, max_zoom), 1);
+  current_zoom = new_zoom;
+  int w = new_zoom * (kRenderWidth / kDefaultZoom);
+  int h = new_zoom * (kRenderHeight / kDefaultZoom);
+  SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+  SDL_RenderSetLogicalSize(renderer, w, h);
+  SDL_SetWindowSize(window, w, h);
+  if (bt >= 0) {
+    // Center the window on top of the mouse
+    int mx, my;
+    SDL_GetGlobalMouseState(&mx, &my);
+    int wx = IntMax(IntMin(mx - w / 2, bounds.x + bounds.w - bl - br - w), bounds.x + bl);
+    int wy = IntMax(IntMin(my - h / 2, bounds.y + bounds.h - bt - bb - h), bounds.y + bt);
+    SDL_SetWindowPosition(window, wx, wy);
+  } else {
+    SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+  }
+}
+
+static SDL_HitTestResult HitTestCallback(SDL_Window *win, const SDL_Point *area, void *data) {
+  uint32 flags = SDL_GetWindowFlags(win);
+  return (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 && 
+         (SDL_GetModState() & KMOD_CTRL) != 0 ? SDL_HITTEST_DRAGGABLE : SDL_HITTEST_NORMAL;
+}
+
 #undef main
 int main(int argc, char** argv) {
   // set up SDL
@@ -66,17 +120,18 @@
     return 1;
   }
   uint32 win_flags = SDL_WINDOWPOS_UNDEFINED;
-  SDL_Window* window = SDL_CreateWindow("Zelda3", SDL_WINDOWPOS_UNDEFINED, win_flags, 512, 480, 0);
+  SDL_Window* window = SDL_CreateWindow("Zelda3", SDL_WINDOWPOS_UNDEFINED, win_flags, kRenderWidth, kRenderHeight, 0);
   if(window == NULL) {
     printf("Failed to create window: %s\n", SDL_GetError());
     return 1;
   }
+  SDL_SetWindowHitTest(window, HitTestCallback, NULL);
   SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
   if(renderer == NULL) {
     printf("Failed to create renderer: %s\n", SDL_GetError());
     return 1;
   }
-  SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, 512, 480);
+  SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, kRenderWidth, kRenderHeight);
   if(texture == NULL) {
     printf("Failed to create texture: %s\n", SDL_GetError());
     return 1;
@@ -153,6 +208,18 @@
       case SDL_CONTROLLERBUTTONUP:
         HandleGamepadInput(event.cbutton.button, event.cbutton.state == SDL_PRESSED);
         break;
+      case SDL_MOUSEWHEEL:
+        if ((win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 && event.wheel.y != 0 && SDL_GetModState() & KMOD_CTRL)
+          DoZoom(window, renderer, event.wheel.y > 0 ? 1 : -1);
+        break;
+      case SDL_MOUSEBUTTONDOWN:
+        if (event.button.button == SDL_BUTTON_LEFT && event.button.state == SDL_PRESSED && event.button.clicks == 2) {
+          if ((win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 && SDL_GetModState() & KMOD_SHIFT) {
+            win_flags ^= SDL_WINDOW_BORDERLESS;
+            SDL_SetWindowBordered(window, (win_flags & SDL_WINDOW_BORDERLESS) == 0);
+          }
+        }
+        break;
       case SDL_KEYDOWN: {
         bool skip_default = false;
         switch(event.key.keysym.sym) {
@@ -178,7 +245,7 @@
         case SDLK_RETURN:
           if (event.key.keysym.mod & KMOD_ALT) {
             win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
-            SDL_SetWindowFullscreen(window, win_flags);
+            SDL_SetWindowFullscreen(window, win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP);
             skip_default = true;
           }
           break;