From c0998cd996434ff0824257569b9c8434cdd0514b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 7 Jun 2013 03:31:30 -0300 Subject: [PATCH] Fixed love.graphics.setScissor when love.graphics.setCanvas is called directly after a setScissor call --- src/modules/graphics/opengl/Canvas.cpp | 2 +- src/modules/graphics/opengl/Graphics.cpp | 21 ++++++------- src/modules/graphics/opengl/Graphics.h | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 38 ++++++++++++++++++++++ src/modules/graphics/opengl/OpenGL.h | 40 ++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 10865edcb..faf2369fd 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -455,7 +455,7 @@ void Canvas::setupGrab() // bind buffer and clear screen glPushAttrib(GL_VIEWPORT_BIT | GL_TRANSFORM_BIT); strategy->bindFBO(fbo); - glViewport(0, 0, width, height); + gl.setViewport(OpenGL::Viewport(0, 0, width, height)); // Reset the projection matrix glMatrixMode(GL_PROJECTION); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 74877bd57..52c91d9ce 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -96,7 +96,7 @@ DisplayState Graphics::saveState() s.scissor = (glIsEnabled(GL_SCISSOR_TEST) == GL_TRUE); //do we have scissor, if so, store the box if (s.scissor) - glGetIntegerv(GL_SCISSOR_BOX, s.scissorBox); + s.scissorBox = gl.getScissor(); for (int i = 0; i < 4; i++) s.colorMask[i] = colorMask[i]; @@ -116,7 +116,7 @@ void Graphics::restoreState(const DisplayState &s) else setAlphaTest(); if (s.scissor) - setScissor(s.scissorBox[0], s.scissorBox[1], s.scissorBox[2], s.scissorBox[3]); + setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h); else setScissor(); setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]); @@ -161,7 +161,7 @@ bool Graphics::setMode(int width, int height) gl.setActiveTextureUnit(0); // Set the viewport to top-left corner - glViewport(0, 0, width, height); + gl.setViewport(OpenGL::Viewport(0, 0, width, height)); // Reset the projection matrix glMatrixMode(GL_PROJECTION); @@ -266,8 +266,8 @@ bool Graphics::isCreated() const void Graphics::setScissor(int x, int y, int width, int height) { glEnable(GL_SCISSOR_TEST); - // Compensates for the fact that our y-coordinate is reverse of OpenGL's. - glScissor(x, getRenderHeight() - (y + height), width, height); + // OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor. + gl.setScissor(OpenGL::Viewport(x, y, width, height)); } void Graphics::setScissor() @@ -280,13 +280,12 @@ int Graphics::getScissor(lua_State *L) const if (glIsEnabled(GL_SCISSOR_TEST) == GL_FALSE) return 0; - GLint scissor[4]; - glGetIntegerv(GL_SCISSOR_BOX, scissor); + OpenGL::Viewport scissor = gl.getScissor(); - lua_pushnumber(L, scissor[0]); - lua_pushnumber(L, getRenderHeight() - (scissor[1] + scissor[3])); // Compensates for the fact that our y-coordinate is reverse of OpenGLs. - lua_pushnumber(L, scissor[2]); - lua_pushnumber(L, scissor[3]); + lua_pushinteger(L, scissor.x); + lua_pushinteger(L, scissor.y); + lua_pushinteger(L, scissor.w); + lua_pushinteger(L, scissor.h); return 4; } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index e5f4f96a4..523b65ffc 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -80,7 +80,7 @@ struct DisplayState // Scissor. bool scissor; - GLint scissorBox[4]; + OpenGL::Viewport scissorBox; // Color mask. bool colorMask[4]; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index fd604dda2..363e0c10c 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -64,6 +64,14 @@ void OpenGL::initContext() state.clearColor.b = glcolor[2] * 255; state.clearColor.a = glcolor[3] * 255; + // Get the current viewport. + glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport); + + // And the current scissor - but we need to compensate for GL scissors + // starting at the bottom left instead of top left. + glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor); + state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h); + // Initialize multiple texture unit support for shaders, if available. state.textureUnits.clear(); if (Shader::isSupported()) @@ -187,6 +195,36 @@ Color OpenGL::getClearColor() const return state.clearColor; } +void OpenGL::setViewport(const OpenGL::Viewport &v) +{ + glViewport(v.x, v.y, v.w, v.h); + state.viewport = v; + + // glScissor starts from the lower left, so we compensate when setting the + // scissor. When the viewport is changed, we need to manually update the + // scissor again. + if (v.h != state.viewport.h) + setScissor(state.scissor); +} + +OpenGL::Viewport OpenGL::getViewport() const +{ + return state.viewport; +} + +void OpenGL::setScissor(const OpenGL::Viewport &v) +{ + // We need to compensate for glScissor starting from the lower left of the + // viewport instead of the top left. + glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h); + state.scissor = v; +} + +OpenGL::Viewport OpenGL::getScissor() const +{ + return state.scissor; +} + void OpenGL::setActiveTextureUnit(int textureunit) { if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size()) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 7217ed48a..3fba36432 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -48,6 +48,21 @@ class OpenGL { public: + // A rectangle representing an OpenGL viewport or a scissor box. + struct Viewport + { + int x, y; + int w, h; + + Viewport() + : x(0), y(0), w(0), h(0) + {} + + Viewport(int _x, int _y, int _w, int _h) + : x(_x), y(_y), w(_w), h(_h) + {} + }; + OpenGL(); /** @@ -83,6 +98,28 @@ public: **/ Color getClearColor() const; + /** + * Sets the OpenGL rendering viewport to the specified rectangle. + * The y-coordinate starts at the top. + **/ + void setViewport(const Viewport &v); + + /** + * Gets the current OpenGL rendering viewport rectangle. + **/ + Viewport getViewport() const; + + /** + * Sets the scissor box to the specified rectangle. + * The y-coordinate starts at the top and is flipped internally. + **/ + void setScissor(const Viewport &v); + + /** + * Gets the current scissor box (regardless of whether scissoring is enabled.) + **/ + Viewport getScissor() const; + /** * Helper for setting the active texture unit. * @@ -153,6 +190,9 @@ private: // Currently active texture unit. int curTextureUnit; + Viewport viewport; + Viewport scissor; + } state; }; // OpenGL