Browse Source

Allow rendering to integer textures.

Alex Szpakowski 4 years ago
parent
commit
cffd485976

+ 1 - 0
src/common/Color.h

@@ -137,6 +137,7 @@ ColorT<T> operator/(const ColorT<T> &a, T s)
 
 typedef ColorT<unsigned char> Color32;
 typedef ColorT<float> Colorf;
+typedef ColorT<double> ColorD;
 
 inline Color32 toColor32(Colorf cf)
 {

+ 0 - 6
src/modules/graphics/Graphics.cpp

@@ -693,9 +693,6 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
 	if (!firsttex->isValidSlice(firsttarget.slice))
 		throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
 
-	if (isPixelFormatInteger(firstcolorformat))
-		throw love::Exception("Textures with integer pixel formats cannot be rendered to, currently.");
-
 	bool hasSRGBtexture = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM;
 	int pixelw = firsttex->getPixelWidth(firsttarget.mipmap);
 	int pixelh = firsttex->getPixelHeight(firsttarget.mipmap);
@@ -729,9 +726,6 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
 		if (isPixelFormatDepthStencil(format))
 			throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets.");
 
-		if (isPixelFormatInteger(format))
-			throw love::Exception("Textures with integer pixel formats cannot be rendered to, currently.");
-
 		if (format == PIXELFORMAT_sRGBA8_UNORM)
 			hasSRGBtexture = true;
 	}

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

@@ -61,7 +61,7 @@ class Text;
 class Video;
 class Buffer;
 
-typedef Optional<Colorf> OptionalColorf;
+typedef Optional<ColorD> OptionalColorD;
 
 const int MAX_COLOR_RENDER_TARGETS = 8;
 
@@ -457,8 +457,8 @@ public:
 	 **/
 	void reset();
 
-	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 clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) = 0;
+	virtual void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) = 0;
 
 	virtual void discard(const std::vector<bool> &colorbuffers, bool depthstencil) = 0;
 

+ 37 - 0
src/modules/graphics/Shader.cpp

@@ -640,6 +640,40 @@ const Shader::UniformInfo *Shader::getMainTextureInfo() const
 	return getUniformInfo(BUILTIN_TEXTURE_MAIN);
 }
 
+DataBaseType Shader::getDataBaseType(PixelFormat format)
+{
+	switch (getPixelFormatInfo(format).dataType)
+	{
+		case PIXELFORMATTYPE_UNORM:
+			return DATA_BASETYPE_UNORM;
+		case PIXELFORMATTYPE_SNORM:
+			return DATA_BASETYPE_SNORM;
+		case PIXELFORMATTYPE_UFLOAT:
+		case PIXELFORMATTYPE_SFLOAT:
+			return DATA_BASETYPE_FLOAT;
+		case PIXELFORMATTYPE_SINT:
+			return DATA_BASETYPE_INT;
+		case PIXELFORMATTYPE_UINT:
+			return DATA_BASETYPE_UINT;
+		default:
+			return DATA_BASETYPE_FLOAT;
+	}
+}
+
+bool Shader::isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b)
+{
+	if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
+		return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
+
+	if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
+		return true;
+
+	if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
+		return true;
+
+	return false;
+}
+
 void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
 {
 	if ((primtype == PRIMITIVE_POINTS) != validationReflection.usesPointSize)
@@ -672,6 +706,9 @@ void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
 		throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
 	}
 
+	if (!isResourceBaseTypeCompatible(info->dataBaseType, getDataBaseType(maintex->getPixelFormat())))
+		throw love::Exception("Texture's data format base type must match the uniform variable declared in the shader (float, int, or uint).");
+
 	if (info->isDepthSampler != maintex->getSamplerState().depthSampleMode.hasValue)
 	{
 		if (info->isDepthSampler)

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

@@ -259,6 +259,8 @@ protected:
 	};
 
 	static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, ValidationReflection &reflection);
+	static DataBaseType getDataBaseType(PixelFormat format);
+	static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b);
 
 	StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM];
 

+ 36 - 12
src/modules/graphics/opengl/Graphics.cpp

@@ -835,7 +835,7 @@ void Graphics::endPass()
 	}
 }
 
-void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
+void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth)
 {
 	if (c.hasValue || stencil.hasValue || depth.hasValue)
 		flushBatchedDraws();
@@ -844,8 +844,9 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
 
 	if (c.hasValue)
 	{
-		gammaCorrectColor(c.value);
-		glClearColor(c.value.r, c.value.g, c.value.b, c.value.a);
+		Colorf cf((float)c.value.r, (float)c.value.g, (float)c.value.b, (float)c.value.b);
+		gammaCorrectColor(cf);
+		glClearColor(cf.r, cf.g, cf.b, cf.a);
 		flags |= GL_COLOR_BUFFER_BIT;
 	}
 
@@ -881,17 +882,19 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
 	}
 }
 
