Implemented desktop_size discovery in GLRenderer
[supertux.git] / src / video / gl / gl_renderer.cpp
index 81d8743..950ee40 100644 (file)
@@ -1,5 +1,6 @@
 //  SuperTux
 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//     Updated by GiBy 2013 for SDL2 <giby_the_kid@yahoo.fr>
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -19,6 +20,7 @@
 #include <iomanip>
 #include <iostream>
 #include <physfs.h>
+#include "SDL.h"
 
 #include "supertux/gameconfig.hpp"
 #include "supertux/globals.hpp"
 #endif
 
 GLRenderer::GLRenderer() :
+  window(),
   desktop_size(-1, -1),
   screen_size(-1, -1),
-  fullscreen_active(false)
+  fullscreen_active(false),
+  last_texture(static_cast<GLuint> (-1))
 {
   Renderer::instance_ = this;
 
-#if SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION > 2 || (SDL_MINOR_VERSION == 2 && SDL_PATCHLEVEL >= 10)
-  // unfortunately only newer SDLs have these infos.
-  // This must be called before SDL_SetVideoMode() or it will return
-  // the window size instead of the desktop size.
-  const SDL_VideoInfo *info = SDL_GetVideoInfo();
-  if (info)
-  {
-    desktop_size = Size(info->current_w, info->current_h);
-  }
-#endif
+  SDL_DisplayMode mode;
+  SDL_GetCurrentDisplayMode(0, &mode);
+  desktop_size = Size(mode.w, mode.h);
 
   if(texture_manager != 0)
     texture_manager->save_textures();
 
-#ifdef SDL_GL_SWAP_CONTROL
-  if(config->try_vsync) {
+  if(g_config->try_vsync) {
     /* we want vsync for smooth scrolling */
-    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
+    if (SDL_GL_SetSwapInterval(-1) != 0)
+    {
+      log_info << "no support for late swap tearing vsync: " << SDL_GetError() << std::endl;
+      if (SDL_GL_SetSwapInterval(1))
+      {
+        log_info << "no support for vsync: " << SDL_GetError() << std::endl;
+      }
+    }
   }
-#endif
 
   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 
-  // FIXME: Hu? 16bit rendering?
   SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   5);
   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  5);
@@ -107,16 +108,34 @@ GLRenderer::GLRenderer() :
 
 GLRenderer::~GLRenderer()
 {
+  SDL_GL_DeleteContext(glcontext);
+  SDL_DestroyWindow(window);
 }
 
 void
 GLRenderer::draw_surface(const DrawingRequest& request)
 {
   const Surface* surface = (const Surface*) request.request_data;
-  boost::shared_ptr<GLTexture> gltexture = boost::dynamic_pointer_cast<GLTexture>(surface->get_texture());
-  GLSurfaceData *surface_data = reinterpret_cast<GLSurfaceData *>(surface->get_surface_data());
+  if(surface == NULL)
+  {
+    return;
+  }
+  GLTexture* gltexture = static_cast<GLTexture*>(surface->get_texture().get());
+  if(gltexture == NULL)
+  {
+    return;
+  }
+  GLSurfaceData *surface_data = static_cast<GLSurfaceData*>(surface->get_surface_data());
+  if(surface_data == NULL)
+  {
+    return;
+  }
 
-  glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+  GLuint th = gltexture->get_handle();
+  if (th != last_texture) {
+    last_texture = th;
+    glBindTexture(GL_TEXTURE_2D, th);
+  }
   intern_draw(request.pos.x, request.pos.y,
               request.pos.x + surface->get_width(),
               request.pos.y + surface->get_height(),
@@ -148,7 +167,11 @@ GLRenderer::draw_surface_part(const DrawingRequest& request)
   float uv_right = surface_data->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
   float uv_bottom = surface_data->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
 
-  glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
+  GLuint th = gltexture->get_handle();
+  if (th != last_texture) {
+    last_texture = th;
+    glBindTexture(GL_TEXTURE_2D, th);
+  }
   intern_draw(request.pos.x, request.pos.y,
               request.pos.x + surfacepartrequest->size.x,
               request.pos.y + surfacepartrequest->size.y,
@@ -177,9 +200,9 @@ GLRenderer::draw_gradient(const DrawingRequest& request)
 
   float vertices[] = {
     0, 0,
-    SCREEN_WIDTH, 0,
-    SCREEN_WIDTH, SCREEN_HEIGHT,
-    0, SCREEN_HEIGHT
+    float(SCREEN_WIDTH), 0,
+    float(SCREEN_WIDTH), float(SCREEN_HEIGHT),
+    0, float(SCREEN_HEIGHT)
   };
   glVertexPointer(2, GL_FLOAT, 0, vertices);
 
@@ -433,18 +456,17 @@ void
 GLRenderer::flip()
 {
   assert_gl("drawing");
-  SDL_GL_SwapBuffers();
+  SDL_GL_SwapWindow(window);
 }
 
 void
 GLRenderer::resize(int w, int h)
 {
-  // This causes the screen to go black, which is annoying, but seems
-  // unavoidable with SDL at the moment
-  SDL_SetVideoMode(w, h, 0, SDL_OPENGL | SDL_RESIZABLE);
-
   g_config->window_size = Size(w, h);
 
+  PHYSICAL_SCREEN_WIDTH = w;
+  PHYSICAL_SCREEN_HEIGHT = h;
+
   apply_config();
 }
 
@@ -500,12 +522,13 @@ GLRenderer::apply_config()
     SCREEN_HEIGHT = static_cast<int>(screen_size.height  * (target_aspect / desktop_aspect));
   }
 
-  Size max_size(1600, 1200); // FIXME: Maybe 1920 is ok too
+  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
+    // 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;
@@ -513,7 +536,16 @@ GLRenderer::apply_config()
       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);
     }
