Browse Source

Consolidate some internal graphics state definitions into a new renderstate file.

--HG--
branch : minor
Alex Szpakowski 5 years ago
parent
commit
efa2bd7837

+ 2 - 2
CMakeLists.txt

@@ -520,8 +520,6 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 	src/modules/graphics/Buffer.h
 	src/modules/graphics/Canvas.cpp
 	src/modules/graphics/Canvas.h
-	src/modules/graphics/depthstencil.cpp
-	src/modules/graphics/depthstencil.h
 	src/modules/graphics/Deprecations.cpp
 	src/modules/graphics/Deprecations.h
 	src/modules/graphics/Drawable.cpp
@@ -540,6 +538,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 	src/modules/graphics/Polyline.h
 	src/modules/graphics/Quad.cpp
 	src/modules/graphics/Quad.h
+	src/modules/graphics/renderstate.cpp
+	src/modules/graphics/renderstate.h
 	src/modules/graphics/Resource.h
 	src/modules/graphics/Shader.cpp
 	src/modules/graphics/Shader.h

+ 10 - 8
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -975,6 +975,9 @@
 		FAB2D5AA1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB2D5A81AABDD8A008224A4 /* TrueTypeRasterizer.cpp */; };
 		FAB2D5AB1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB2D5A81AABDD8A008224A4 /* TrueTypeRasterizer.cpp */; };
 		FAB2D5AC1AABDD8A008224A4 /* TrueTypeRasterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB2D5A91AABDD8A008224A4 /* TrueTypeRasterizer.h */; };
+		FAC271E523B5B5B400C200D3 /* renderstate.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC271E323B5B5B400C200D3 /* renderstate.h */; };
+		FAC271E623B5B5B400C200D3 /* renderstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC271E423B5B5B400C200D3 /* renderstate.cpp */; };
+		FAC271E723B5B5B400C200D3 /* renderstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC271E423B5B5B400C200D3 /* renderstate.cpp */; };
 		FAC756F51E4F99B400B91289 /* Effect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC756F31E4F99B400B91289 /* Effect.cpp */; };
 		FAC756F61E4F99B400B91289 /* Effect.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC756F41E4F99B400B91289 /* Effect.h */; };
 		FAC756F71E4F99BC00B91289 /* Effect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC756F31E4F99B400B91289 /* Effect.cpp */; };
@@ -1204,8 +1207,6 @@
 		FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
 		FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
 		FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF1403C1E20934C00F898D2 /* InitializeDll.h */; };
-		FAF1889F1E9DBC4B008C1479 /* depthstencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */; };
-		FAF188A01E9DBC4B008C1479 /* depthstencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -1904,6 +1905,8 @@
 		FAB17BF41ABFC4B100F9BA27 /* lz4hc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lz4hc.h; sourceTree = "<group>"; };
 		FAB2D5A81AABDD8A008224A4 /* TrueTypeRasterizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrueTypeRasterizer.cpp; sourceTree = "<group>"; };
 		FAB2D5A91AABDD8A008224A4 /* TrueTypeRasterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrueTypeRasterizer.h; sourceTree = "<group>"; };
+		FAC271E323B5B5B400C200D3 /* renderstate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderstate.h; sourceTree = "<group>"; };
+		FAC271E423B5B5B400C200D3 /* renderstate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = renderstate.cpp; sourceTree = "<group>"; };
 		FAC734C11B2E021A00AB460A /* wrap_SoundData.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_SoundData.lua; sourceTree = "<group>"; };
 		FAC734C21B2E628700AB460A /* wrap_ImageData.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_ImageData.lua; sourceTree = "<group>"; };
 		FAC756F31E4F99B400B91289 /* Effect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Effect.cpp; sourceTree = "<group>"; };
@@ -2057,8 +2060,6 @@
 		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>"; };
-		FAF1889D1E9DBBC8008C1479 /* depthstencil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = depthstencil.h; sourceTree = "<group>"; };
-		FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = depthstencil.cpp; sourceTree = "<group>"; };
 		FAF949FD21DEE8B7001CD27E /* wrap_Event.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_Event.lua; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -2781,8 +2782,6 @@
 				FA1BA0A61E16F20600AA2803 /* Canvas.h */,
 				FA9D53AA1F5307E900125C6B /* Deprecations.cpp */,
 				FA9D53AB1F5307E900125C6B /* Deprecations.h */,
-				FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */,
-				FAF1889D1E9DBBC8008C1479 /* depthstencil.h */,
 				FA9D8DDC1DEF842A002CD881 /* Drawable.cpp */,
 				FA0B7B891A95902C000E1D17 /* Drawable.h */,
 				FA1BA09B1E16CFCE00AA2803 /* Font.cpp */,
@@ -2800,6 +2799,8 @@
 				FA0B7B9C1A95902C000E1D17 /* Polyline.h */,
 				FA0B7BBC1A95902C000E1D17 /* Quad.cpp */,
 				FA0B7BBD1A95902C000E1D17 /* Quad.h */,
+				FAC271E423B5B5B400C200D3 /* renderstate.cpp */,
+				FAC271E323B5B5B400C200D3 /* renderstate.h */,
 				FA10DD7B1F9EC24E00E1FE3D /* Resource.h */,
 				FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */,
 				FA1BA0B01E16FD0800AA2803 /* Shader.h */,
@@ -3724,6 +3725,7 @@
 				FA0B7CCF1A95902C000E1D17 /* Audio.h in Headers */,
 				FA0B7EC01A95902C000E1D17 /* Thread.h in Headers */,
 				FA0B7E9C1A95902C000E1D17 /* VorbisDecoder.h in Headers */,
+				FAC271E523B5B5B400C200D3 /* renderstate.h in Headers */,
 				FAC756FB1E4F99D200B91289 /* Effect.h in Headers */,
 				FAC7CD901FE35E95006A60C7 /* physfs_miniz.h in Headers */,
 				FA0B791D1A958E3B000E1D17 /* b64.h in Headers */,
@@ -4300,6 +4302,7 @@
 				FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */,
 				FADF53FE1E3D74F200012CC0 /* Text.cpp in Sources */,
 				FA0B7D191A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */,
