Browse Source

Add new mesh data formats: int32, uint32, [u]int8, [u]int16, snorm8, and snorm16.

Integer formats for vertex attributes are only supported in glsl3 shaders. They use ivec/uvec types in glsl.

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

+ 10 - 0
src/common/runtime.h

@@ -214,6 +214,16 @@ inline float luax_checkfloat(lua_State *L, int idx)
 	return static_cast<float>(luaL_checknumber(L, idx));
 	return static_cast<float>(luaL_checknumber(L, idx));
 }
 }
 
 
+inline lua_Number luax_checknumberclamped(lua_State *L, int idx, double minv, double maxv)
+{
+	return std::min(std::max(luaL_checknumber(L, idx), minv), maxv);
+}
+
+inline lua_Number luax_optnumberclamped(lua_State *L, int idx, double minv, double maxv, double def)
+{
+	return std::min(std::max(luaL_optnumber(L, idx, def), minv), maxv);
+}
+
 inline lua_Number luax_checknumberclamped01(lua_State *L, int idx)
 inline lua_Number luax_checknumberclamped01(lua_State *L, int idx)
 {
 {
 	return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0);
 	return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0);

+ 8 - 3
src/modules/graphics/Mesh.cpp

@@ -73,7 +73,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexforma
 	, rangeCount(-1)
 	, rangeCount(-1)
 {
 {
 	setupAttachedAttributes();
 	setupAttachedAttributes();
-	calculateAttributeSizes();
+	calculateAttributeSizes(gfx);
 
 
 	vertexCount = datasize / vertexStride;
 	vertexCount = datasize / vertexStride;
 	indexDataType = vertex::getIndexDataTypeFromMax(vertexCount);
 	indexDataType = vertex::getIndexDataTypeFromMax(vertexCount);
@@ -103,7 +103,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexforma
 		throw love::Exception("Invalid number of vertices (%d).", vertexcount);
 		throw love::Exception("Invalid number of vertices (%d).", vertexcount);
 
 
 	setupAttachedAttributes();
 	setupAttachedAttributes();
-	calculateAttributeSizes();
+	calculateAttributeSizes(gfx);
 
 
 	size_t buffersize = vertexCount * vertexStride;
 	size_t buffersize = vertexCount * vertexStride;
 
 
@@ -143,8 +143,10 @@ void Mesh::setupAttachedAttributes()
 	}
 	}
 }
 }
 
 
-void Mesh::calculateAttributeSizes()
+void Mesh::calculateAttributeSizes(Graphics *gfx)
 {
 {
+	bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3];
+
 	size_t stride = 0;
 	size_t stride = 0;
 
 
 	for (const AttribFormat &format : vertexFormat)
 	for (const AttribFormat &format : vertexFormat)
@@ -158,6 +160,9 @@ void Mesh::calculateAttributeSizes()
 		if (size % 4 != 0)
 		if (size % 4 != 0)
 			throw love::Exception("Vertex attributes must have enough components to be a multiple of 32 bits.");
 			throw love::Exception("Vertex attributes must have enough components to be a multiple of 32 bits.");
 
 
+		if (vertex::isDataTypeInteger(format.type) && !supportsGLSL3)
+			throw love::Exception("Integer vertex attribute data types require GLSL 3 support.");
+
 		// Total size in bytes of each attribute in a single vertex.
 		// Total size in bytes of each attribute in a single vertex.
 		attributeSizes.push_back(size);
 		attributeSizes.push_back(size);
 		stride += size;
 		stride += size;

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

@@ -187,7 +187,7 @@ private:
 	};
 	};
 
 
 	void setupAttachedAttributes();
 	void setupAttachedAttributes();
-	void calculateAttributeSizes();
+	void calculateAttributeSizes(Graphics *gfx);
 	size_t getAttributeOffset(size_t attribindex) const;
 	size_t getAttributeOffset(size_t attribindex) const;
 
 
 	std::vector<AttribFormat> vertexFormat;
 	std::vector<AttribFormat> vertexFormat;

+ 33 - 3
src/modules/graphics/opengl/OpenGL.cpp

@@ -627,18 +627,43 @@ GLenum OpenGL::getGLIndexDataType(IndexDataType type)
 	}
 	}
 }
 }
 
 
