Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Added SDL_RenderSetLogicalSize() and SDL_RenderGetLogicalSize()
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Oct 2, 2012
1 parent 7fd393b commit 700b1ba
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 11 deletions.
44 changes: 44 additions & 0 deletions include/SDL_render.h
Expand Up @@ -417,6 +417,40 @@ extern DECLSPEC SDL_bool SDLCALL SDL_RenderTargetSupported(SDL_Renderer *rendere
extern DECLSPEC int SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer,
SDL_Texture *texture);

/**
* \brief Set device independent resolution for rendering
*
* \param w The width of the logical resolution
* \param h The height of the logical resolution
*
* This function uses the viewport and scaling functionality to allow a fixed logical
* resolution for rendering, regardless of the actual output resolution. If the actual
* output resolution doesn't have the same aspect ratio the output rendering will be
* centered within the output display.
*
* If the output display is a window, mouse events in the window will be filtered
* and scaled so they seem to arrive within the logical resolution.
*
* \note If this function results in scaling or subpixel drawing by the
* rendering backend, it will be handled using the appropriate
* quality hints.
*
* \sa SDL_RenderGetLogicalSize()
* \sa SDL_RenderSetScale()
* \sa SDL_RenderSetViewport()
*/
extern DECLSPEC int SDLCALL SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h);

/**
* \brief Get device independent resolution for rendering
*
* \param w A pointer filled with the width of the logical resolution
* \param h A pointer filled with the height of the logical resolution
*
* \sa SDL_RenderSetLogicalSize()
*/
extern DECLSPEC void SDLCALL SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *y);

/**
* \brief Set the drawing area for rendering on the current target.
*
Expand All @@ -426,12 +460,17 @@ extern DECLSPEC int SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer,
*
* \note When the window is resized, the current viewport is automatically
* centered within the new window size.
*
* \sa SDL_RenderGetViewport()
* \sa SDL_RenderSetLogicalSize()
*/
extern DECLSPEC int SDLCALL SDL_RenderSetViewport(SDL_Renderer * renderer,
const SDL_Rect * rect);

/**
* \brief Get the drawing area for the current target.
*
* \sa SDL_RenderSetViewport()
*/
extern DECLSPEC void SDLCALL SDL_RenderGetViewport(SDL_Renderer * renderer,
SDL_Rect * rect);
Expand All @@ -449,6 +488,9 @@ extern DECLSPEC void SDLCALL SDL_RenderGetViewport(SDL_Renderer * renderer,
* \note If this results in scaling or subpixel drawing by the
* rendering backend, it will be handled using the appropriate
* quality hints. For best results use integer scaling factors.
*
* \sa SDL_RenderGetScale()
* \sa SDL_RenderSetLogicalSize()
*/
extern DECLSPEC int SDLCALL SDL_RenderSetScale(SDL_Renderer * renderer,
float scaleX, float scaleY);
Expand All @@ -458,6 +500,8 @@ extern DECLSPEC int SDLCALL SDL_RenderSetScale(SDL_Renderer * renderer,
*
* \param scaleX A pointer filled in with the horizontal scaling factor
* \param scaleY A pointer filled in with the vertical scaling factor
*
* \sa SDL_RenderSetScale()
*/
extern DECLSPEC void SDLCALL SDL_RenderGetScale(SDL_Renderer * renderer,
float *scaleX, float *scaleY);
Expand Down
129 changes: 118 additions & 11 deletions src/render/SDL_render.c
Expand Up @@ -70,6 +70,8 @@ static const SDL_RenderDriver *render_drivers[] = {
static char renderer_magic;
static char texture_magic;

static int UpdateLogicalSize(SDL_Renderer *renderer);

int
SDL_GetNumRenderDrivers(void)
{
Expand Down Expand Up @@ -101,21 +103,27 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
}

if (event->window.event == SDL_WINDOWEVENT_RESIZED) {
/* Try to keep the previous viewport centered */
int w, h;

SDL_GetWindowSize(window, &w, &h);
if (renderer->target) {
renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
if (renderer->logical_w) {
/* We'll update the renderer in the SIZE_CHANGED event */
} else {
renderer->viewport.x = (w - renderer->viewport.w) / 2;
renderer->viewport.y = (h - renderer->viewport.h) / 2;
renderer->UpdateViewport(renderer);
/* Try to keep the previous viewport centered */
int w, h;

SDL_GetWindowSize(window, &w, &h);
if (renderer->target) {
renderer->viewport_backup.x = (w - renderer->viewport_backup.w) / 2;
renderer->viewport_backup.y = (h - renderer->viewport_backup.h) / 2;
} else {
renderer->viewport.x = (w - renderer->viewport.w) / 2;
renderer->viewport.y = (h - renderer->viewport.h) / 2;
renderer->UpdateViewport(renderer);
}
}
renderer->resized = SDL_TRUE;
} else if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
if (!renderer->resized) {
if (renderer->logical_w) {
UpdateLogicalSize(renderer);
} else if (!renderer->resized) {
/* Window was programmatically resized, reset viewport */
int w, h;

Expand Down Expand Up @@ -148,6 +156,21 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
}
}
}
} else if (event->type == SDL_MOUSEMOTION) {
if (renderer->logical_w) {
event->motion.x -= renderer->viewport.x;
event->motion.y -= renderer->viewport.y;
event->motion.x = (int)(event->motion.x / renderer->scale.x);
event->motion.y = (int)(event->motion.y / renderer->scale.y);
}
} else if (event->type == SDL_MOUSEBUTTONDOWN ||
event->type == SDL_MOUSEBUTTONUP) {
if (renderer->logical_w) {
event->button.x -= renderer->viewport.x;
event->button.y -= renderer->viewport.y;
event->button.x = (int)(event->button.x / renderer->scale.x);
event->button.y = (int)(event->button.y / renderer->scale.y);
}
}
return 0;
}
Expand Down Expand Up @@ -245,6 +268,8 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
renderer->window = window;
renderer->scale.x = 1.0f;
renderer->scale.y = 1.0f;
renderer->logical_w = 0;
renderer->logical_h = 0;

if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
renderer->hidden = SDL_TRUE;
Expand Down Expand Up @@ -921,6 +946,88 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
return 0;
}