+				FAC271E723B5B5B400C200D3 /* renderstate.cpp in Sources */,
 				FA0B7CFB1A95902C000E1D17 /* Filesystem.cpp in Sources */,
 				FA0B7D3D1A95902C000E1D17 /* Image.cpp in Sources */,
 				FA0B7B351A958EA3000E1D17 /* wuff_convert.c in Sources */,
@@ -4402,7 +4405,6 @@
 				FA0B7A2A1A958EA3000E1D17 /* b2BroadPhase.cpp in Sources */,
 				FA0A3A6123366CE9001C269E /* floattypes.cpp in Sources */,
 				FA0B7A811A958EA3000E1D17 /* b2EdgeAndCircleContact.cpp in Sources */,
-				FAF188A01E9DBC4B008C1479 /* depthstencil.cpp in Sources */,
 				FA0B7D071A95902C000E1D17 /* wrap_File.cpp in Sources */,
 				FA6A2B751F60B6710074C308 /* ByteData.cpp in Sources */,
 				FAD19A181DFF8CA200D5398A /* ImageDataBase.cpp in Sources */,
@@ -4623,6 +4625,7 @@
 				FA0B7ECB1A95902C000E1D17 /* wrap_Channel.cpp in Sources */,
 				FACA02F21F5E396B0084B28F /* HashFunction.cpp in Sources */,
 				FAF140A71E20934C00F898D2 /* ShaderLang.cpp in Sources */,
+				FAC271E623B5B5B400C200D3 /* renderstate.cpp in Sources */,
 				FA1BA09D1E16CFCE00AA2803 /* Font.cpp in Sources */,
 				FA0B7E6C1A95902C000E1D17 /* wrap_RevoluteJoint.cpp in Sources */,
 				FA0B7A5E1A958EA3000E1D17 /* b2Body.cpp in Sources */,
@@ -4797,7 +4800,6 @@
 				FA0B7DDC1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */,
 				FA0B7A951A958EA3000E1D17 /* b2Joint.cpp in Sources */,
 				FA0B7D061A95902C000E1D17 /* wrap_File.cpp in Sources */,
-				FAF1889F1E9DBC4B008C1479 /* depthstencil.cpp in Sources */,
 				FAC7CD871FE35E95006A60C7 /* physfs_archiver_vdf.c in Sources */,
 				FA0B7A4E1A958EA3000E1D17 /* b2Draw.cpp in Sources */,
 				FAD19A171DFF8CA200D5398A /* ImageDataBase.cpp in Sources */,

+ 9 - 8
src/common/pixelformat.cpp

@@ -32,21 +32,22 @@ static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] =
 	{ "hdr",     PIXELFORMAT_HDR     },
 
 	{ "r8",      PIXELFORMAT_R8_UNORM     },
+	{ "r16",     PIXELFORMAT_R16_UNORM    },
+	{ "r16f",    PIXELFORMAT_R16_FLOAT    },
+	{ "r32f",    PIXELFORMAT_R32_FLOAT    },
+
 	{ "rg8",     PIXELFORMAT_RG8_UNORM    },
+	{ "la8",     PIXELFORMAT_LA8_UNORM    },
+	{ "rg16",    PIXELFORMAT_RG16_UNORM   },
+	{ "rg16f",   PIXELFORMAT_RG16_FLOAT   },
+	{ "rg32f",   PIXELFORMAT_RG32_FLOAT   },
+
 	{ "rgba8",   PIXELFORMAT_RGBA8_UNORM  },
 	{ "srgba8",  PIXELFORMAT_sRGBA8_UNORM },
-	{ "r16",     PIXELFORMAT_R16_UNORM    },
-	{ "rg16",    PIXELFORMAT_RG16_UNORM   },
 	{ "rgba16",  PIXELFORMAT_RGBA16_UNORM },
-	{ "r16f",    PIXELFORMAT_R16_FLOAT    },
-	{ "rg16f",   PIXELFORMAT_RG16_FLOAT   },
 	{ "rgba16f", PIXELFORMAT_RGBA16_FLOAT },
-	{ "r32f",    PIXELFORMAT_R32_FLOAT    },
-	{ "rg32f",   PIXELFORMAT_RG32_FLOAT   },
 	{ "rgba32f", PIXELFORMAT_RGBA32_FLOAT },
 
-	{ "la8",     PIXELFORMAT_LA8_UNORM    },
-
 	{ "rgba4",    PIXELFORMAT_RGBA4_UNORM    },
 	{ "rgb5a1",   PIXELFORMAT_RGB5A1_UNORM   },
 	{ "rgb565",   PIXELFORMAT_RGB565_UNORM   },

+ 13 - 10
src/common/pixelformat.h

@@ -33,29 +33,32 @@ enum PixelFormat
 	PIXELFORMAT_NORMAL,
 	PIXELFORMAT_HDR,
 
-	// "regular" formats
+	// 1-channel normal formats
 	PIXELFORMAT_R8_UNORM,
+	PIXELFORMAT_R16_UNORM,
+	PIXELFORMAT_R16_FLOAT,
+	PIXELFORMAT_R32_FLOAT,
+
+	// 2-channel normal formats
 	PIXELFORMAT_RG8_UNORM,
+	PIXELFORMAT_LA8_UNORM, // Same as RG8, but accessed as (L, L, L, A)
+	PIXELFORMAT_RG16_UNORM,
+	PIXELFORMAT_RG16_FLOAT,
+	PIXELFORMAT_RG32_FLOAT,
+
+	// 4-channel normal formats
 	PIXELFORMAT_RGBA8_UNORM,
 	PIXELFORMAT_sRGBA8_UNORM,
-	PIXELFORMAT_R16_UNORM,
-	PIXELFORMAT_RG16_UNORM,
 	PIXELFORMAT_RGBA16_UNORM,
-	PIXELFORMAT_R16_FLOAT,
-	PIXELFORMAT_RG16_FLOAT,
 	PIXELFORMAT_RGBA16_FLOAT,
-	PIXELFORMAT_R32_FLOAT,
-	PIXELFORMAT_RG32_FLOAT,
 	PIXELFORMAT_RGBA32_FLOAT,
 