-GLenum OpenGL::getGLVertexDataType(vertex::DataType type, GLboolean &normalized)
+GLenum OpenGL::getGLVertexDataType(vertex::DataType type, GLboolean &normalized, bool &intformat)
 {
 {
 	normalized = GL_FALSE;
 	normalized = GL_FALSE;
+	intformat = false;
 
 
 	switch (type)
 	switch (type)
 	{
 	{
+	case vertex::DATA_SNORM8:
+		normalized = GL_TRUE;
+		return GL_BYTE;
 	case vertex::DATA_UNORM8:
 	case vertex::DATA_UNORM8:
 		normalized = GL_TRUE;
 		normalized = GL_TRUE;
 		return GL_UNSIGNED_BYTE;
 		return GL_UNSIGNED_BYTE;
+	case vertex::DATA_INT8:
+		intformat = true;
+		return GL_BYTE;
+	case vertex::DATA_UINT8:
+		intformat = true;
+		return GL_UNSIGNED_BYTE;
+	case vertex::DATA_SNORM16:
+		normalized = GL_TRUE;
+		return GL_SHORT;
 	case vertex::DATA_UNORM16:
 	case vertex::DATA_UNORM16:
 		normalized = GL_TRUE;
 		normalized = GL_TRUE;
 		return GL_UNSIGNED_SHORT;
 		return GL_UNSIGNED_SHORT;
+	case vertex::DATA_INT16:
+		intformat = true;
+		return GL_SHORT;
+	case vertex::DATA_UINT16:
+		intformat = true;
+		return GL_UNSIGNED_SHORT;
+	case vertex::DATA_INT32:
+		intformat = true;
+		return GL_INT;
+	case vertex::DATA_UINT32:
+		intformat = true;
+		return GL_UNSIGNED_INT;
 	case vertex::DATA_FLOAT:
 	case vertex::DATA_FLOAT:
 		normalized = GL_FALSE;
 		normalized = GL_FALSE;
 		return GL_FLOAT;
 		return GL_FLOAT;
@@ -718,12 +743,17 @@ void OpenGL::setVertexAttributes(const vertex::Attributes &attributes, const ver
 				glVertexAttribDivisor(i, divisor);
 				glVertexAttribDivisor(i, divisor);
 
 
 			GLboolean normalized = GL_FALSE;
 			GLboolean normalized = GL_FALSE;
-			GLenum gltype = getGLVertexDataType(attrib.type, normalized);
+			bool intformat = false;
+			GLenum gltype = getGLVertexDataType(attrib.type, normalized, intformat);
 
 
 			const void *offsetpointer = reinterpret_cast<void*>(bufferinfo.offset + attrib.offsetFromVertex);
 			const void *offsetpointer = reinterpret_cast<void*>(bufferinfo.offset + attrib.offsetFromVertex);
 
 
 			bindBuffer(BUFFER_VERTEX, (GLuint) bufferinfo.buffer->getHandle());
 			bindBuffer(BUFFER_VERTEX, (GLuint) bufferinfo.buffer->getHandle());
-			glVertexAttribPointer(i, attrib.components, gltype, normalized, layout.stride, offsetpointer);
+
+			if (intformat)
+				glVertexAttribIPointer(i, attrib.components, gltype, layout.stride, offsetpointer);
+			else
+				glVertexAttribPointer(i, attrib.components, gltype, normalized, layout.stride, offsetpointer);
 		}
 		}
 
 
 		i++;
 		i++;

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

@@ -404,7 +404,7 @@ public:
 	static GLenum getGLPrimitiveType(PrimitiveType type);
 	static GLenum getGLPrimitiveType(PrimitiveType type);
 	static GLenum getGLBufferType(BufferType type);
 	static GLenum getGLBufferType(BufferType type);
 	static GLenum getGLIndexDataType(IndexDataType type);
 	static GLenum getGLIndexDataType(IndexDataType type);
-	static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized);
+	static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized, bool &intformat);
 	static GLenum getGLBufferUsage(vertex::Usage usage);
 	static GLenum getGLBufferUsage(vertex::Usage usage);
 	static GLenum getGLTextureType(TextureType type);
 	static GLenum getGLTextureType(TextureType type);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);

+ 50 - 30
src/modules/graphics/vertex.cpp

