Browse Source

Add new variants of love.graphics.clear for controlling how the depth and stencil buffers are cleared.

- Add love.graphics.clear(r, g, b, a [, stencilvalue, depthvalue]).
- Add love.graphics.clear(color1, color2, …, [, stencilvalue, depthvalue]).
- Add love.graphics.clear(false, stencilvalue, depthvalue).

stencilvalue and depthvalue are either true, false, or a number. True is the default behaviour and clears that buffer to the default value (0 for stencil, 1 for depth), false prevents clearing.

The third variant listed above only clears the depth and/or stencil buffers and not the color buffer.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
0001b4695e

+ 1 - 0
CMakeLists.txt

@@ -275,6 +275,7 @@ set(LOVE_SRC_COMMON
 	src/common/Module.h
 	src/common/Object.cpp
 	src/common/Object.h
+	src/common/Optional.h
 	src/common/pixelformat.cpp
 	src/common/pixelformat.h
 	src/common/Reference.cpp

+ 2 - 0
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -1936,6 +1936,7 @@
 		FAF140291E20934C00F898D2 /* ShaderLang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShaderLang.h; sourceTree = "<group>"; };
 		FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
 		FAF1403C1E20934C00F898D2 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = "<group>"; };
+		FAF1889C1E9DA834008C1479 /* Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optional.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -2054,6 +2055,7 @@
 				FA0B79071A958E3B000E1D17 /* Module.h */,
 				FA0B79081A958E3B000E1D17 /* Object.cpp */,
 				FA0B79091A958E3B000E1D17 /* Object.h */,
+				FAF1889C1E9DA834008C1479 /* Optional.h */,
 				FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */,
 				FA9D8DD01DEB56C3002CD881 /* pixelformat.h */,
 				FA0B790C1A958E3B000E1D17 /* Reference.cpp */,

+ 52 - 0
src/common/Optional.h

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2006-2017 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+namespace love
+{
+
+// Currently only meant for simple types.
+template <typename T>
+struct Optional
+{
+	bool hasValue;
+	T value;
+
+	Optional()
+		: hasValue(false)
+		, value(T())
+	{}
+
+	Optional(T val)
+		: hasValue(true)
+		, value(val)
+	{}
+
+private:
+
+};
+
+typedef Optional<bool> OptionalBool;
+typedef Optional<float> OptionalFloat;
+typedef Optional<double> OptionalDouble;
+typedef Optional<int> OptionalInt;
+
+} // love

+ 6 - 9
src/modules/graphics/Graphics.h

@@ -26,6 +26,7 @@
 #include "common/Module.h"
 #include "common/StringMap.h"
 #include "common/Vector.h"
+#include "common/Optional.h"
 #include "StreamBuffer.h"
 #include "vertex.h"
 #include "Color.h"
@@ -58,6 +59,8 @@ class Text;
 class Video;
 class Buffer;
 
+typedef Optional<Colorf> OptionalColorf;
+
 const int MAX_COLOR_RENDER_TARGETS = 8;
 
 /**
@@ -253,12 +256,6 @@ public:
 		}
 	};
 
-	struct OptionalColorf
-	{
-		Colorf c;
-		bool enabled;
-	};
-
 	struct StreamDrawRequest
 	{
 		vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES;
@@ -397,8 +394,8 @@ public:
 	 **/
 	void reset();
 
-	virtual void clear(Colorf color) = 0;
-	virtual void clear(const std::vector<OptionalColorf> &colors) = 0;
+	virtual void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) = 0;
+	virtual void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) = 0;
 
 	virtual void discard(const std::vector<bool> &colorbuffers, bool depthstencil) = 0;
 
@@ -525,7 +522,7 @@ public:
 	/**
 	 * Clear the stencil buffer in the active Canvas(es.)
 	 **/