-	PIXELFORMAT_LA8_UNORM, // Same as RG8, but accessed as (L, L, L, A)
-
 	// packed formats
 	PIXELFORMAT_RGBA4_UNORM,    // LSB->MSB: [a, b, g, r]
 	PIXELFORMAT_RGB5A1_UNORM,   // LSB->MSB: [a, b, g, r]
 	PIXELFORMAT_RGB565_UNORM,   // LSB->MSB: [b, g, r]
 	PIXELFORMAT_RGB10A2_UNORM,  // LSB->MSB: [r, g, b, a]
-	PIXELFORMAT_RG11B10_FLOAT, // LSB->MSB: [r, g, b]
+	PIXELFORMAT_RG11B10_FLOAT,  // LSB->MSB: [r, g, b]
 
 	// depth/stencil formats
 	PIXELFORMAT_STENCIL8,

+ 2 - 55
src/modules/graphics/Graphics.cpp

@@ -896,12 +896,12 @@ vertex::Winding Graphics::getFrontFaceWinding() const
 	return states.back().winding;
 }
 
-Graphics::ColorMask Graphics::getColorMask() const
+ColorChannelMask Graphics::getColorMask() const
 {
 	return states.back().colorMask;
 }
 
-Graphics::BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
+BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
 {
 	alphamode = states.back().blendAlphaMode;
 	return states.back().blendMode;
@@ -1778,36 +1778,6 @@ std::vector<std::string> Graphics::getConstants(ArcMode)
 	return arcModes.getNames();
 }
 