@@ -41,28 +41,17 @@ size_t getFormatStride(CommonFormat format)
 {
 {
 	switch (format)
 	switch (format)
 	{
 	{
-	case CommonFormat::NONE:
-		return 0;
-	case CommonFormat::XYf:
-		return sizeof(float) * 2;
-	case CommonFormat::XYZf:
-		return sizeof(float) * 3;
-	case CommonFormat::RGBAub:
-		return sizeof(uint8) * 4;
-	case CommonFormat::STf_RGBAub:
-		return sizeof(STf_RGBAub);
-	case CommonFormat::STPf_RGBAub:
-		return sizeof(STPf_RGBAub);
-	case CommonFormat::XYf_STf:
-		return sizeof(XYf_STf);
-	case CommonFormat::XYf_STPf:
-		return sizeof(XYf_STPf);
-	case CommonFormat::XYf_STf_RGBAub:
-		return sizeof(XYf_STf_RGBAub);
-	case CommonFormat::XYf_STus_RGBAub:
-		return sizeof(XYf_STus_RGBAub);
-	case CommonFormat::XYf_STPf_RGBAub:
-		return sizeof(XYf_STPf_RGBAub);
+		case CommonFormat::NONE: return 0;
+		case CommonFormat::XYf: return sizeof(float) * 2;
+		case CommonFormat::XYZf: return sizeof(float) * 3;
+		case CommonFormat::RGBAub: return sizeof(uint8) * 4;
+		case CommonFormat::STf_RGBAub: return sizeof(STf_RGBAub);
+		case CommonFormat::STPf_RGBAub: return sizeof(STPf_RGBAub);
+		case CommonFormat::XYf_STf: return sizeof(XYf_STf);
+		case CommonFormat::XYf_STPf: return sizeof(XYf_STPf);
+		case CommonFormat::XYf_STf_RGBAub: return sizeof(XYf_STf_RGBAub);
+		case CommonFormat::XYf_STus_RGBAub: return sizeof(XYf_STus_RGBAub);
+		case CommonFormat::XYf_STPf_RGBAub: return sizeof(XYf_STPf_RGBAub);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -118,12 +107,9 @@ size_t getIndexDataSize(IndexDataType type)
 {
 {
 	switch (type)
 	switch (type)
 	{
 	{
-	case INDEX_UINT16:
-		return sizeof(uint16);
-	case INDEX_UINT32:
-		return sizeof(uint32);
-	default:
-		return 0;
+		case INDEX_UINT16: return sizeof(uint16);
+		case INDEX_UINT32: return sizeof(uint32);
+		default: return 0;
 	}
 	}
 }
 }
 
 
@@ -131,15 +117,41 @@ size_t getDataTypeSize(DataType datatype)
 {
 {
 	switch (datatype)
 	switch (datatype)
 	{
 	{
+	case DATA_SNORM8:
 	case DATA_UNORM8:
 	case DATA_UNORM8:
+	case DATA_INT8:
+	case DATA_UINT8:
 		return sizeof(uint8);
 		return sizeof(uint8);
+	case DATA_SNORM16:
 	case DATA_UNORM16:
 	case DATA_UNORM16:
+	case DATA_INT16:
+	case DATA_UINT16:
 		return sizeof(uint16);
 		return sizeof(uint16);
+	case DATA_INT32:
+	case DATA_UINT32:
+		return sizeof(uint32);
 	case DATA_FLOAT:
 	case DATA_FLOAT:
 		return sizeof(float);
 		return sizeof(float);
-	default:
+	case DATA_MAX_ENUM:
 		return 0;
 		return 0;
 	}
 	}
+	return 0;
+}
+
+bool isDataTypeInteger(DataType datatype)
+{
+	switch (datatype)
+	{
+	case DATA_INT8:
+	case DATA_UINT8:
+	case DATA_INT16:
+	case DATA_UINT16:
+	case DATA_INT32:
+	case DATA_UINT32:
+		return true;
+	default:
+		return false;
+	}
 }
 }
 
 
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue)
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue)
@@ -323,8 +335,16 @@ static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps(attributeStepEntri
 
 
 static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[] =
 static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[] =
 {
 {
-	{ "byte",    DATA_UNORM8  }, // Legacy / more user-friendly name...
+	{ "snorm8",  DATA_SNORM8  },
+	{ "unorm8",  DATA_UNORM8  },
+	{ "int8",    DATA_INT8    },
+	{ "uint8",   DATA_UINT8   },
+	{ "snorm16", DATA_SNORM16 },
 	{ "unorm16", DATA_UNORM16 },
 	{ "unorm16", DATA_UNORM16 },
+	{ "int16",   DATA_INT16   },
+	{ "uint16",  DATA_UINT16  },
+	{ "int32",   DATA_INT32   },
+	{ "uint32",  DATA_UINT32  },
 	{ "float",   DATA_FLOAT   },
 	{ "float",   DATA_FLOAT   },
 };
 };
 
 

+ 13 - 0
src/modules/graphics/vertex.h

@@ -106,9 +106,21 @@ enum Usage
 
 
 enum DataType
 enum DataType
 {
 {
+	DATA_SNORM8,
 	DATA_UNORM8,
 	DATA_UNORM8,
+	DATA_INT8,
+	DATA_UINT8,
+
+	DATA_SNORM16,
 	DATA_UNORM16,
 	DATA_UNORM16,
+	DATA_INT16,
+	DATA_UINT16,
+
+	DATA_INT32,
+	DATA_UINT32,
+
 	DATA_FLOAT,
 	DATA_FLOAT,
+
 	DATA_MAX_ENUM
 	DATA_MAX_ENUM
 };
 };
 
 
@@ -296,6 +308,7 @@ inline CommonFormat getSinglePositionFormat(bool is2D)
 
 
 size_t getIndexDataSize(IndexDataType type);
 size_t getIndexDataSize(IndexDataType type);
 size_t getDataTypeSize(DataType datatype);
 size_t getDataTypeSize(DataType datatype);
+bool isDataTypeInteger(DataType datatype);
 
 
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
 
 

+ 3 - 1
src/modules/graphics/wrap_Graphics.cpp

@@ -1529,7 +1529,9 @@ static Mesh *newCustomMesh(lua_State *L)
 		format.name = luaL_checkstring(L, -3);
 		format.name = luaL_checkstring(L, -3);
 
 
 		const char *tname = luaL_checkstring(L, -2);
 		const char *tname = luaL_checkstring(L, -2);
-		if (!vertex::getConstant(tname, format.type))
+		if (strcmp(tname, "byte") == 0) // Legacy name.
+			format.type = vertex::DATA_UNORM8;
+		else if (!vertex::getConstant(tname, format.type))
 		{
 		{
 			luax_enumerror(L, "Mesh vertex data type name", vertex::getConstants(format.type), tname);
 			luax_enumerror(L, "Mesh vertex data type name", vertex::getConstants(format.type), tname);
 			return nullptr;
 			return nullptr;

+ 74 - 30
src/modules/graphics/wrap_Mesh.cpp

@@ -37,91 +37,135 @@ Mesh *luax_checkmesh(lua_State *L, int idx)
 	return luax_checktype<Mesh>(L, idx);
 	return luax_checktype<Mesh>(L, idx);
 }
 }
 
 
-static inline size_t writeUnorm8Data(lua_State *L, int startidx, int components, char *data)
+static const double defaultComponents[] = {0.0, 0.0, 0.0, 1.0};
+
+template <typename T>
+static inline size_t writeData(lua_State *L, int startidx, int components, char *data)
 {
 {
-	uint8 *componentdata = (uint8 *) data;
+	auto componentdata = (T *) data;
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		componentdata[i] = (uint8) (luax_optnumberclamped01(L, startidx + i, 1.0) * 255.0);
+		componentdata[i] = (T) (luaL_optnumber(L, startidx + i, defaultComponents[i]));
 
 
-	return sizeof(uint8) * components;
+	return sizeof(T) * components;
 }
 }
 
 
-static inline size_t writeUnorm16Data(lua_State *L, int startidx, int components, char *data)
+template <typename T>
+static inline size_t writeSNormData(lua_State *L, int startidx, int components, char *data)
 {
 {
-	uint16 *componentdata = (uint16 *) data;
+	auto componentdata = (T *) data;
+	auto maxval = std::numeric_limits<T>::max();
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		componentdata[i] = (uint16) (luax_optnumberclamped01(L, startidx + i, 1.0) * 65535.0);
+		componentdata[i] = (T) (luax_optnumberclamped(L, startidx + i, -1.0, 1.0, defaultComponents[i]) * maxval);
 
 
-	return sizeof(uint16) * components;
+	return sizeof(T) * components;
 }
 }
 
 
-static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data)
+template <typename T>
+static inline size_t writeUNormData(lua_State *L, int startidx, int components, char *data)
 {
 {
-	float *componentdata = (float *) data;
+	auto componentdata = (T *) data;
+	auto maxval = std::numeric_limits<T>::max();
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0);
+		componentdata[i] = (T) (luax_optnumberclamped01(L, startidx + i, 1.0) * maxval);
 
 
-	return sizeof(float) * components;
+	return sizeof(T) * components;
 }
 }
 
 
 char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data)
 char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data)
 {
 {
 	switch (type)
 	switch (type)
 	{
 	{
+	case vertex::DATA_SNORM8:
+		return data + writeSNormData<int8>(L, startidx, components, data);
 	case vertex::DATA_UNORM8:
 	case vertex::DATA_UNORM8:
-		return data + writeUnorm8Data(L, startidx, components, data);
+		return data + writeUNormData<uint8>(L, startidx, components, data);
+	case vertex::DATA_INT8:
+		return data + writeData<int8>(L, startidx, components, data);
+	case vertex::DATA_UINT8:
+		return data + writeData<uint8>(L, startidx, components, data);
+	case vertex::DATA_SNORM16:
+		return data + writeSNormData<int16>(L, startidx, components, data);
 	case vertex::DATA_UNORM16:
 	case vertex::DATA_UNORM16:
-		return data + writeUnorm16Data(L, startidx, components, data);
+		return data + writeUNormData<uint16>(L, startidx, components, data);
+	case vertex::DATA_INT16:
+		return data + writeData<int16>(L, startidx, components, data);
+	case vertex::DATA_UINT16:
+		return data + writeData<uint16>(L, startidx, components, data);
+	case vertex::DATA_INT32:
+		return data + writeData<int32>(L, startidx, components, data);
+	case vertex::DATA_UINT32:
+		return data + writeData<uint32>(L, startidx, components, data);
 	case vertex::DATA_FLOAT:
 	case vertex::DATA_FLOAT:
-		return data + writeFloatData(L, startidx, components, data);
+		return data + writeData<float>(L, startidx, components, data);
 	default:
 	default:
 		return data;
 		return data;
 	}
 	}
 }
 }
 
 
