mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -187,7 +187,7 @@ private:
|
||||
};
|
||||
|
||||
void setupAttachedAttributes();
|
||||
void calculateAttributeSizes();
|
||||
void calculateAttributeSizes(Graphics *gfx);
|
||||
size_t getAttributeOffset(size_t attribindex) const;
|
||||
|
||||
std::vector<AttribFormat> vertexFormat;
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user