-void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth)
+void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
 {
 	if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
 		return;
 
-	int ncolorRTs = (int) states.back().renderTargets.colors.size();
+	const auto &rts = states.back().renderTargets.colors;
+
+	int ncolorRTs = (int) rts.size();
 	int ncolors = (int) colors.size();
 
-	if (ncolors <= 1 && ncolorRTs <= 1)
+	if (ncolors <= 1 && (ncolorRTs == 0 || (ncolorRTs == 1 && rts[0].texture != nullptr && !isPixelFormatInteger(rts[0].texture->getPixelFormat()))))
 	{
-		clear(ncolors > 0 ? colors[0] : OptionalColorf(), stencil, depth);
+		clear(ncolors > 0 ? colors[0] : OptionalColorD(), stencil, depth);
 		return;
 	}
 
@@ -905,18 +908,39 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
 		if (!colors[i].hasValue)
 			continue;
 
-		Colorf c = colors[i].value;
-		gammaCorrectColor(c);
+		PixelFormatType datatype = PIXELFORMATTYPE_UNORM;
+		if (rts[i].texture != nullptr)
+			datatype = getPixelFormatInfo(rts[i].texture->getPixelFormat()).dataType;
+
+		ColorD c = colors[i].value;
 
 		if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
 		{
-			const GLfloat carray[] = {c.r, c.g, c.b, c.a};
-			glClearBufferfv(GL_COLOR, i, carray);
+			if (datatype == PIXELFORMATTYPE_SINT)
+			{
+				const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a};
+				glClearBufferiv(GL_COLOR, i, carray);
+			}
+			else if (datatype == PIXELFORMATTYPE_UINT)
+			{
+				const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a};
+				glClearBufferuiv(GL_COLOR, i, carray);
+			}
+			else
+			{
+				Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
+				gammaCorrectColor(cf);
+				const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a};
+				glClearBufferfv(GL_COLOR, i, carray);
+			}
 		}
 		else
 		{
+			Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
+			gammaCorrectColor(cf);
+
 			glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
-			glClearColor(c.r, c.g, c.b, c.a);
+			glClearColor(cf.r, cf.g, cf.b, cf.a);
 			glClear(GL_COLOR_BUFFER_BIT);
 
 			drawbuffersmodified = true;

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

@@ -74,8 +74,8 @@ public:
 	void draw(const DrawIndexedCommand &cmd) override;
 	void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture) override;
 
-	void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
-	void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
+	void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
+	void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
 
 	void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
 

+ 0 - 34
src/modules/graphics/opengl/Shader.cpp

@@ -710,40 +710,6 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
 	}
 }
 
-static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b)
-{
-	if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
-		return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
-
-	if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
-		return true;
-
-	if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
-		return true;
-
-	return false;
-}
-
-static DataBaseType getDataBaseType(PixelFormat format)
-{
-	switch (getPixelFormatInfo(format).dataType)
-	{
-		case PIXELFORMATTYPE_UNORM:
-			return DATA_BASETYPE_UNORM;
-		case PIXELFORMATTYPE_SNORM:
-			return DATA_BASETYPE_SNORM;
-		case PIXELFORMATTYPE_UFLOAT:
-		case PIXELFORMATTYPE_SFLOAT:
-			return DATA_BASETYPE_FLOAT;
-		case PIXELFORMATTYPE_SINT:
-			return DATA_BASETYPE_INT;
-		case PIXELFORMATTYPE_UINT:
-			return DATA_BASETYPE_UINT;
-		default:
-			return DATA_BASETYPE_FLOAT;
-	}
-}
-
 void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
 {
 	Shader::sendTextures(info, textures, count, false);

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

@@ -68,8 +68,8 @@ int w_reset(lua_State *)
 
 int w_clear(lua_State *L)
 {
-	OptionalColorf color(Colorf(0.0f, 0.0f, 0.0f, 0.0f));
-	std::vector<OptionalColorf> colors;
+	OptionalColorD color(ColorD(0.0, 0.0, 0.0, 0.0));
+	std::vector<OptionalColorD> colors;
 
 	OptionalInt stencil(0);
 	OptionalDouble depth(1.0);
@@ -93,19 +93,19 @@ int w_clear(lua_State *L)
 			}
 			else if (argtype == LUA_TNIL || argtype == LUA_TNONE || luax_objlen(L, i + 1) == 0)
 			{
-				colors.push_back(OptionalColorf());
+				colors.push_back(OptionalColorD());
 				continue;
 			}
 
 			for (int j = 1; j <= 4; j++)
 				lua_rawgeti(L, i + 1, j);
 
-			OptionalColorf c;
+			OptionalColorD 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);
+			c.value.r = luaL_checknumber(L, -4);
+			c.value.g = luaL_checknumber(L, -3);
+			c.value.b = luaL_checknumber(L, -2);
+			c.value.a = luaL_optnumber(L, -1, 1.0);
 			colors.push_back(c);
 
 			lua_pop(L, 4);
@@ -627,7 +627,7 @@ int w_stencil(lua_State *L)
 		luaL_checktype(L, 4, LUA_TBOOLEAN);
 
 	if (stencilclear.hasValue)
-		instance()->clear(OptionalColorf(), stencilclear, OptionalDouble());
+		instance()->clear(OptionalColorD(), stencilclear, OptionalDouble());
 
 	luax_catchexcept(L, [&](){ instance()->drawToStencilBuffer(action, stencilvalue); });