-bool Graphics::getConstant(const char *in, BlendMode &out)
-{
-	return blendModes.find(in, out);
-}
-
-bool Graphics::getConstant(BlendMode in, const char *&out)
-{
-	return blendModes.find(in, out);
-}
-
-std::vector<std::string> Graphics::getConstants(BlendMode)
-{
-	return blendModes.getNames();
-}
-
-bool Graphics::getConstant(const char *in, BlendAlpha &out)
-{
-	return blendAlphaModes.find(in, out);
-}
-
-bool Graphics::getConstant(BlendAlpha in, const char *&out)
-{
-	return blendAlphaModes.find(in, out);
-}
-
-std::vector<std::string> Graphics::getConstants(BlendAlpha)
-{
-	return blendAlphaModes.getNames();
-}
-
 bool Graphics::getConstant(const char *in, LineStyle &out)
 {
 	return lineStyles.find(in, out);
@@ -1890,29 +1860,6 @@ StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM>::Entry Graphics::arcModeEnt
 
 StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM> Graphics::arcModes(Graphics::arcModeEntries, sizeof(Graphics::arcModeEntries));
 
-StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM>::Entry Graphics::blendModeEntries[] =
-{
-	{ "alpha",    BLEND_ALPHA    },
-	{ "add",      BLEND_ADD      },
-	{ "subtract", BLEND_SUBTRACT },
-	{ "multiply", BLEND_MULTIPLY },
-	{ "lighten",  BLEND_LIGHTEN  },
-	{ "darken",   BLEND_DARKEN   },
-	{ "screen",   BLEND_SCREEN   },
-	{ "replace",  BLEND_REPLACE  },
-	{ "none",     BLEND_NONE     },
-};
-
-StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM> Graphics::blendModes(Graphics::blendModeEntries, sizeof(Graphics::blendModeEntries));
-
-StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM>::Entry Graphics::blendAlphaEntries[] =
-{
-	{ "alphamultiply", BLENDALPHA_MULTIPLY      },
-	{ "premultiplied", BLENDALPHA_PREMULTIPLIED },
-};
-
-StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM> Graphics::blendAlphaModes(Graphics::blendAlphaEntries, sizeof(Graphics::blendAlphaEntries));
-
 StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM>::Entry Graphics::lineStyleEntries[] =
 {
 	{ "smooth", LINE_SMOOTH },

+ 4 - 62
src/modules/graphics/Graphics.h

@@ -40,7 +40,7 @@
 #include "Mesh.h"
 #include "Image.h"
 #include "Deprecations.h"
-#include "depthstencil.h"
+#include "renderstate.h"
 #include "math/Transform.h"
 #include "font/Rasterizer.h"
 #include "font/Font.h"
@@ -118,27 +118,6 @@ public:
 		ARC_MAX_ENUM
 	};
 
-	enum BlendMode
-	{
-		BLEND_ALPHA,
-		BLEND_ADD,
-		BLEND_SUBTRACT,
-		BLEND_MULTIPLY,
-		BLEND_LIGHTEN,
-		BLEND_DARKEN,
-		BLEND_SCREEN,
-		BLEND_REPLACE,
-		BLEND_NONE,
-		BLEND_MAX_ENUM
-	};
-
-	enum BlendAlpha
-	{
-		BLENDALPHA_MULTIPLY,
-		BLENDALPHA_PREMULTIPLIED,
-		BLENDALPHA_MAX_ENUM
-	};
-
 	enum LineStyle
 	{
 		LINE_ROUGH,
@@ -228,29 +207,6 @@ public:
 		int64 textureMemory;
 	};
 
-	struct ColorMask
-	{
-		bool r, g, b, a;
-
-		ColorMask()
-			: r(true), g(true), b(true), a(true)
-		{}
-
-		ColorMask(bool _r, bool _g, bool _b, bool _a)
-			: r(_r), g(_g), b(_b), a(_a)
-		{}
-
-		bool operator == (const ColorMask &m) const
-		{
-			return r == m.r && g == m.g && b == m.b && a == m.a;
-		}
-
-		bool operator != (const ColorMask &m) const
-		{
-			return !(operator == (m));
-		}
-	};
-
 	struct DrawCommand
 	{
 		PrimitiveType primitiveType = PRIMITIVE_TRIANGLES;
@@ -643,12 +599,12 @@ public:
 	/**
 	 * Sets the enabled color components when rendering.
 	 **/
-	virtual void setColorMask(ColorMask mask) = 0;
+	virtual void setColorMask(ColorChannelMask mask) = 0;
 
 	/**
 	 * Gets the current color mask.
 	 **/
-	ColorMask getColorMask() const;
+	ColorChannelMask getColorMask() const;
 
 	/**
 	 * Sets the current blend mode.
@@ -902,14 +858,6 @@ public:
 	static bool getConstant(ArcMode in, const char *&out);
 	static std::vector<std::string> getConstants(ArcMode);
 
-	static bool getConstant(const char *in, BlendMode &out);
-	static bool getConstant(BlendMode in, const char *&out);
-	static std::vector<std::string> getConstants(BlendMode);
-
-	static bool getConstant(const char *in, BlendAlpha &out);
-	static bool getConstant(BlendAlpha in, const char *&out);
-	static std::vector<std::string> getConstants(BlendAlpha);
-
 	static bool getConstant(const char *in, LineStyle &out);
 	static bool getConstant(LineStyle in, const char *&out);
 	static std::vector<std::string> getConstants(LineStyle);
@@ -964,7 +912,7 @@ protected:
 
 		RenderTargetsStrongRef renderTargets;
 
-		ColorMask colorMask = ColorMask(true, true, true, true);
+		ColorChannelMask colorMask;
 
 		bool wireframe = false;
 
@@ -1082,12 +1030,6 @@ private:
 	static StringMap<ArcMode, ARC_MAX_ENUM>::Entry arcModeEntries[];
 	static StringMap<ArcMode, ARC_MAX_ENUM> arcModes;
 
-	static StringMap<BlendMode, BLEND_MAX_ENUM>::Entry blendModeEntries[];
-	static StringMap<BlendMode, BLEND_MAX_ENUM> blendModes;
-
-	static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM>::Entry blendAlphaEntries[];
-	static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM> blendAlphaModes;
-
 	static StringMap<LineStyle, LINE_MAX_ENUM>::Entry lineStyleEntries[];
 	static StringMap<LineStyle, LINE_MAX_ENUM> lineStyles;
 

+ 1 - 1
src/modules/graphics/Texture.h

@@ -31,7 +31,7 @@
 #include "Drawable.h"
 #include "Quad.h"
 #include "vertex.h"
-#include "depthstencil.h"
+#include "renderstate.h"
 #include "Resource.h"
 
 // C

+ 0 - 103
src/modules/graphics/depthstencil.cpp

@@ -1,103 +0,0 @@
-/**
- * Copyright (c) 2006-2019 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.
- **/
-
-#include "depthstencil.h"
-#include "common/StringMap.h"
-
-namespace love
-{
-namespace graphics
-{
-
-CompareMode getReversedCompareMode(CompareMode mode)
-{
-	switch (mode)
-	{
-	case COMPARE_LESS:
-		return COMPARE_GREATER;
-	case COMPARE_LEQUAL:
-		return COMPARE_GEQUAL;
-	case COMPARE_GEQUAL:
-		return COMPARE_LEQUAL;
-	case COMPARE_GREATER:
-		return COMPARE_LESS;
-	default:
-		return mode;
-	}
-}
-
-static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[] =
-{
-	{ "replace",       STENCIL_REPLACE        },
-	{ "increment",     STENCIL_INCREMENT      },
-	{ "decrement",     STENCIL_DECREMENT      },
-	{ "incrementwrap", STENCIL_INCREMENT_WRAP },
-	{ "decrementwrap", STENCIL_DECREMENT_WRAP },
-	{ "invert",        STENCIL_INVERT         },
-};
-
-static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions(stencilActionEntries, sizeof(stencilActionEntries));
-
-static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
-{
-	{ "less",     COMPARE_LESS     },
-	{ "lequal",   COMPARE_LEQUAL   },
-	{ "equal",    COMPARE_EQUAL    },
-	{ "gequal",   COMPARE_GEQUAL   },
-	{ "greater",  COMPARE_GREATER  },
-	{ "notequal", COMPARE_NOTEQUAL },
-	{ "always",   COMPARE_ALWAYS   },
-	{ "never",    COMPARE_NEVER    },
-};
-
-static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes(compareModeEntries, sizeof(compareModeEntries));
-
-bool getConstant(const char *in, StencilAction &out)
-{
-	return stencilActions.find(in, out);
-}
-
-bool getConstant(StencilAction in, const char *&out)
-{
-	return stencilActions.find(in, out);
-}
-
-std::vector<std::string> getConstants(StencilAction)
-{
-	return stencilActions.getNames();
-}
-
-bool getConstant(const char *in, CompareMode &out)
-{
-	return compareModes.find(in, out);
-}
-
-bool getConstant(CompareMode in, const char *&out)
-{
-	return compareModes.find(in, out);
-}
-
-std::vector<std::string> getConstants(CompareMode)
-{
-	return compareModes.getNames();
-}
-
-} // graphics
-} // love

+ 0 - 74
src/modules/graphics/depthstencil.h

@@ -1,74 +0,0 @@
-/**
- * Copyright (c) 2006-2019 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
-
-#include <vector>
-#include <string>
-
-namespace love
-{
-namespace graphics
-{
-
-enum StencilAction
-{
-	STENCIL_REPLACE,
-	STENCIL_INCREMENT,
-	STENCIL_DECREMENT,
-	STENCIL_INCREMENT_WRAP,
-	STENCIL_DECREMENT_WRAP,
-	STENCIL_INVERT,
-	STENCIL_MAX_ENUM
-};
-
-enum CompareMode
-{
-	COMPARE_LESS,
-	COMPARE_LEQUAL,
-	COMPARE_EQUAL,
-	COMPARE_GEQUAL,
-	COMPARE_GREATER,
-	COMPARE_NOTEQUAL,
-	COMPARE_ALWAYS,
-	COMPARE_NEVER,
-	COMPARE_MAX_ENUM
-};
-
-/**
- * GPU APIs do the comparison in the opposite way of what makes sense for some
- * of love's APIs. For example in OpenGL if the compare function is GL_GREATER,
- * then the stencil test will pass if the reference value is greater than the
- * value in the stencil buffer. With our stencil API it's more intuitive to
- * assume that setStencilTest(COMPARE_GREATER, 4) will make it pass if the
- * stencil buffer has a value greater than 4.
- **/
-CompareMode getReversedCompareMode(CompareMode mode);
-
-bool getConstant(const char *in, StencilAction &out);
-bool getConstant(StencilAction in, const char *&out);
-std::vector<std::string> getConstants(StencilAction);
-
-bool getConstant(const char *in, CompareMode &out);
-bool getConstant(CompareMode in, const char *&out);
-std::vector<std::string> getConstants(CompareMode);
-
-} // graphics
-} // love