+   
 
     glViewport(0, 0, screen_size.width, screen_size.height);
   }
@@ -540,9 +572,9 @@ GLRenderer::apply_config()
 
     // Clear both buffers so that we get a clean black border without junk
     glClear(GL_COLOR_BUFFER_BIT);
-    SDL_GL_SwapBuffers();
+    SDL_GL_SwapWindow(window);
     glClear(GL_COLOR_BUFFER_BIT);
-    SDL_GL_SwapBuffers();
+    SDL_GL_SwapWindow(window);
 
     glViewport(std::max(0, (screen_size.width  - new_size.width)  / 2),
                std::max(0, (screen_size.height - new_size.height) / 2),
@@ -564,32 +596,87 @@ GLRenderer::apply_config()
 void
 GLRenderer::apply_video_mode(const Size& size, bool fullscreen)
 {
-  // Only change video mode when its different from the current one
-  if (screen_size != size || fullscreen_active != fullscreen)
+  if (window)
   {
-    int flags = SDL_OPENGL;
+    SDL_SetWindowSize(window, size.width, size.height);
 
     if (fullscreen)
     {
-      flags |= SDL_FULLSCREEN;
+      int fullscreen_flags = SDL_WINDOW_FULLSCREEN; // SDL_WINDOW_FULLSCREEN_DESKTOP or 0
+      SDL_SetWindowDisplayMode(window, NULL);
+
+      SDL_DisplayMode mode;
+      mode.format = SDL_PIXELFORMAT_RGB888;
+      mode.w = g_config->fullscreen_size.width;
+      mode.h = g_config->fullscreen_size.height;
+      mode.refresh_rate = g_config->fullscreen_refresh_rate;
+      mode.driverdata = 0;
+
+      if (SDL_SetWindowDisplayMode(window, &mode) != 0)
+      {
+        log_warning << "failed to set display mode: "
+                    << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": "
+                    << SDL_GetError() << std::endl;
+      }
+      else
+      {
+        SDL_SetWindowFullscreen(window, fullscreen_flags);
+      }
     }
     else
     {
-      flags |= SDL_RESIZABLE;
-    }
-
-    if (SDL_Surface *screen = SDL_SetVideoMode(size.width, size.height, 0, flags))
-    {
-      screen_size = Size(screen->w, screen->h);
-      fullscreen_active = fullscreen; 
+      SDL_SetWindowFullscreen(window, 0);
     }
-    else
+  }
+  else
+  {
+    // Only change video mode when its different from the current one
+    if (screen_size != size || fullscreen_active != fullscreen)
     {
-      std::ostringstream msg;
-      msg << "Couldn't set video mode " << size.width << "x" << size.height << ": " << SDL_GetError();
-      throw std::runtime_error(msg.str());
+      int flags = SDL_WINDOW_OPENGL;
+
+      if (fullscreen)
+      {
+        flags |= SDL_WINDOW_FULLSCREEN;
+      }
+      else
+      {
+        flags |= SDL_WINDOW_RESIZABLE;
+      }
+
+      window = SDL_CreateWindow("SuperTux",
+                                SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+                                size.width, size.height,
+                                flags);
+      if (!window)
+      {
+        std::ostringstream msg;
+        msg << "Couldn't set video mode " << size.width << "x" << size.height << ": " << SDL_GetError();
+        throw std::runtime_error(msg.str());
+      }
+      else
+      {
+        glcontext = SDL_GL_CreateContext(window);
+        screen_size = size;
+        
+        PHYSICAL_SCREEN_WIDTH = size.width;
+        PHYSICAL_SCREEN_HEIGHT = size.height;
+
+        SCREEN_WIDTH = size.width;
+        SCREEN_HEIGHT = size.height;
+        
+        fullscreen_active = fullscreen;
+      }
     }
   }
 }
 
+void
+GLRenderer::set_gamma(float gamma)
+{
+  Uint16 ramp[256];
+  SDL_CalculateGammaRamp(gamma, ramp);
+  SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
+}
+
 /* EOF */