From 5d8990ecb19370367a4d07dec959cdd68bcd4fc3 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 29 May 2013 03:07:55 -0700 Subject: [PATCH] Fixed bug 1622 - SDL_RenderSetViewport with empty SDL_Rect raises wrong error for OpenGL rendering backend It's now legal to set an empty viewport rect - it will prevent any rendering. Also added an API to query the output size: SDL_GetRendererOutputSize() --- include/SDL_render.h | 6 ++++ src/render/SDL_render.c | 40 ++++++++++++++----------- src/render/SDL_sysrender.h | 1 + src/render/direct3d/SDL_render_d3d.c | 36 +++++++++++----------- src/render/opengl/SDL_render_gl.c | 31 +++++++++---------- src/render/opengles/SDL_render_gles.c | 14 +++++---- src/render/opengles2/SDL_render_gles2.c | 4 +++ src/render/software/SDL_render_sw.c | 35 +++++++++++++++++----- 8 files changed, 103 insertions(+), 64 deletions(-) diff --git a/include/SDL_render.h b/include/SDL_render.h index aa92559a3..4e85cfcd7 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -211,6 +211,12 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window * window); extern DECLSPEC int SDLCALL SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info); +/** + * \brief Get the output size of a rendering context. + */ +extern DECLSPEC int SDLCALL SDL_GetRendererOutputSize(SDL_Renderer * renderer, + int *w, int *h); + /** * \brief Create a texture for a rendering context. * diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 785e0b905..fcab8c44f 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -337,6 +337,25 @@ SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) return 0; } +int +SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (renderer->target) { + return SDL_QueryTexture(renderer->target, NULL, NULL, w, h); + } else if (renderer->window) { + SDL_GetWindowSize(renderer->window, w, h); + return 0; + } else if (renderer->GetOutputSize) { + return renderer->GetOutputSize(renderer, w, h); + } else { + /* This should never happen */ + SDL_SetError("Renderer doesn't support querying output size"); + return -1; + } +} + static SDL_bool IsSupportedFormat(SDL_Renderer * renderer, Uint32 format) { @@ -985,13 +1004,8 @@ UpdateLogicalSize(SDL_Renderer *renderer) float scale; SDL_Rect viewport; - if (renderer->target) { - SDL_QueryTexture(renderer->target, NULL, NULL, &w, &h); - } else if (renderer->window) { - SDL_GetWindowSize(renderer->window, &w, &h); - } else { - /* FIXME */ - return SDL_SetError("Internal error: No way to get output resolution"); + if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { + return -1; } want_aspect = (float)renderer->logical_w / renderer->logical_h; @@ -1074,16 +1088,8 @@ SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) } else { renderer->viewport.x = 0; renderer->viewport.y = 0; - if (renderer->target) { - SDL_QueryTexture(renderer->target, NULL, NULL, - &renderer->viewport.w, &renderer->viewport.h); - } else if (renderer->window) { - SDL_GetWindowSize(renderer->window, - &renderer->viewport.w, &renderer->viewport.h); - } else { - /* This will be filled in by UpdateViewport() */ - renderer->viewport.w = 0; - renderer->viewport.h = 0; + if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) { + return -1; } } return renderer->UpdateViewport(renderer); diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 4f0795274..b01ac887c 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -78,6 +78,7 @@ struct SDL_Renderer const void *magic; void (*WindowEvent) (SDL_Renderer * renderer, const SDL_WindowEvent *event); + int (*GetOutputSize) (SDL_Renderer * renderer, int *w, int *h); int (*CreateTexture) (SDL_Renderer * renderer, SDL_Texture * texture); int (*SetTextureColorMod) (SDL_Renderer * renderer, SDL_Texture * texture); diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index dea31f644..1ab27ab7e 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -866,23 +866,25 @@ D3D_UpdateViewport(SDL_Renderer * renderer) IDirect3DDevice9_SetViewport(data->device, &viewport); /* Set an orthographic projection matrix */ - matrix.m[0][0] = 2.0f / renderer->viewport.w; - matrix.m[0][1] = 0.0f; - matrix.m[0][2] = 0.0f; - matrix.m[0][3] = 0.0f; - matrix.m[1][0] = 0.0f; - matrix.m[1][1] = -2.0f / renderer->viewport.h; - matrix.m[1][2] = 0.0f; - matrix.m[1][3] = 0.0f; - matrix.m[2][0] = 0.0f; - matrix.m[2][1] = 0.0f; - matrix.m[2][2] = 1.0f; - matrix.m[2][3] = 0.0f; - matrix.m[3][0] = -1.0f; - matrix.m[3][1] = 1.0f; - matrix.m[3][2] = 0.0f; - matrix.m[3][3] = 1.0f; - IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix); + if (renderer->viewport.w && renderer->viewport.h) { + matrix.m[0][0] = 2.0f / renderer->viewport.w; + matrix.m[0][1] = 0.0f; + matrix.m[0][2] = 0.0f; + matrix.m[0][3] = 0.0f; + matrix.m[1][0] = 0.0f; + matrix.m[1][1] = -2.0f / renderer->viewport.h; + matrix.m[1][2] = 0.0f; + matrix.m[1][3] = 0.0f; + matrix.m[2][0] = 0.0f; + matrix.m[2][1] = 0.0f; + matrix.m[2][2] = 1.0f; + matrix.m[2][3] = 0.0f; + matrix.m[3][0] = -1.0f; + matrix.m[3][1] = 1.0f; + matrix.m[3][2] = 0.0f; + matrix.m[3][3] = 1.0f; + IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix); + } return 0; } diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 6e37cf552..77248e421 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -849,28 +849,25 @@ GL_UpdateViewport(SDL_Renderer * renderer) return 0; } - if (!renderer->viewport.w || !renderer->viewport.h) { - /* The viewport isn't set up yet, ignore it */ - return -1; - } - data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h); data->glMatrixMode(GL_PROJECTION); data->glLoadIdentity(); - if (renderer->target) { - data->glOrtho((GLdouble) 0, - (GLdouble) renderer->viewport.w, - (GLdouble) 0, - (GLdouble) renderer->viewport.h, - 0.0, 1.0); - } else { - data->glOrtho((GLdouble) 0, - (GLdouble) renderer->viewport.w, - (GLdouble) renderer->viewport.h, - (GLdouble) 0, - 0.0, 1.0); + if (renderer->viewport.w && renderer->viewport.h) { + if (renderer->target) { + data->glOrtho((GLdouble) 0, + (GLdouble) renderer->viewport.w, + (GLdouble) 0, + (GLdouble) renderer->viewport.h, + 0.0, 1.0); + } else { + data->glOrtho((GLdouble) 0, + (GLdouble) renderer->viewport.w, + (GLdouble) renderer->viewport.h, + (GLdouble) 0, + 0.0, 1.0); + } } return GL_CheckError("", renderer); } diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index bd3eedfea..920b35fb0 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -623,12 +623,14 @@ GLES_UpdateViewport(SDL_Renderer * renderer) data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h); - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glOrthof((GLfloat) 0, - (GLfloat) renderer->viewport.w, - (GLfloat) renderer->viewport.h, - (GLfloat) 0, 0.0, 1.0); + if (renderer->viewport.w && renderer->viewport.h) { + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glOrthof((GLfloat) 0, + (GLfloat) renderer->viewport.w, + (GLfloat) renderer->viewport.h, + (GLfloat) 0, 0.0, 1.0); + } return 0; } diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index 3933100d6..f52afc15a 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -906,6 +906,10 @@ GLES2_SetOrthographicProjection(SDL_Renderer *renderer) GLfloat projection[4][4]; GLuint locProjection; + if (!renderer->viewport.w || !renderer->viewport.h) { + return 0; + } + /* Prepare an orthographic projection */ projection[0][0] = 2.0f / renderer->viewport.w; projection[0][1] = 0.0f; diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index 8c84da143..b7f2b1798 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -39,6 +39,7 @@ static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags); static void SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event); +static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h); static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture); @@ -110,9 +111,14 @@ SW_ActivateRenderer(SDL_Renderer * renderer) data->surface = data->window; } if (!data->surface) { - data->surface = data->window = SDL_GetWindowSurface(renderer->window); + SDL_Surface *surface = SDL_GetWindowSurface(renderer->window); + if (surface) { + data->surface = data->window = surface; + renderer->viewport.w = surface->w; + renderer->viewport.h = surface->h; - SW_UpdateViewport(renderer); + SW_UpdateViewport(renderer); + } } return data->surface; } @@ -143,6 +149,7 @@ SW_CreateRendererForSurface(SDL_Surface * surface) data->surface = surface; renderer->WindowEvent = SW_WindowEvent; + renderer->GetOutputSize = SW_GetOutputSize; renderer->CreateTexture = SW_CreateTexture; renderer->SetTextureColorMod = SW_SetTextureColorMod; renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; @@ -194,6 +201,25 @@ SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } +static int +SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + + if (surface) { + if (w) { + *w = surface->w; + } + if (h) { + *h = surface->h; + } + return 0; + } else { + SDL_SetError("Software renderer doesn't have an output surface"); + return -1; + } +} + static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { @@ -313,11 +339,6 @@ SW_UpdateViewport(SDL_Renderer * renderer) return 0; } - if (!renderer->viewport.w && !renderer->viewport.h) { - /* There may be no window, so update the viewport directly */ - renderer->viewport.w = surface->w; - renderer->viewport.h = surface->h; - } SDL_SetClipRect(data->surface, &renderer->viewport); return 0; }