+ 1 - 1
src/modules/graphics/opengl/Canvas.cpp

@@ -407,7 +407,7 @@ void Canvas::setDepthSampleMode(Optional<CompareMode> mode)
 		gl.bindTextureToUnit(texType, texture, 0, false);
 		GLenum gltextype = OpenGL::getGLTextureType(texType);
 
-		// See the comment in depthstencil.h
+		// See the comment in renderstate.h
 		GLenum glmode = OpenGL::getGLCompareMode(getReversedCompareMode(mode.value));
 
 		glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);

+ 44 - 47
src/modules/graphics/opengl/Graphics.cpp

@@ -54,6 +54,40 @@ namespace graphics
 namespace opengl
 {
 
+static GLenum getGLBlendOperation(BlendOperation op)
+{
+	switch (op)
+	{
+		case BLENDOP_ADD: return GL_FUNC_ADD;
+		case BLENDOP_SUBTRACT: return GL_FUNC_SUBTRACT;
+		case BLENDOP_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
+		case BLENDOP_MIN: return GL_MIN;
+		case BLENDOP_MAX: return GL_MAX;
+		case BLENDOP_MAX_ENUM: return 0;
+	}
+	return 0;
+}
+
+static GLenum getGLBlendFactor(BlendFactor factor)
+{
+	switch (factor)
+	{
+		case BLENDFACTOR_ZERO: return GL_ZERO;
+		case BLENDFACTOR_ONE: return GL_ONE;
+		case BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR;
+		case BLENDFACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
+		case BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA;
+		case BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
+		case BLENDFACTOR_DST_COLOR: return GL_DST_COLOR;
+		case BLENDFACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
+		case BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA;
+		case BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
+		case BLENDFACTOR_SRC_ALPHA_SATURATED: return GL_SRC_ALPHA_SATURATE;
+		case BLENDFACTOR_MAX_ENUM: return 0;
+	}
+	return 0;
+}
+
 Graphics::Graphics()
 	: windowHasStencil(false)
 	, mainVAO(0)
@@ -1226,7 +1260,7 @@ void Graphics::setColor(Colorf c)
 	states.back().color = c;
 }
 
-void Graphics::setColorMask(ColorMask mask)
+void Graphics::setColorMask(ColorChannelMask mask)
 {
 	flushStreamDraws();
 
@@ -1253,7 +1287,7 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
 		case BLEND_LIGHTEN:
 		case BLEND_DARKEN:
 		case BLEND_MULTIPLY:
-			getConstant(mode, modestr);
+			love::graphics::getConstant(mode, modestr);
 			throw love::Exception("The '%s' blend mode must be used with premultiplied alpha.", modestr);
 			break;
 		default:
@@ -1261,52 +1295,15 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
 		}
 	}
 
-	GLenum func   = GL_FUNC_ADD;
-	GLenum srcRGB = GL_ONE;
-	GLenum srcA   = GL_ONE;
-	GLenum dstRGB = GL_ZERO;
-	GLenum dstA   = GL_ZERO;
-
-	switch (mode)
-	{
-	case BLEND_ALPHA:
-		srcRGB = srcA = GL_ONE;
-		dstRGB = dstA = GL_ONE_MINUS_SRC_ALPHA;
-		break;
-	case BLEND_MULTIPLY:
-		srcRGB = srcA = GL_DST_COLOR;
-		dstRGB = dstA = GL_ZERO;
-		break;
-	case BLEND_SUBTRACT:
-		func = GL_FUNC_REVERSE_SUBTRACT;
-	case BLEND_ADD:
-		srcRGB = GL_ONE;
-		srcA = GL_ZERO;
-		dstRGB = dstA = GL_ONE;
-		break;
-	case BLEND_LIGHTEN:
-		func = GL_MAX;
-		break;
-	case BLEND_DARKEN:
-		func = GL_MIN;
-		break;
-	case BLEND_SCREEN:
-		srcRGB = srcA = GL_ONE;
-		dstRGB = dstA = GL_ONE_MINUS_SRC_COLOR;
-		break;
-	case BLEND_REPLACE:
-	case BLEND_NONE:
-	default:
-		srcRGB = srcA = GL_ONE;
-		dstRGB = dstA = GL_ZERO;
-		break;
-	}
-
-	// We can only do alpha-multiplication when srcRGB would have been unmodified.
-	if (srcRGB == GL_ONE && alphamode == BLENDALPHA_MULTIPLY && mode != BLEND_NONE)
-		srcRGB = GL_SRC_ALPHA;
+	BlendState state = getBlendState(mode, alphamode);
+	GLenum opRGB  = getGLBlendOperation(state.operationRGB);
+	GLenum opA    = getGLBlendOperation(state.operationA);
+	GLenum srcRGB = getGLBlendFactor(state.srcFactorRGB);
+	GLenum srcA   = getGLBlendFactor(state.srcFactorA);
+	GLenum dstRGB = getGLBlendFactor(state.dstFactorRGB);
+	GLenum dstA   = getGLBlendFactor(state.dstFactorA);
 
-	glBlendEquation(func);
+	glBlendEquationSeparate(opRGB, opA);
 	glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA);
 
 	states.back().blendMode = mode;

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

@@ -96,7 +96,7 @@ public:
 
 	void setFrontFaceWinding(vertex::Winding winding) override;
 
-	void setColorMask(ColorMask mask) override;
+	void setColorMask(ColorChannelMask mask) override;
 
 	void setBlendMode(BlendMode mode, BlendAlpha alphamode) override;
 

+ 1 - 1
src/modules/graphics/opengl/OpenGL.h

@@ -28,7 +28,7 @@
 #include "common/Color.h"
 #include "graphics/Texture.h"
 #include "graphics/vertex.h"
-#include "graphics/depthstencil.h"
+#include "graphics/renderstate.h"
 #include "common/Matrix.h"
 
 // GLAD

+ 261 - 0
src/modules/graphics/renderstate.cpp

