From 0001b4695e370826d45395f55a25fa133b18d798 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 11 Apr 2017 22:32:40 -0300 Subject: [PATCH] Add new variants of love.graphics.clear for controlling how the depth and stencil buffers are cleared. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- CMakeLists.txt | 1 + .../xcode/liblove.xcodeproj/project.pbxproj | 2 + src/common/Optional.h | 52 ++++++++++ src/modules/graphics/Graphics.h | 15 ++- src/modules/graphics/Shader.h | 1 + src/modules/graphics/opengl/Canvas.cpp | 8 ++ src/modules/graphics/opengl/Graphics.cpp | 67 ++++++++++--- src/modules/graphics/opengl/Graphics.h | 6 +- src/modules/graphics/wrap_Graphics.cpp | 95 ++++++++++++++----- 9 files changed, 194 insertions(+), 53 deletions(-) create mode 100644 src/common/Optional.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aa7ffa4c6..e212fa074 100755 --- a/CMakeLists.txt +++ b/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 diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index f3dfd10dd..544206209 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/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 = ""; }; FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = ""; }; FAF1403C1E20934C00F898D2 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = ""; }; + FAF1889C1E9DA834008C1479 /* Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optional.h; sourceTree = ""; }; /* 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 */, diff --git a/src/common/Optional.h b/src/common/Optional.h new file mode 100644 index 000000000..aa40b3cd6 --- /dev/null +++ b/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 +struct Optional +{ + bool hasValue; + T value; + + Optional() + : hasValue(false) + , value(T()) + {} + + Optional(T val) + : hasValue(true) + , value(val) + {} + +private: + +}; + +typedef Optional OptionalBool; +typedef Optional OptionalFloat; +typedef Optional OptionalDouble; +typedef Optional OptionalInt; + +} // love diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 8f56ddb64..323393bb5 100644 --- a/src/modules/graphics/Graphics.h +++ b/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 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 &colors) = 0; + virtual void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) = 0; + virtual void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) = 0; virtual void discard(const std::vector &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. diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index de1446afe..f1703b34b 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -128,6 +128,7 @@ public: UniformType baseType; TextureType textureType; + bool isDepthTexture; std::string name; union diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 45ee645d3..5249dd193 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/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. diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ce4ab75a9..655a35f70 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/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 &colors) +void Graphics::clear(const std::vector &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 &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 &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 &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) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 3e19148e0..724f1beaf 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -88,8 +88,8 @@ public: void flushStreamDraws() override; - void clear(Colorf color) override; - void clear(const std::vector &colors) override; + void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override; + void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; void discard(const std::vector &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; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 36118985c..20877bd3b 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/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 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 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.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); + 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; } - luax_catchexcept(L, [&]() { instance()->clear(color); }); + if (startidx >= 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); + } + + 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(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); });