Added SDL_RenderSetLogicalSize() and SDL_RenderGetLogicalSize()
authorSam Lantinga <slouken@libsdl.org>
Mon, 01 Oct 2012 22:30:07 -0700
changeset 6530ba5de88eab60
parent 6529 9094fcfd378d
child 6531 1ab2e34b90cc
Added SDL_RenderSetLogicalSize() and SDL_RenderGetLogicalSize()
include/SDL_render.h
src/render/SDL_render.c
src/render/SDL_sysrender.h
     1.1 --- a/include/SDL_render.h	Mon Oct 01 21:57:09 2012 -0700
     1.2 +++ b/include/SDL_render.h	Mon Oct 01 22:30:07 2012 -0700
     1.3 @@ -418,6 +418,40 @@
     1.4                                                  SDL_Texture *texture);
     1.5  
     1.6  /**
     1.7 + *  \brief Set device independent resolution for rendering
     1.8 + *
     1.9 + *  \param w      The width of the logical resolution
    1.10 + *  \param h      The height of the logical resolution
    1.11 + *
    1.12 + *  This function uses the viewport and scaling functionality to allow a fixed logical
    1.13 + *  resolution for rendering, regardless of the actual output resolution.  If the actual
    1.14 + *  output resolution doesn't have the same aspect ratio the output rendering will be
    1.15 + *  centered within the output display.
    1.16 + *
    1.17 + *  If the output display is a window, mouse events in the window will be filtered
    1.18 + *  and scaled so they seem to arrive within the logical resolution.
    1.19 + *
    1.20 + *  \note If this function results in scaling or subpixel drawing by the 
    1.21 + *        rendering backend, it will be handled using the appropriate
    1.22 + *        quality hints.
    1.23 + *
    1.24 + *  \sa SDL_RenderGetLogicalSize()
    1.25 + *  \sa SDL_RenderSetScale()
    1.26 + *  \sa SDL_RenderSetViewport()
    1.27 + */
    1.28 +extern DECLSPEC int SDLCALL SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h);
    1.29 +
    1.30 +/**
    1.31 + *  \brief Get device independent resolution for rendering
    1.32 + *
    1.33 + *  \param w      A pointer filled with the width of the logical resolution
    1.34 + *  \param h      A pointer filled with the height of the logical resolution
    1.35 + *
    1.36 + *  \sa SDL_RenderSetLogicalSize()
    1.37 + */
    1.38 +extern DECLSPEC void SDLCALL SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *y);
    1.39 +
    1.40 +/**
    1.41   *  \brief Set the drawing area for rendering on the current target.
    1.42   *
    1.43   *  \param rect The rectangle representing the drawing area, or NULL to set the viewport to the entire target.
    1.44 @@ -426,12 +460,17 @@
    1.45   *
    1.46   *  \note When the window is resized, the current viewport is automatically
    1.47   *        centered within the new window size.
    1.48 + *
    1.49 + *  \sa SDL_RenderGetViewport()
    1.50 + *  \sa SDL_RenderSetLogicalSize()
    1.51   */
    1.52  extern DECLSPEC int SDLCALL SDL_RenderSetViewport(SDL_Renderer * renderer,
    1.53                                                    const SDL_Rect * rect);
    1.54  
    1.55  /**
    1.56   *  \brief Get the drawing area for the current target.
    1.57 + *
    1.58 + *  \sa SDL_RenderSetViewport()
    1.59   */
    1.60  extern DECLSPEC void SDLCALL SDL_RenderGetViewport(SDL_Renderer * renderer,
    1.61                                                     SDL_Rect * rect);
    1.62 @@ -449,6 +488,9 @@
    1.63   *  \note If this results in scaling or subpixel drawing by the 
    1.64   *        rendering backend, it will be handled using the appropriate
    1.65   *        quality hints.  For best results use integer scaling factors.
    1.66 + *
    1.67 + *  \sa SDL_RenderGetScale()
    1.68 + *  \sa SDL_RenderSetLogicalSize()
    1.69   */
    1.70  extern DECLSPEC int SDLCALL SDL_RenderSetScale(SDL_Renderer * renderer,
    1.71                                                 float scaleX, float scaleY);
    1.72 @@ -458,6 +500,8 @@
    1.73   *
    1.74   *  \param scaleX A pointer filled in with the horizontal scaling factor
    1.75   *  \param scaleY A pointer filled in with the vertical scaling factor
    1.76 + *
    1.77 + *  \sa SDL_RenderSetScale()
    1.78   */
    1.79  extern DECLSPEC void SDLCALL SDL_RenderGetScale(SDL_Renderer * renderer,
    1.80                                                 float *scaleX, float *scaleY);
     2.1 --- a/src/render/SDL_render.c	Mon Oct 01 21:57:09 2012 -0700
     2.2 +++ b/src/render/SDL_render.c	Mon Oct 01 22:30:07 2012 -0700
     2.3 @@ -70,6 +70,8 @@
     2.4  static char renderer_magic;
     2.5  static char texture_magic;
     2.6  
     2.7 +static int UpdateLogicalSize(SDL_Renderer *renderer);
     2.8 +
     2.9  int
    2.10  SDL_GetNumRenderDrivers(void)
    2.11  {
    2.12 @@ -101,21 +103,27 @@
    2.13              }
    2.14  
    2.15              if (event->window.event == SDL_WINDOWEVENT_RESIZED) {
    2.16 -                /* Try to keep the previous viewport centered */
    2.17 -                int w, h;
    2.18 +                if (renderer->logical_w) {
    2.19 +                    /* We'll update the renderer in the SIZE_CHANGED event */
    2.20 +                } else {
    2.21 +                    /* Try to keep the previous viewport centered */
    2.22 +                    int w, h;
    2.23  
    2.24 -                SDL_GetWindowSize(window, &w, &h);
    2.25 -                if (renderer->target) {
    2.26 -                    renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
    2.27 -                    renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
    2.28 -                } else {
    2.29 -                    renderer->viewport.x = (w - renderer->viewport.w) / 2;
    2.30 -                    renderer->viewport.y = (h - renderer->viewport.h) / 2;
    2.31 -                    renderer->UpdateViewport(renderer);
    2.32 +                    SDL_GetWindowSize(window, &w, &h);
    2.33 +                    if (renderer->target) {
    2.34 +                        renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
    2.35 +                        renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
    2.36 +                    } else {
    2.37 +                        renderer->viewport.x = (w - renderer->viewport.w) / 2;
    2.38 +                        renderer->viewport.y = (h - renderer->viewport.h) / 2;
    2.39 +                        renderer->UpdateViewport(renderer);
    2.40 +                    }
    2.41                  }
    2.42                  renderer->resized = SDL_TRUE;
    2.43              } else if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
    2.44 -                if (!renderer->resized) {
    2.45 +                if (renderer->logical_w) {
    2.46 +                    UpdateLogicalSize(renderer);
    2.47 +                } else if (!renderer->resized) {
    2.48                      /* Window was programmatically resized, reset viewport */
    2.49                      int w, h;
    2.50  
    2.51 @@ -148,6 +156,21 @@
    2.52                  }
    2.53              }
    2.54          }
    2.55 +    } else if (event->type == SDL_MOUSEMOTION) {
    2.56 +        if (renderer->logical_w) {
    2.57 +            event->motion.x -= renderer->viewport.x;
    2.58 +            event->motion.y -= renderer->viewport.y;
    2.59 +            event->motion.x = (int)(event->motion.x / renderer->scale.x);
    2.60 +            event->motion.y = (int)(event->motion.y / renderer->scale.y);
    2.61 +        }
    2.62 +    } else if (event->type == SDL_MOUSEBUTTONDOWN ||
    2.63 +               event->type == SDL_MOUSEBUTTONUP) {
    2.64 +        if (renderer->logical_w) {
    2.65 +            event->button.x -= renderer->viewport.x;
    2.66 +            event->button.y -= renderer->viewport.y;
    2.67 +            event->button.x = (int)(event->button.x / renderer->scale.x);
    2.68 +            event->button.y = (int)(event->button.y / renderer->scale.y);
    2.69 +        }
    2.70      }
    2.71      return 0;
    2.72  }
    2.73 @@ -245,6 +268,8 @@
    2.74          renderer->window = window;
    2.75          renderer->scale.x = 1.0f;
    2.76          renderer->scale.y = 1.0f;
    2.77 +        renderer->logical_w = 0;
    2.78 +        renderer->logical_h = 0;
    2.79  
    2.80          if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
    2.81              renderer->hidden = SDL_TRUE;
    2.82 @@ -921,6 +946,88 @@
    2.83      return 0;
    2.84  }
    2.85  
    2.86 +static int
    2.87 +UpdateLogicalSize(SDL_Renderer *renderer)
    2.88 +{
    2.89 +    int w, h;
    2.90 +    float want_aspect;
    2.91 +    float real_aspect;
    2.92 +    float scale;
    2.93 +    SDL_Rect viewport;
    2.94 +
    2.95 +    if (renderer->window) {
    2.96 +        SDL_GetWindowSize(renderer->window, &w, &h);
    2.97 +    } else {
    2.98 +        /* FIXME */
    2.99 +        SDL_SetError("Internal error: No way to get output resolution");
   2.100 +        return -1;
   2.101 +    }
   2.102 +
   2.103 +    want_aspect = (float)renderer->logical_w / renderer->logical_h;
   2.104 +    real_aspect = (float)w / h;
   2.105 +
   2.106 +    /* Clear the scale because we're setting viewport in output coordinates */
   2.107 +    SDL_RenderSetScale(renderer, 1.0f, 1.0f);
   2.108 +
   2.109 +    if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
   2.110 +        /* The aspect ratios are the same, just scale appropriately */
   2.111 +        scale = (float)w / renderer->logical_w;
   2.112 +        SDL_RenderSetViewport(renderer, NULL);
   2.113 +    } else if (want_aspect > real_aspect) {
   2.114 +        /* We want a wider aspect ratio than is available - letterbox it */
   2.115 +        scale = (float)w / renderer->logical_w;
   2.116 +        viewport.x = 0;
   2.117 +        viewport.w = w;
   2.118 +        viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
   2.119 +        viewport.y = (h - viewport.h) / 2;
   2.120 +        SDL_RenderSetViewport(renderer, &viewport);
   2.121 +    } else {
   2.122 +        /* We want a narrower aspect ratio than is available - use side-bars */
   2.123 +        scale = (float)h / renderer->logical_h;
   2.124 +        viewport.y = 0;
   2.125 +        viewport.h = h;
   2.126 +        viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
   2.127 +        viewport.x = (w - viewport.w) / 2;
   2.128 +        SDL_RenderSetViewport(renderer, &viewport);
   2.129 +    }
   2.130 +
   2.131 +    /* Set the new scale */
   2.132 +    SDL_RenderSetScale(renderer, scale, scale);
   2.133 +}
   2.134 +
   2.135 +int
   2.136 +SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
   2.137 +{
   2.138 +    CHECK_RENDERER_MAGIC(renderer, -1);
   2.139 +
   2.140 +    if (!w || !h) {
   2.141 +        /* Clear any previous logical resolution */
   2.142 +        renderer->logical_w = 0;
   2.143 +        renderer->logical_h = 0;
   2.144 +        SDL_RenderSetViewport(renderer, NULL);
   2.145 +        SDL_RenderSetScale(renderer, 1.0f, 1.0f);
   2.146 +        return 0;
   2.147 +    }
   2.148 +
   2.149 +    renderer->logical_w = w;
   2.150 +    renderer->logical_h = h;
   2.151 +
   2.152 +    return UpdateLogicalSize(renderer);
   2.153 +}
   2.154 +
   2.155 +void
   2.156 +SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
   2.157 +{
   2.158 +    CHECK_RENDERER_MAGIC(renderer, );
   2.159 +
   2.160 +    if (w) {
   2.161 +        *w = renderer->logical_w;
   2.162 +    }
   2.163 +    if (h) {
   2.164 +        *h = renderer->logical_h;
   2.165 +    }
   2.166 +}
   2.167 +
   2.168  int
   2.169  SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
   2.170  {
     3.1 --- a/src/render/SDL_sysrender.h	Mon Oct 01 21:57:09 2012 -0700
     3.2 +++ b/src/render/SDL_sysrender.h	Mon Oct 01 22:30:07 2012 -0700
     3.3 @@ -123,6 +123,10 @@
     3.4      SDL_bool hidden;
     3.5      SDL_bool resized;
     3.6  
     3.7 +    /* The logical resolution for rendering */
     3.8 +    int logical_w;
     3.9 +    int logical_h;
    3.10 +
    3.11      /* The drawable area within the window */
    3.12      SDL_Rect viewport;
    3.13      SDL_Rect viewport_backup;