@@ -0,0 +1,261 @@
+/**
+ * Copyright (c) 2006-2019 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.
+ **/
+
+#include "renderstate.h"
+#include "common/StringMap.h"
+
+namespace love
+{
+namespace graphics
+{
+
+BlendState getBlendState(BlendMode mode, BlendAlpha alphamode)
+{
+	BlendState s;
+
+	s.enable = mode != BLEND_NONE;
+	s.operationRGB = BLENDOP_ADD;
+	s.operationA = BLENDOP_ADD;
+
+	switch (mode)
+	{
+	case BLEND_ALPHA:
+		s.srcFactorRGB = s.srcFactorA = BLENDFACTOR_ONE;
+		s.dstFactorRGB = s.dstFactorA = BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
+		break;
+	case BLEND_MULTIPLY:
+		s.srcFactorRGB = s.srcFactorA = BLENDFACTOR_DST_COLOR;
+		s.dstFactorRGB = s.dstFactorA = BLENDFACTOR_ZERO;
+		break;
+	case BLEND_SUBTRACT:
+		s.operationRGB = s.operationA = BLENDOP_REVERSE_SUBTRACT;
+	case BLEND_ADD:
+		s.srcFactorRGB = BLENDFACTOR_ONE;
+		s.srcFactorA = BLENDFACTOR_ZERO;
+		s.dstFactorRGB = s.dstFactorA = BLENDFACTOR_ONE;
+		break;
+	case BLEND_LIGHTEN:
+		s.operationRGB = s.operationA = BLENDOP_MAX;
+		break;
+	case BLEND_DARKEN:
+		s.operationRGB = s.operationA = BLENDOP_MIN;
+		break;
+	case BLEND_SCREEN:
+		s.srcFactorRGB = s.srcFactorA = BLENDFACTOR_ONE;
+		s.dstFactorRGB = s.dstFactorA = BLENDFACTOR_ONE_MINUS_SRC_COLOR;
+		break;
+	case BLEND_REPLACE:
+	case BLEND_NONE:
+	default:
+		s.srcFactorRGB = s.srcFactorA = BLENDFACTOR_ONE;
+		s.dstFactorRGB = s.dstFactorA = BLENDFACTOR_ZERO;
+		break;
+	}
+
+	// We can only do alpha-multiplication when srcRGB would have been unmodified.
+	if (s.srcFactorRGB == BLENDFACTOR_ONE && alphamode == BLENDALPHA_MULTIPLY && mode != BLEND_NONE)
+		s.srcFactorRGB = BLENDFACTOR_SRC_ALPHA;
+
+	return s;
+}
+
+CompareMode getReversedCompareMode(CompareMode mode)
+{
+	switch (mode)
+	{
+		case COMPARE_LESS: return COMPARE_GREATER;
+		case COMPARE_LEQUAL: return COMPARE_GEQUAL;
+		case COMPARE_GEQUAL: return COMPARE_LEQUAL;
+		case COMPARE_GREATER: return COMPARE_LESS;
+		default: return mode;
+	}
+}
+
+static StringMap<BlendMode, BLEND_MAX_ENUM>::Entry blendModeEntries[] =
+{
+	{ "alpha",    BLEND_ALPHA    },
+	{ "add",      BLEND_ADD      },
+	{ "subtract", BLEND_SUBTRACT },
+	{ "multiply", BLEND_MULTIPLY },
+	{ "lighten",  BLEND_LIGHTEN  },
+	{ "darken",   BLEND_DARKEN   },
+	{ "screen",   BLEND_SCREEN   },
+	{ "replace",  BLEND_REPLACE  },
+	{ "none",     BLEND_NONE     },
+};
+
+static StringMap<BlendMode, BLEND_MAX_ENUM> blendModes(blendModeEntries, sizeof(blendModeEntries));
+
+static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM>::Entry blendAlphaEntries[] =
+{
+	{ "alphamultiply", BLENDALPHA_MULTIPLY      },
+	{ "premultiplied", BLENDALPHA_PREMULTIPLIED },
+};
+
+static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM> blendAlphaModes(blendAlphaEntries, sizeof(blendAlphaEntries));
+
+static StringMap<BlendFactor, BLENDFACTOR_MAX_ENUM>::Entry blendFactorEntries[] =
+{
+	{ "zero",              BLENDFACTOR_ZERO                 },
+	{ "one",               BLENDFACTOR_ONE                  },
+	{ "srccolor",          BLENDFACTOR_SRC_COLOR            },
+	{ "oneminussrccolor",  BLENDFACTOR_ONE_MINUS_SRC_COLOR  },
+	{ "srcalpha",          BLENDFACTOR_SRC_ALPHA            },
+	{ "oneminussrcalpha",  BLENDFACTOR_ONE_MINUS_SRC_ALPHA  },
+	{ "dstcolor",          BLENDFACTOR_DST_COLOR            },
+	{ "oneminusdstcolor",  BLENDFACTOR_ONE_MINUS_DST_COLOR  },
+	{ "dstalpha",          BLENDFACTOR_DST_ALPHA            },
+	{ "oneminusdstalpha",  BLENDFACTOR_ONE_MINUS_DST_ALPHA  },
+	{ "srcalphasaturated", BLENDFACTOR_SRC_ALPHA_SATURATED  },
+};
+
+static StringMap<BlendFactor, BLENDFACTOR_MAX_ENUM> blendFactors(blendFactorEntries, sizeof(blendFactorEntries));
+
+static StringMap<BlendOperation, BLENDOP_MAX_ENUM>::Entry blendOperationEntries[] =
+{
+	{ "add",             BLENDOP_ADD              },
+	{ "subtract",        BLENDOP_SUBTRACT         },
+	{ "reversesubtract", BLENDOP_REVERSE_SUBTRACT },
+	{ "min",             BLENDOP_MIN              },
+	{ "max",             BLENDOP_MAX              },
+};
+
+static StringMap<BlendOperation, BLENDOP_MAX_ENUM> blendOperations(blendOperationEntries, sizeof(blendOperationEntries));
+
+static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[] =
+{
+	{ "keep",          STENCIL_KEEP           },
+	{ "zero",          STENCIL_ZERO           },
+	{ "replace",       STENCIL_REPLACE        },
+	{ "increment",     STENCIL_INCREMENT      },
+	{ "decrement",     STENCIL_DECREMENT      },
+	{ "incrementwrap", STENCIL_INCREMENT_WRAP },
+	{ "decrementwrap", STENCIL_DECREMENT_WRAP },
+	{ "invert",        STENCIL_INVERT         },
+};
+
+static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions(stencilActionEntries, sizeof(stencilActionEntries));
+
+static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
+{
+	{ "less",     COMPARE_LESS     },
+	{ "lequal",   COMPARE_LEQUAL   },
+	{ "equal",    COMPARE_EQUAL    },
+	{ "gequal",   COMPARE_GEQUAL   },
+	{ "greater",  COMPARE_GREATER  },
+	{ "notequal", COMPARE_NOTEQUAL },
+	{ "always",   COMPARE_ALWAYS   },
+	{ "never",    COMPARE_NEVER    },
+};
+
+static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes(compareModeEntries, sizeof(compareModeEntries));
+
+bool getConstant(const char *in, BlendMode &out)
+{
+	return blendModes.find(in, out);
+}
+
+bool getConstant(BlendMode in, const char *&out)
+{
+	return blendModes.find(in, out);
+}
+
+std::vector<std::string> getConstants(BlendMode)
+{
+	return blendModes.getNames();
+}
+
+bool getConstant(const char *in, BlendAlpha &out)
+{
+	return blendAlphaModes.find(in, out);
+}
+
+bool getConstant(BlendAlpha in, const char *&out)
+{
+	return blendAlphaModes.find(in, out);
+}
+
+std::vector<std::string> getConstants(BlendAlpha)
+{
+	return blendAlphaModes.getNames();
+}
+
+bool getConstant(const char *in, BlendFactor &out)
+{
+	return blendFactors.find(in, out);
+}
+
+bool getConstant(BlendFactor in, const char *&out)
+{
+	return blendFactors.find(in, out);
+}
+
+std::vector<std::string> getConstants(BlendFactor)
+{
+	return blendFactors.getNames();
+}
+
+bool getConstant(const char *in, BlendOperation &out)
+{
+	return blendOperations.find(in, out);
+}
+
+bool getConstant(BlendOperation in, const char *&out)
+{
+	return blendOperations.find(in, out);
+}
+
+std::vector<std::string> getConstants(BlendOperation)
+{
+	return blendOperations.getNames();
+}
+
+bool getConstant(const char *in, StencilAction &out)
+{
+	return stencilActions.find(in, out);
+}
+
+bool getConstant(StencilAction in, const char *&out)
+{
+	return stencilActions.find(in, out);
+}
+
+std::vector<std::string> getConstants(StencilAction)
+{
+	return stencilActions.getNames();
+}
+
+bool getConstant(const char *in, CompareMode &out)
+{
+	return compareModes.find(in, out);
+}
+
+bool getConstant(CompareMode in, const char *&out)
+{
+	return compareModes.find(in, out);
+}
+
+std::vector<std::string> getConstants(CompareMode)
+{
+	return compareModes.getNames();
+}
+
+} // graphics
+} // love