-	virtual void clearStencil() = 0;
+	virtual void clearStencil(int value) = 0;
 
 	/**
 	 * Sets the enabled color components when rendering.

+ 1 - 0
src/modules/graphics/Shader.h

@@ -128,6 +128,7 @@ public:
 
 		UniformType baseType;
 		TextureType textureType;
+		bool isDepthTexture;
 		std::string name;
 
 		union

+ 8 - 0
src/modules/graphics/opengl/Canvas.cpp

@@ -60,7 +60,11 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
 					gl.framebufferTexture(attachment, texType, texture, 0, layer, face);
 
 					if (isPixelFormatDepthStencil(format))
+					{
+						glClearDepth(1.0);
+						glClearStencil(0);
 						glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+					}
 					else
 					{
 						glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -116,7 +120,11 @@ static bool createRenderbuffer(int width, int height, int &samples, PixelFormat
 	if (status == GL_FRAMEBUFFER_COMPLETE && (reqsamples <= 1 || samples > 1))
 	{
 		if (isPixelFormatDepthStencil(pixelformat))
+		{
+			glClearDepth(1.0);
+			glClearStencil(0);
 			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		}
 		else
 		{
 			// Initialize the buffer to transparent black.

+ 52 - 15
src/modules/graphics/opengl/Graphics.cpp

@@ -703,15 +703,36 @@ void Graphics::endPass()
 	}
 }
 
-void Graphics::clear(Colorf c)
+void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
 {
-	flushStreamDraws();
+	if (c.hasValue || stencil.hasValue || depth.hasValue)
+		flushStreamDraws();
 
-	gammaCorrectColor(c);
-	glClearColor(c.r, c.g, c.b, c.a);
-	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	GLbitfield flags = 0;
 
-	if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
+	if (c.hasValue)
+	{
+		gammaCorrectColor(c.value);
+		glClearColor(c.value.r, c.value.g, c.value.b, c.value.a);
+		flags |= GL_COLOR_BUFFER_BIT;
+	}
+
+	if (stencil.hasValue)
+	{
+		glClearStencil(stencil.value);
+		flags |= GL_STENCIL_BUFFER_BIT;
+	}
+
+	if (depth.hasValue)
+	{
+		glClearDepth(depth.value);
+		flags |= GL_DEPTH_BUFFER_BIT;
+	}
+
+	if (flags != 0)
+		glClear(flags);
+
+	if (flags != 0 && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
 	{
 		// This seems to be enough to fix the bug for me. Other methods I've
 		// tried (e.g. dummy draws) don't work in all cases.
@@ -720,9 +741,9 @@ void Graphics::clear(Colorf c)
 	}
 }
 
-void Graphics::clear(const std::vector<OptionalColorf> &colors)
+void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth)
 {
-	if (colors.size() == 0)
+	if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
 		return;
 
 	int ncanvases = (int) states.back().renderTargets.colors.size();
@@ -730,8 +751,8 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
 
 	if (ncolors <= 1 && ncanvases <= 1)
 	{
-		if (colors[0].enabled)
-			clear(colors[0].c);
+		if (colors[0].hasValue)
+			clear(colors[0].value, stencil, depth);
 
 		return;
 	}
@@ -742,10 +763,10 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
 
 	for (int i = 0; i < ncolors; i++)
 	{
-		if (!colors[i].enabled)
+		if (!colors[i].hasValue)
 			continue;
 
-		Colorf c = colors[i].c;
+		Colorf c = colors[i].value;
 		gammaCorrectColor(c);
 
 		if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
@@ -775,7 +796,22 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
 		glDrawBuffers(ncanvases, bufs);
 	}
 
-	glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	GLbitfield flags = 0;
+
+	if (stencil.hasValue)
+	{
+		glClearStencil(stencil.value);
+		flags |= GL_STENCIL_BUFFER_BIT;
+	}
+
+	if (depth.hasValue)
+	{
+		glClearDepth(depth.value);
+		flags |= GL_DEPTH_BUFFER_BIT;
+	}
+
+	if (flags != 0)
+		glClear(flags);
 
 	if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current)
 	{
@@ -1250,9 +1286,10 @@ void Graphics::setStencilTest()
 	setStencilTest(COMPARE_ALWAYS, 0);
 }
 
-void Graphics::clearStencil()
+void Graphics::clearStencil(int value)
 {
-	glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glClearStencil(value);
+	glClear(GL_STENCIL_BUFFER_BIT);
 }
 
 void Graphics::setColor(Colorf c)

+ 3 - 3
src/modules/graphics/opengl/Graphics.h

@@ -88,8 +88,8 @@ public:
 
 	void flushStreamDraws() override;
 
-	void clear(Colorf color) override;
-	void clear(const std::vector<OptionalColorf> &colors) override;
+	void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
+	void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
 
 	void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
 
@@ -109,7 +109,7 @@ public:
 	void setStencilTest(CompareMode compare, int value) override;
 	void setStencilTest() override;
 
-	void clearStencil() override;
+	void clearStencil(int value) override;
 
 	void setColorMask(ColorMask mask) override;
 

+ 69 - 26
src/modules/graphics/wrap_Graphics.cpp

@@ -65,46 +65,84 @@ int w_reset(lua_State *)
 
 int w_clear(lua_State *L)
 {
-	Colorf color;
+	OptionalColorf color(Colorf(0.0f, 0.0f, 0.0f, 0.0f));
+	std::vector<OptionalColorf> colors;
 
-	if (lua_isnoneornil(L, 1))
-		color.set(0.0, 0.0, 0.0, 0.0);
-	else if (lua_istable(L, 1))
+	OptionalInt stencil(0);
+	OptionalDouble depth(1.0);
+
+	int argtype = lua_type(L, 1);
+	int startidx = -1;
+
+	if (argtype == LUA_TTABLE)
 	{
-		std::vector<Graphics::OptionalColorf> colors((size_t) lua_gettop(L));
+		int maxn = lua_gettop(L);
+		colors.reserve(maxn);
 
-		for (int i = 0; i < lua_gettop(L); i++)
+		for (int i = 0; i < maxn; i++)
 		{
-			if (lua_isnoneornil(L, i + 1) || luax_objlen(L, i + 1) == 0)
+			argtype = lua_type(L, i + 1);
+
+			if (argtype == LUA_TNUMBER || argtype == LUA_TBOOLEAN)
 			{
-				colors[i].enabled = false;
+				startidx = i + 1;
+				break;
+			}
+			else if (argtype == LUA_TNIL || argtype == LUA_TNONE || luax_objlen(L, i + 1) == 0)
+			{
+				colors.push_back(OptionalColorf());
 				continue;
 			}
 
 			for (int j = 1; j <= 4; j++)
 				lua_rawgeti(L, i + 1, j);
 
-			colors[i].enabled = true;
-			colors[i].c.r = (float) luaL_checknumber(L, -4);
-			colors[i].c.g = (float) luaL_checknumber(L, -3);
-			colors[i].c.b = (float) luaL_checknumber(L, -2);
-			colors[i].c.a = (float) luaL_optnumber(L, -1, 1.0);
+			OptionalColorf c;
+			c.hasValue = true;
+			c.value.r = (float) luaL_checknumber(L, -4);
+			c.value.g = (float) luaL_checknumber(L, -3);
+			c.value.b = (float) luaL_checknumber(L, -2);
+			c.value.a = (float) luaL_optnumber(L, -1, 1.0);
+			colors.push_back(c);
 
 			lua_pop(L, 4);
 		}
-
-		luax_catchexcept(L, [&]() { instance()->clear(colors); });
-		return 0;
 	}
-	else
+	else if (argtype == LUA_TBOOLEAN)
+	{
+		color.hasValue = luax_toboolean(L, 1);
+		startidx = 2;
+	}
+	else if (argtype != LUA_TNONE && argtype != LUA_TNIL)
+	{
+		color.hasValue = true;
+		color.value.r = (float) luaL_checknumber(L, 1);
+		color.value.g = (float) luaL_checknumber(L, 2);
+		color.value.b = (float) luaL_checknumber(L, 3);
+		color.value.a = (float) luaL_optnumber(L, 4, 1.0);
+		startidx = 5;
+	}
+
+	if (startidx >= 0)
 	{
-		color.r = (float) luaL_checknumber(L, 1);
-		color.g = (float) luaL_checknumber(L, 2);
-		color.b = (float) luaL_checknumber(L, 3);
-		color.a = (float) luaL_optnumber(L, 4, 1.0);
+		argtype = lua_type(L, startidx);
+		if (argtype == LUA_TBOOLEAN)
+			stencil.hasValue = luax_toboolean(L, startidx);
+		else if (argtype == LUA_TNUMBER)
+			stencil.value = (int) luaL_checkinteger(L, startidx);
+
+		argtype = lua_type(L, startidx + 1);
+		if (argtype == LUA_TBOOLEAN)
+			depth.hasValue = luax_toboolean(L, startidx + 1);
+		else if (argtype == LUA_TNUMBER)
+			depth.value = luaL_checknumber(L, startidx + 1);
 	}
 
-	luax_catchexcept(L, [&]() { instance()->clear(color); });
+	if (colors.empty())
+		luax_catchexcept(L, [&]() { instance()->clear(color, stencil, depth); });
+	else
+		luax_catchexcept(L, [&]() { instance()->clear(colors, stencil, depth); });
+
 	return 0;
 }
 
@@ -128,8 +166,8 @@ int w_discard(lua_State *L)
 		colorbuffers = std::vector<bool>(numbuffers, discardcolor);
 	}
 
-	bool stencil = luax_optboolean(L, 2, true);
-	instance()->discard(colorbuffers, stencil);
+	bool depthstencil = luax_optboolean(L, 2, true);
+	instance()->discard(colorbuffers, depthstencil);
 	return 0;
 }
 
@@ -463,8 +501,13 @@ int w_stencil(lua_State *L)
 	int stencilvalue = (int) luaL_optnumber(L, 3, 1);
 
 	// Fourth argument: whether to keep the contents of the stencil buffer.
-	if (lua_toboolean(L, 4) == 0)
-		instance()->clearStencil();
+	int argtype = lua_type(L, 4);
+	if (argtype == LUA_TNONE || argtype == LUA_TNIL || (argtype == LUA_TBOOLEAN && luax_toboolean(L, 4) == false))
+		instance()->clearStencil(0);
+	else if (argtype == LUA_TNUMBER)
+		instance()->clearStencil((int) luaL_checkinteger(L, 4));
+	else if (argtype != LUA_TBOOLEAN)
+		luaL_checktype(L, 4, LUA_TBOOLEAN);
 
 	luax_catchexcept(L, [&](){ instance()->drawToStencilBuffer(action, stencilvalue); });