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
This commit is contained in:
Alex Szpakowski
2020-01-11 22:24:38 -04:00
parent 5c009d4bb9
commit 23bc1a7aae
9 changed files with 193 additions and 69 deletions
+10
View File
@@ -214,6 +214,16 @@ inline float luax_checkfloat(lua_State *L, int 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)
{
return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0);
+8 -3
View File
@@ -73,7 +73,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexforma
, rangeCount(-1)
{
setupAttachedAttributes();
calculateAttributeSizes();
calculateAttributeSizes(gfx);
vertexCount = datasize / vertexStride;
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);
setupAttachedAttributes();
calculateAttributeSizes();
calculateAttributeSizes(gfx);
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;
for (const AttribFormat &format : vertexFormat)
@@ -158,6 +160,9 @@ void Mesh::calculateAttributeSizes()
if (size % 4 != 0)
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.
attributeSizes.push_back(size);
stride += size;
+1 -1
View File
@@ -187,7 +187,7 @@ private:
};
void setupAttachedAttributes();
void calculateAttributeSizes();
void calculateAttributeSizes(Graphics *gfx);
size_t getAttributeOffset(size_t attribindex) const;
std::vector<AttribFormat> vertexFormat;
+33 -3
View File
@@ -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;
intformat = false;
switch (type)
{
case vertex::DATA_SNORM8:
normalized = GL_TRUE;
return GL_BYTE;
case vertex::DATA_UNORM8:
normalized = GL_TRUE;
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:
normalized = GL_TRUE;
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:
normalized = GL_FALSE;
return GL_FLOAT;
@@ -718,12 +743,17 @@ void OpenGL::setVertexAttributes(const vertex::Attributes &attributes, const ver
glVertexAttribDivisor(i, divisor);
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);
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++;
+1 -1
View File
@@ -404,7 +404,7 @@ public:
static GLenum getGLPrimitiveType(PrimitiveType type);
static GLenum getGLBufferType(BufferType 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 getGLTextureType(TextureType type);
static GLint getGLWrapMode(Texture::WrapMode wmode);
+50 -30
View File
@@ -41,28 +41,17 @@ size_t getFormatStride(CommonFormat 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;
}
@@ -118,12 +107,9 @@ size_t getIndexDataSize(IndexDataType 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)
{
case DATA_SNORM8:
case DATA_UNORM8:
case DATA_INT8:
case DATA_UINT8:
return sizeof(uint8);
case DATA_SNORM16:
case DATA_UNORM16:
case DATA_INT16:
case DATA_UINT16:
return sizeof(uint16);
case DATA_INT32:
case DATA_UINT32:
return sizeof(uint32);
case DATA_FLOAT:
return sizeof(float);
default:
case DATA_MAX_ENUM:
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)
@@ -323,8 +335,16 @@ static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps(attributeStepEntri
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 },
{ "int16", DATA_INT16 },
{ "uint16", DATA_UINT16 },
{ "int32", DATA_INT32 },
{ "uint32", DATA_UINT32 },
{ "float", DATA_FLOAT },
};
+13
View File
@@ -106,9 +106,21 @@ enum Usage
enum DataType
{
DATA_SNORM8,
DATA_UNORM8,
DATA_INT8,
DATA_UINT8,
DATA_SNORM16,
DATA_UNORM16,
DATA_INT16,
DATA_UINT16,
DATA_INT32,
DATA_UINT32,
DATA_FLOAT,
DATA_MAX_ENUM
};
@@ -296,6 +308,7 @@ inline CommonFormat getSinglePositionFormat(bool is2D)
size_t getIndexDataSize(IndexDataType type);
size_t getDataTypeSize(DataType datatype);
bool isDataTypeInteger(DataType datatype);
IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
+3 -1
View File
@@ -1529,7 +1529,9 @@ static Mesh *newCustomMesh(lua_State *L)
format.name = luaL_checkstring(L, -3);
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);
return nullptr;
+74 -30
View File
@@ -37,91 +37,135 @@ Mesh *luax_checkmesh(lua_State *L, int 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++)
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++)
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++)
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)
{
switch (type)
{
case vertex::DATA_SNORM8:
return data + writeSNormData<int8>(L, startidx, components, data);
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:
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:
return data + writeFloatData(L, startidx, components, data);
return data + writeData<float>(L, startidx, components, data);
default:
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++)
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++)
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++)
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)
{
switch (type)
{
case vertex::DATA_SNORM8:
return data + readSNormData<int8>(L, components, data);
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:
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:
return data + readFloatData(L, components, data);
return data + readData<float>(L, components, data);
default:
return data;
}