+ 216 - 0
src/modules/graphics/renderstate.h

@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2006-2019 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
+
+#include "common/int.h"
+#include "common/math.h"
+#include "vertex.h"
+
+#include <vector>
+#include <string>
+
+namespace love
+{
+namespace graphics
+{
+
+class Shader;
+
+enum BlendMode // High level wrappers
+{
+	BLEND_ALPHA,
+	BLEND_ADD,
+	BLEND_SUBTRACT,
+	BLEND_MULTIPLY,
+	BLEND_LIGHTEN,
+	BLEND_DARKEN,
+	BLEND_SCREEN,
+	BLEND_REPLACE,
+	BLEND_NONE,
+	BLEND_MAX_ENUM
+};
+
+enum BlendAlpha // High level wrappers
+{
+	BLENDALPHA_MULTIPLY,
+	BLENDALPHA_PREMULTIPLIED,
+	BLENDALPHA_MAX_ENUM
+};
+
+enum BlendFactor
+{
+	BLENDFACTOR_ZERO,
+	BLENDFACTOR_ONE,
+	BLENDFACTOR_SRC_COLOR,
+	BLENDFACTOR_ONE_MINUS_SRC_COLOR,
+	BLENDFACTOR_SRC_ALPHA,
+	BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
+	BLENDFACTOR_DST_COLOR,
+	BLENDFACTOR_ONE_MINUS_DST_COLOR,
+	BLENDFACTOR_DST_ALPHA,
+	BLENDFACTOR_ONE_MINUS_DST_ALPHA,
+	BLENDFACTOR_SRC_ALPHA_SATURATED,
+	BLENDFACTOR_MAX_ENUM
+};
+
+enum BlendOperation
+{
+	BLENDOP_ADD,
+	BLENDOP_SUBTRACT,
+	BLENDOP_REVERSE_SUBTRACT,
+	BLENDOP_MIN,
+	BLENDOP_MAX,
+	BLENDOP_MAX_ENUM
+};
+
+enum StencilAction
+{
+	STENCIL_KEEP,
+	STENCIL_ZERO,
+	STENCIL_REPLACE,
+	STENCIL_INCREMENT,
+	STENCIL_DECREMENT,
+	STENCIL_INCREMENT_WRAP,
+	STENCIL_DECREMENT_WRAP,
+	STENCIL_INVERT,
+	STENCIL_MAX_ENUM
+};
+
+enum CompareMode
+{
+	COMPARE_LESS,
+	COMPARE_LEQUAL,
+	COMPARE_EQUAL,
+	COMPARE_GEQUAL,
+	COMPARE_GREATER,
+	COMPARE_NOTEQUAL,
+	COMPARE_ALWAYS,
+	COMPARE_NEVER,
+	COMPARE_MAX_ENUM
+};
+
+struct BlendState
+{
+	bool enable = false;
+	BlendOperation operationRGB = BLENDOP_ADD;
+	BlendOperation operationA = BLENDOP_ADD;
+	BlendFactor srcFactorRGB = BLENDFACTOR_ONE;
+	BlendFactor srcFactorA = BLENDFACTOR_ONE;
+	BlendFactor dstFactorRGB = BLENDFACTOR_ZERO;
+	BlendFactor dstFactorA = BLENDFACTOR_ZERO;
+
+	bool operator == (const BlendState &b) const
+	{
+		return enable == b.enable
+			&& operationRGB == b.operationRGB && operationA == b.operationA
+			&& srcFactorRGB == b.srcFactorRGB && srcFactorA == b.srcFactorA
+			&& dstFactorRGB == b.dstFactorRGB && dstFactorA == b.dstFactorA;
+	}
+};
+
+struct DepthState
+{
+	CompareMode compare = COMPARE_ALWAYS;
+	bool write = false;
+
+	bool operator == (const DepthState &d) const
+	{
+		return compare == d.compare && write == d.write;
+	}
+};
+
+struct StencilState
+{
+	CompareMode compare = COMPARE_ALWAYS;
+	StencilAction action = STENCIL_KEEP;
+	int value = 0;
+	uint32 readMask = 0xFFFFFFFF;
+	uint32 writeMask = 0xFFFFFFFF;
+
+	bool operator == (const StencilState &s) const
+	{
+		return compare == s.compare && action == s.action && value == s.value
+			&& readMask == s.readMask && writeMask == s.writeMask;
+	}
+};
+
+struct ColorChannelMask
+{
+	bool r = true;
+	bool g = true;
+	bool b = true;
+	bool a = true;
+
+	bool operator == (ColorChannelMask c) const
+	{
+		return r == c.r && g == c.g && b == c.b && a == c.a;
+	}
+
+	bool operator != (ColorChannelMask c) const
+	{
+		return !(operator==(c));
+	}
+};
+
+struct ScissorState
+{
+	Rect rect = {0, 0, 0, 0};
+	bool enable = false;
+};
+
+BlendState getBlendState(BlendMode mode, BlendAlpha alphamode);
+
+/**
+ * GPU APIs do the comparison in the opposite way of what makes sense for some
+ * of love's APIs. For example in OpenGL if the compare function is GL_GREATER,
+ * then the stencil test will pass if the reference value is greater than the
+ * value in the stencil buffer. With our stencil API it's more intuitive to
+ * assume that setStencilTest(COMPARE_GREATER, 4) will make it pass if the
+ * stencil buffer has a value greater than 4.
+ **/
+CompareMode getReversedCompareMode(CompareMode mode);
+
+bool getConstant(const char *in, BlendMode &out);
+bool getConstant(BlendMode in, const char *&out);
+std::vector<std::string> getConstants(BlendMode);
+
+bool getConstant(const char *in, BlendAlpha &out);
+bool getConstant(BlendAlpha in, const char *&out);
+std::vector<std::string> getConstants(BlendAlpha);
+
+bool getConstant(const char *in, BlendFactor &out);
+bool getConstant(BlendFactor in, const char *&out);
+std::vector<std::string> getConstants(BlendFactor);
+
+bool getConstant(const char *in, BlendOperation &out);
+bool getConstant(BlendOperation in, const char *&out);
+std::vector<std::string> getConstants(BlendOperation);
+
+bool getConstant(const char *in, StencilAction &out);
+bool getConstant(StencilAction in, const char *&out);
+std::vector<std::string> getConstants(StencilAction);
+
+bool getConstant(const char *in, CompareMode &out);
+bool getConstant(CompareMode in, const char *&out);
+std::vector<std::string> getConstants(CompareMode);
+
+} // graphics
+} // love