-static inline size_t readUnorm8Data(lua_State *L, int components, const char *data)
+template <typename T>
+static inline size_t readData(lua_State *L, int components, const char *data)
 {
 {
-	const uint8 *componentdata = (const uint8 *) data;
+	auto componentdata = (const T *) data;
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		lua_pushnumber(L, (lua_Number) componentdata[i] / 255.0);
+		lua_pushnumber(L, (lua_Number) componentdata[i]);
 
 
-	return sizeof(uint8) * components;
+	return sizeof(T) * components;
 }
 }
 
 
-static inline size_t readUnorm16Data(lua_State *L, int components, const char *data)
+template <typename T>
+static inline size_t readSNormData(lua_State *L, int components, const char *data)
 {
 {
-	const uint16 *componentdata = (const uint16 *) data;
+	auto componentdata = (const T *) data;
+	auto maxval = std::numeric_limits<T>::max();
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		lua_pushnumber(L, (lua_Number) componentdata[i] / 65535.0);
+		lua_pushnumber(L, std::max(-1.0, (lua_Number) componentdata[i] / (lua_Number)maxval));
 
 
-	return sizeof(uint16) * components;
+	return sizeof(T) * components;
 }
 }
 
 
-static inline size_t readFloatData(lua_State *L, int components, const char *data)
+template <typename T>
+static inline size_t readUNormData(lua_State *L, int components, const char *data)
 {
 {
-	const float *componentdata = (const float *) data;
+	auto componentdata = (const T *) data;
+	auto maxval = std::numeric_limits<T>::max();
 
 
 	for (int i = 0; i < components; i++)
 	for (int i = 0; i < components; i++)
-		lua_pushnumber(L, componentdata[i]);
+		lua_pushnumber(L, (lua_Number) componentdata[i] / (lua_Number)maxval);
 
 
-	return sizeof(float) * components;
+	return sizeof(T) * components;
 }
 }
 
 
 const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data)
 const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data)
 {
 {
 	switch (type)
 	switch (type)
 	{
 	{
+	case vertex::DATA_SNORM8:
+		return data + readSNormData<int8>(L, components, data);
 	case vertex::DATA_UNORM8:
 	case vertex::DATA_UNORM8:
-		return data + readUnorm8Data(L, components, data);
+		return data + readUNormData<uint8>(L, components, data);
+	case vertex::DATA_INT8:
+		return data + readData<int8>(L, components, data);
+	case vertex::DATA_UINT8:
+		return data + readData<uint8>(L, components, data);
+	case vertex::DATA_SNORM16:
+		return data + readSNormData<int16>(L, components, data);
 	case vertex::DATA_UNORM16:
 	case vertex::DATA_UNORM16:
-		return data + readUnorm16Data(L, components, data);
+		return data + readUNormData<uint16>(L, components, data);
+	case vertex::DATA_INT16:
+		return data + readData<int16>(L, components, data);
+	case vertex::DATA_UINT16:
+		return data + readData<uint16>(L, components, data);
+	case vertex::DATA_INT32:
+		return data + readData<int32>(L, components, data);
+	case vertex::DATA_UINT32:
+		return data + readData<uint32>(L, components, data);
 	case vertex::DATA_FLOAT:
 	case vertex::DATA_FLOAT:
-		return data + readFloatData(L, components, data);
+		return data + readData<float>(L, components, data);
 	default:
 	default:
 		return data;
 		return data;
 	}
 	}