static int
UpdateLogicalSize(SDL_Renderer *renderer)
{
int w, h;
float want_aspect;
float real_aspect;
float scale;
SDL_Rect viewport;

if (renderer->window) {
SDL_GetWindowSize(renderer->window, &w, &h);
} else {
/* FIXME */
SDL_SetError("Internal error: No way to get output resolution");
return -1;
}

want_aspect = (float)renderer->logical_w / renderer->logical_h;
real_aspect = (float)w / h;

/* Clear the scale because we're setting viewport in output coordinates */
SDL_RenderSetScale(renderer, 1.0f, 1.0f);

if (SDL_fabs(want_aspect-real_aspect) < 0.0001) {
/* The aspect ratios are the same, just scale appropriately */
scale = (float)w / renderer->logical_w;
SDL_RenderSetViewport(renderer, NULL);
} else if (want_aspect > real_aspect) {
/* We want a wider aspect ratio than is available - letterbox it */
scale = (float)w / renderer->logical_w;
viewport.x = 0;
viewport.w = w;
viewport.h = (int)SDL_ceil(renderer->logical_h * scale);
viewport.y = (h - viewport.h) / 2;
SDL_RenderSetViewport(renderer, &viewport);
} else {
/* We want a narrower aspect ratio than is available - use side-bars */
scale = (float)h / renderer->logical_h;
viewport.y = 0;
viewport.h = h;
viewport.w = (int)SDL_ceil(renderer->logical_w * scale);
viewport.x = (w - viewport.w) / 2;
SDL_RenderSetViewport(renderer, &viewport);
}

/* Set the new scale */
SDL_RenderSetScale(renderer, scale, scale);
}

int
SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h)
{
CHECK_RENDERER_MAGIC(renderer, -1);

if (!w || !h) {
/* Clear any previous logical resolution */
renderer->logical_w = 0;
renderer->logical_h = 0;
SDL_RenderSetViewport(renderer, NULL);
SDL_RenderSetScale(renderer, 1.0f, 1.0f);
return 0;
}

renderer->logical_w = w;
renderer->logical_h = h;

return UpdateLogicalSize(renderer);
}

void
SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h)
{
CHECK_RENDERER_MAGIC(renderer, );

if (w) {
*w = renderer->logical_w;
}
if (h) {
*h = renderer->logical_h;
}
}

int
SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
{
Expand Down
4 changes: 4 additions & 0 deletions src/render/SDL_sysrender.h
Expand Up @@ -123,6 +123,10 @@ struct SDL_Renderer
SDL_bool hidden;
SDL_bool resized;

/* The logical resolution for rendering */
int logical_w;
int logical_h;

/* The drawable area within the window */
SDL_Rect viewport;
SDL_Rect viewport_backup;
Expand Down

0 comments on commit 700b1ba

Please sign in to comment.