+ 12 - 12
src/modules/graphics/wrap_Graphics.cpp

@@ -1777,7 +1777,7 @@ int w_getFont(lua_State *L)
 
 int w_setColorMask(lua_State *L)
 {
-	Graphics::ColorMask mask;
+	ColorChannelMask mask;
 
 	if (lua_gettop(L) <= 1 && lua_isnoneornil(L, 1))
 	{
@@ -1799,7 +1799,7 @@ int w_setColorMask(lua_State *L)
 
 int w_getColorMask(lua_State *L)
 {
-	Graphics::ColorMask mask = instance()->getColorMask();
+	ColorChannelMask mask = instance()->getColorMask();
 
 	luax_pushboolean(L, mask.r);
 	luax_pushboolean(L, mask.g);
@@ -1811,17 +1811,17 @@ int w_getColorMask(lua_State *L)
 
 int w_setBlendMode(lua_State *L)
 {
-	Graphics::BlendMode mode;
+	BlendMode mode;
 	const char *str = luaL_checkstring(L, 1);
-	if (!Graphics::getConstant(str, mode))
-		return luax_enumerror(L, "blend mode", Graphics::getConstants(mode), str);
+	if (!getConstant(str, mode))
+		return luax_enumerror(L, "blend mode", getConstants(mode), str);
 
-	Graphics::BlendAlpha alphamode = Graphics::BLENDALPHA_MULTIPLY;
+	BlendAlpha alphamode = BLENDALPHA_MULTIPLY;
 	if (!lua_isnoneornil(L, 2))
 	{
 		const char *alphastr = luaL_checkstring(L, 2);
-		if (!Graphics::getConstant(alphastr, alphamode))
-			return luax_enumerror(L, "blend alpha mode", Graphics::getConstants(alphamode), alphastr);
+		if (!getConstant(alphastr, alphamode))
+			return luax_enumerror(L, "blend alpha mode", getConstants(alphamode), alphastr);
 	}
 
 	luax_catchexcept(L, [&](){ instance()->setBlendMode(mode, alphamode); });
@@ -1833,13 +1833,13 @@ int w_getBlendMode(lua_State *L)
 	const char *str;
 	const char *alphastr;
 
-	Graphics::BlendAlpha alphamode;
-	Graphics::BlendMode mode = instance()->getBlendMode(alphamode);
+	BlendAlpha alphamode;
+	BlendMode mode = instance()->getBlendMode(alphamode);
 
-	if (!Graphics::getConstant(mode, str))
+	if (!getConstant(mode, str))
 		return luaL_error(L, "Unknown blend mode");
 
-	if (!Graphics::getConstant(alphamode, alphastr))
+	if (!getConstant(alphamode, alphastr))
 		return luaL_error(L, "Unknown blend alpha mode");
 
 	lua_pushstring(L, str);