Implemented window scaling in SDLRenderer, mouse input however breaks when scaling
authorIngo Ruhnke <grumbel@gmail.com>
Thu, 31 Jul 2014 20:17:16 +0000 (22:17 +0200)
committerIngo Ruhnke <grumbel@gmail.com>
Thu, 31 Jul 2014 20:17:16 +0000 (22:17 +0200)
src/video/sdl/sdl_renderer.cpp
src/video/sdl/sdl_renderer.hpp

index 892e39a..106e013 100644 (file)
 
 SDLRenderer::SDLRenderer() :
   window(),
-  renderer()
+  renderer(),
+  desktop_size()
 {
   Renderer::instance_ = this;
 
+  SDL_DisplayMode mode;
+  SDL_GetCurrentDisplayMode(0, &mode);
+  desktop_size = Size(mode.w, mode.h);
+
   log_info << "creating SDLRenderer" << std::endl;
   int width  = g_config->window_size.width;
   int height = g_config->window_size.height;
@@ -201,11 +206,133 @@ SDLRenderer::flip()
 void
 SDLRenderer::resize(int w , int h)
 {
-  SCREEN_WIDTH  = w;
-  SCREEN_HEIGHT = h;
+  g_config->window_size = Size(w, h);
 
   PHYSICAL_SCREEN_WIDTH = w;
   PHYSICAL_SCREEN_HEIGHT = h;
+
+  apply_config();
+}
+
+void
+SDLRenderer::apply_config()
+{
+  if (false)
+  {
+    log_info << "Applying Config:" 
+             << "\n  Desktop: " << desktop_size.width << "x" << desktop_size.height
+             << "\n  Window:  " << g_config->window_size
+             << "\n  FullRes: " << g_config->fullscreen_size
+             << "\n  Aspect:  " << g_config->aspect_size
+             << "\n  Magnif:  " << g_config->magnification
+             << std::endl;
+  }
+
+  float target_aspect = static_cast<float>(desktop_size.width) / static_cast<float>(desktop_size.height);
+  if (g_config->aspect_size != Size(0, 0))
+  {
+    target_aspect = float(g_config->aspect_size.width) / float(g_config->aspect_size.height);
+  }
+
+  float desktop_aspect = 4.0f / 3.0f; // random default fallback guess
+  if (desktop_size.width != -1 && desktop_size.height != -1)
+  {
+    desktop_aspect = float(desktop_size.width) / float(desktop_size.height);
+  }
+
+  Size screen_size;
+
+  // Get the screen width
+  if (g_config->use_fullscreen)
+  {
+    screen_size = g_config->fullscreen_size;
+    desktop_aspect = float(screen_size.width) / float(screen_size.height);
+  }
+  else
+  {
+    screen_size = g_config->window_size;
+  }
+
+  //apply_video_mode(screen_size, g_config->use_fullscreen);
+
+  if (target_aspect > 1.0f)
+  {
+    SCREEN_WIDTH  = static_cast<int>(screen_size.width * (target_aspect / desktop_aspect));
+    SCREEN_HEIGHT = static_cast<int>(screen_size.height);
+  }
+  else
+  {
+    SCREEN_WIDTH  = static_cast<int>(screen_size.width);
+    SCREEN_HEIGHT = static_cast<int>(screen_size.height  * (target_aspect / desktop_aspect));
+  }
+
+  Size max_size(1280, 800);
+  Size min_size(640, 480);
+
+  if (g_config->magnification == 0.0f) // Magic value that means 'minfill'
+  {
+    // This scales SCREEN_WIDTH/SCREEN_HEIGHT so that they never excede
+    // max_size.width/max_size.height resp. min_size.width/min_size.height
+    if (SCREEN_WIDTH > max_size.width || SCREEN_HEIGHT > max_size.height)
+    {
+      float scale1  = float(max_size.width)/SCREEN_WIDTH;
+      float scale2  = float(max_size.height)/SCREEN_HEIGHT;
+      float scale   = (scale1 < scale2) ? scale1 : scale2;
+      SCREEN_WIDTH  = static_cast<int>(SCREEN_WIDTH  * scale);
+      SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * scale);
+    } 
+    else if (SCREEN_WIDTH < min_size.width || SCREEN_HEIGHT < min_size.height)
+    {
+      float scale1  = float(min_size.width)/SCREEN_WIDTH;
+      float scale2  = float(min_size.height)/SCREEN_HEIGHT;
+      float scale   = (scale1 < scale2) ? scale1 : scale2;
+      SCREEN_WIDTH  = static_cast<int>(SCREEN_WIDTH  * scale);
+      SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * scale);
+    }
+   
+    SDL_Rect viewport;
+    viewport.x = 0;
+    viewport.y = 0;
+    viewport.w = screen_size.width;
+    viewport.h = screen_size.height;
+    SDL_RenderSetViewport(renderer, &viewport);
+  }
+  else
+  {
+    SCREEN_WIDTH  = static_cast<int>(SCREEN_WIDTH  / g_config->magnification);
+    SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT / g_config->magnification);
+
+    // This works by adding black borders around the screen to limit
+    // SCREEN_WIDTH/SCREEN_HEIGHT to max_size.width/max_size.height
+    Size new_size = screen_size;
+
+    if (SCREEN_WIDTH > max_size.width)
+    {
+      new_size.width = static_cast<int>((float) new_size.width * float(max_size.width)/SCREEN_WIDTH);
+      SCREEN_WIDTH = static_cast<int>(max_size.width);
+    }
+
+    if (SCREEN_HEIGHT > max_size.height)
+    {
+      new_size.height = static_cast<int>((float) new_size.height * float(max_size.height)/SCREEN_HEIGHT);
+      SCREEN_HEIGHT = static_cast<int>(max_size.height);
+    }
+
+    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
+    SDL_RenderClear(renderer);
+    SDL_RenderPresent(renderer);
+    SDL_RenderClear(renderer);
+
+    SDL_Rect viewport;
+    viewport.x = std::max(0, (screen_size.width  - new_size.width)  / 2);
+    viewport.y = std::max(0, (screen_size.height - new_size.height) / 2);
+    viewport.w = std::min(new_size.width,  screen_size.width);
+    viewport.h = std::min(new_size.height, screen_size.height);
+    SDL_RenderSetViewport(renderer, &viewport);
+  }
+
+  SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
 }
 
 void
index 67dd321..4c8a62c 100644 (file)
@@ -34,7 +34,7 @@ public:
   void do_take_screenshot();
   void flip();
   void resize(int w, int h);
-  void apply_config() {}
+  void apply_config();
   void set_gamma(float gamma);
   SDL_Window* get_window() const { return window; }
 
@@ -43,6 +43,7 @@ public:
 private:
   SDL_Window* window;
   SDL_Renderer* renderer;
+  Size desktop_size;
 
 private:
   SDLRenderer(const SDLRenderer&);