Browse Source

Fixed love.graphics.setScissor when love.graphics.setCanvas is called directly after a setScissor call

Alex Szpakowski 12 years ago
parent
commit
c0998cd996

+ 1 - 1
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);

+ 10 - 11
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;
 }

+ 1 - 1
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];

+ 38 - 0
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())

+ 40 - 0
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