mirror of https://github.com/bjornbytes/lovr.git
rm VertexData;
This commit is contained in:
parent
4373e29bea
commit
a02d4eb659
|
@ -385,7 +385,6 @@ if(LOVR_ENABLE_DATA)
|
|||
src/data/rasterizer.c
|
||||
src/data/soundData.c
|
||||
src/data/textureData.c
|
||||
src/data/vertexData.c
|
||||
src/api/data.c
|
||||
src/api/types/audioStream.c
|
||||
src/api/types/blob.c
|
||||
|
@ -393,7 +392,6 @@ if(LOVR_ENABLE_DATA)
|
|||
src/api/types/rasterizer.c
|
||||
src/api/types/soundData.c
|
||||
src/api/types/textureData.c
|
||||
src/api/types/vertexData.c
|
||||
src/lib/stb/stb_image.c
|
||||
src/lib/stb/stb_image_write.c
|
||||
src/lib/stb/stb_truetype.c
|
||||
|
|
|
@ -53,7 +53,6 @@ extern const luaL_Reg lovrTexture[];
|
|||
extern const luaL_Reg lovrTextureData[];
|
||||
extern const luaL_Reg lovrThread[];
|
||||
extern const luaL_Reg lovrVec3[];
|
||||
extern const luaL_Reg lovrVertexData[];
|
||||
extern const luaL_Reg lovrWorld[];
|
||||
|
||||
// Enums
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include "data/rasterizer.h"
|
||||
#include "data/soundData.h"
|
||||
#include "data/textureData.h"
|
||||
#include "data/vertexData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
|
||||
static int l_lovrDataNewBlob(lua_State* L) {
|
||||
size_t size;
|
||||
|
@ -45,11 +43,9 @@ static int l_lovrDataNewAudioStream(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static ModelDataIO modelDataIO = { lovrFilesystemRead };
|
||||
|
||||
static int l_lovrDataNewModelData(lua_State* L) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
ModelData* modelData = lovrModelDataCreate(blob, modelDataIO);
|
||||
ModelData* modelData = lovrModelDataCreate(blob);
|
||||
luax_pushobject(L, modelData);
|
||||
lovrRelease(blob);
|
||||
lovrRelease(modelData);
|
||||
|
@ -121,42 +117,6 @@ static int l_lovrDataNewTextureData(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrDataNewVertexData(lua_State* L) {
|
||||
uint32_t count;
|
||||
int dataIndex = 0;
|
||||
bool hasFormat = false;
|
||||
VertexFormat format;
|
||||
vertexFormatInit(&format);
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
count = lua_tointeger(L, 1);
|
||||
} else if (lua_istable(L, 1)) {
|
||||
if (lua_isnumber(L, 2)) {
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
count = lua_tointeger(L, 2);
|
||||
dataIndex = 0;
|
||||
} else if (lua_istable(L, 2)) {
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
count = lua_objlen(L, 2);
|
||||
dataIndex = 2;
|
||||
} else {
|
||||
count = lua_objlen(L, 1);
|
||||
dataIndex = 1;
|
||||
}
|
||||
} else {
|
||||
return luaL_argerror(L, 1, "table or number expected");
|
||||
}
|
||||
|
||||
VertexData* vertexData = lovrVertexDataCreate(count, hasFormat ? &format : NULL);
|
||||
|
||||
if (dataIndex) {
|
||||
luax_loadvertices(L, dataIndex, &vertexData->format, (AttributePointer) { .raw = vertexData->blob.data });
|
||||
}
|
||||
luax_pushobject(L, vertexData);
|
||||
lovrRelease(vertexData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg lovrData[] = {
|
||||
{ "newBlob", l_lovrDataNewBlob },
|
||||
{ "newAudioStream", l_lovrDataNewAudioStream },
|
||||
|
@ -164,7 +124,6 @@ static const luaL_Reg lovrData[] = {
|
|||
{ "newRasterizer", l_lovrDataNewRasterizer },
|
||||
{ "newSoundData", l_lovrDataNewSoundData },
|
||||
{ "newTextureData", l_lovrDataNewTextureData },
|
||||
{ "newVertexData", l_lovrDataNewVertexData },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -177,6 +136,5 @@ int luaopen_lovr_data(lua_State* L) {
|
|||
luax_registertype(L, "Rasterizer", lovrRasterizer);
|
||||
luax_extendtype(L, "Blob", "SoundData", lovrBlob, lovrSoundData);
|
||||
luax_extendtype(L, "Blob", "TextureData", lovrBlob, lovrTextureData);
|
||||
luax_extendtype(L, "Blob", "VertexData", lovrBlob, lovrVertexData);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
#include "data/blob.h"
|
||||
#include "data/vertexData.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
int luax_loadvertices(lua_State* L, int index, VertexFormat* format, AttributePointer vertices);
|
||||
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format);
|
||||
int luax_pushvertexformat(lua_State* L, VertexFormat* format);
|
||||
int luax_pushvertexattribute(lua_State* L, AttributePointer* vertex, Attribute attribute);
|
||||
int luax_pushvertex(lua_State* L, AttributePointer* vertex, VertexFormat* format);
|
||||
void luax_setvertexattribute(lua_State* L, int index, AttributePointer* vertex, Attribute attribute);
|
||||
void luax_setvertex(lua_State* L, int index, AttributePointer* vertex, VertexFormat* format);
|
||||
Blob* luax_readblob(lua_State* L, int index, const char* debug);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "data/modelData.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "data/textureData.h"
|
||||
#include "data/vertexData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "util.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
|
@ -26,13 +25,13 @@ const char* ArcModes[] = {
|
|||
};
|
||||
|
||||
const char* AttributeTypes[] = {
|
||||
[I8] = "i8",
|
||||
[U8] = "u8",
|
||||
[I16] = "i16",
|
||||
[U16] = "u16",
|
||||
[I32] = "i32",
|
||||
[U32] = "u32",
|
||||
[F32] = "f32",
|
||||
[I8] = "byte",
|
||||
[U8] = "ubyte",
|
||||
[I16] = "short",
|
||||
[U16] = "ushort",
|
||||
[I32] = "int",
|
||||
[U32] = "uint",
|
||||
[F32] = "float",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -1124,70 +1123,136 @@ static int l_lovrGraphicsNewMaterial(lua_State* L) {
|
|||
static int l_lovrGraphicsNewMesh(lua_State* L) {
|
||||
uint32_t count;
|
||||
int dataIndex = 0;
|
||||
int formatIndex = 0;
|
||||
int drawModeIndex = 2;
|
||||
VertexData* vertexData = NULL;
|
||||
bool hasFormat = false;
|
||||
VertexFormat format;
|
||||
vertexFormatInit(&format);
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
count = lua_tointeger(L, 1);
|
||||
} else if (lua_istable(L, 1)) {
|
||||
if (lua_isnumber(L, 2)) {
|
||||
drawModeIndex++;
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
formatIndex = 1;
|
||||
count = lua_tointeger(L, 2);
|
||||
dataIndex = 0;
|
||||
} else if (lua_istable(L, 2)) {
|
||||
drawModeIndex++;
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
formatIndex = 1;
|
||||
count = lua_objlen(L, 2);
|
||||
dataIndex = 2;
|
||||
} else {
|
||||
count = lua_objlen(L, 1);
|
||||
dataIndex = 1;
|
||||
}
|
||||
} else if (lua_isuserdata(L, 1)) {
|
||||
vertexData = luax_checktype(L, 1, VertexData);
|
||||
format = vertexData->format;
|
||||
count = vertexData->count;
|
||||
hasFormat = true;
|
||||
} else {
|
||||
luaL_argerror(L, 1, "table or number expected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hasFormat) {
|
||||
vertexFormatAppend(&format, "lovrPosition", F32, 3);
|
||||
vertexFormatAppend(&format, "lovrNormal", F32, 3);
|
||||
vertexFormatAppend(&format, "lovrTexCoord", F32, 2);
|
||||
MeshAttribute attributes[MAX_ATTRIBUTES];
|
||||
const char* attributeNames[MAX_ATTRIBUTES];
|
||||
int attributeCount = 0;
|
||||
size_t stride = 0;
|
||||
|
||||
if (formatIndex == 0) {
|
||||
stride = 32;
|
||||
attributeCount = 3;
|
||||
attributes[0] = (MeshAttribute) { .offset = 0, .stride = stride, .type = F32, .components = 3 };
|
||||
attributes[1] = (MeshAttribute) { .offset = 12, .stride = stride, .type = F32, .components = 3 };
|
||||
attributes[2] = (MeshAttribute) { .offset = 24, .stride = stride, .type = F32, .components = 2 };
|
||||
attributeNames[0] = "lovrPosition";
|
||||
attributeNames[1] = "lovrNormal";
|
||||
attributeNames[2] = "lovrTexCoord";
|
||||
} else {
|
||||
attributeCount = lua_objlen(L, formatIndex);
|
||||
lovrAssert(attributeCount >= 0 && attributeCount <= MAX_ATTRIBUTES, "Attribute count must be between 0 and %d", MAX_ATTRIBUTES);
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
lua_rawgeti(L, formatIndex, i + 1);
|
||||
lovrAssert(lua_type(L, -1) == LUA_TTABLE, "Attribute definitions must be tables containing name, type, and component count");
|
||||
lua_rawgeti(L, -1, 3);
|
||||
lua_rawgeti(L, -1, 2);
|
||||
lua_rawgeti(L, -1, 1);
|
||||
|
||||
attributeNames[i] = lua_tostring(L, -1);
|
||||
attributes[i].offset = stride;
|
||||
attributes[i].type = luaL_checkoption(L, -2, "float", AttributeTypes);
|
||||
attributes[i].components = luaL_optinteger(L, -3, 1);
|
||||
|
||||
switch (attributes[i].type) {
|
||||
case I8:
|
||||
case U8:
|
||||
stride += 1 * attributes[i].components;
|
||||
break;
|
||||
|
||||
case I16:
|
||||
case U16:
|
||||
stride += 2 * attributes[i].components;
|
||||
break;
|
||||
|
||||
case I32:
|
||||
case U32:
|
||||
case F32:
|
||||
stride += 4 * attributes[i].components;
|
||||
break;
|
||||
}
|
||||
lua_pop(L, 3);
|
||||
}
|
||||
}
|
||||
|
||||
DrawMode mode = luaL_checkoption(L, drawModeIndex, "fan", DrawModes);
|
||||
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
|
||||
bool readable = lua_toboolean(L, drawModeIndex + 2);
|
||||
size_t bufferSize = count * format.stride;
|
||||
size_t bufferSize = attributeCount * stride;
|
||||
Buffer* vertexBuffer = lovrBufferCreate(bufferSize, NULL, BUFFER_VERTEX, usage, readable);
|
||||
Mesh* mesh = lovrMeshCreate(mode, format, vertexBuffer, count);
|
||||
Mesh* mesh = lovrMeshCreate(mode, vertexBuffer, count);
|
||||
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
lovrMeshAttachAttribute(mesh, attributeNames[i], &(MeshAttribute) {
|
||||
.buffer = vertexBuffer,
|
||||
.offset = attributes[i].offset,
|
||||
.stride = stride,
|
||||
.type = attributes[i].type,
|
||||
.components = attributes[i].components
|
||||
});
|
||||
}
|
||||
|
||||
lovrMeshAttachAttribute(mesh, "lovrDrawID", &(MeshAttribute) {
|
||||
.buffer = lovrGraphicsGetIdentityBuffer(),
|
||||
.type = U8,
|
||||
.components = 1,
|
||||
.divisor = 1,
|
||||
.integer = true,
|
||||
.enabled = true
|
||||
.integer = true
|
||||
});
|
||||
|
||||
if (dataIndex) {
|
||||
AttributePointer vertices = { .raw = lovrBufferMap(vertexBuffer, 0) };
|
||||
luax_loadvertices(L, dataIndex, lovrMeshGetVertexFormat(mesh), vertices);
|
||||
} else if (vertexData) {
|
||||
void* vertices = lovrBufferMap(vertexBuffer, 0);
|
||||
memcpy(vertices, vertexData->blob.data, vertexData->count * vertexData->format.stride);
|
||||
AttributeData data = { .raw = lovrBufferMap(vertexBuffer, 0) };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, dataIndex, i + 1);
|
||||
lovrAssert(lua_istable(L, -1), "Vertices should be specified as a table of tables");
|
||||
|
||||
int component = 0;
|
||||
for (int j = 0; j < attributeCount; j++) {
|
||||
MeshAttribute* attribute = &attributes[j];
|
||||
for (int k = 0; k < attribute->components; k++) {
|
||||
lua_rawgeti(L, -1, ++component);
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case F32: *data.u32++ = luaL_optnumber(L, -1, 0.); break;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lovrBufferMarkRange(vertexBuffer, 0, count * format.stride);
|
||||
lovrBufferMarkRange(vertexBuffer, 0, count * stride);
|
||||
lovrRelease(vertexBuffer);
|
||||
|
||||
luax_pushobject(L, mesh);
|
||||
|
@ -1200,8 +1265,7 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
|
||||
if (!modelData) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
static ModelDataIO io = { lovrFilesystemRead };
|
||||
modelData = lovrModelDataCreate(blob, io);
|
||||
modelData = lovrModelDataCreate(blob);
|
||||
lovrRelease(blob);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,25 +9,24 @@ int l_lovrMeshAttachAttributes(lua_State* L) {
|
|||
Mesh* other = luax_checktype(L, 2, Mesh);
|
||||
int instanceDivisor = luaL_optinteger(L, 3, 0);
|
||||
if (lua_isnoneornil(L, 4)) {
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(other);
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
const char* name = format->attributes[i].name;
|
||||
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
|
||||
MeshAttribute attachment = *attribute;
|
||||
int count = 0;
|
||||
for (int i = 0; i < other->attributeCount; i++) {
|
||||
MeshAttribute attachment = other->attributes[i];
|
||||
if (attachment.buffer != other->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
attachment.divisor = instanceDivisor;
|
||||
attachment.enabled = true;
|
||||
lovrMeshAttachAttribute(mesh, name, &attachment);
|
||||
lovrMeshAttachAttribute(mesh, other->attributeNames[i], &attachment);
|
||||
}
|
||||
} else if (lua_istable(L, 4)) {
|
||||
int length = lua_objlen(L, 4);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, 4, i + 1);
|
||||
const char* name = lua_tostring(L, -1);
|
||||
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
|
||||
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
|
||||
MeshAttribute attachment = *attribute;
|
||||
attachment.divisor = instanceDivisor;
|
||||
attachment.enabled = true;
|
||||
lovrMeshAttachAttribute(mesh, name, &attachment);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
@ -35,11 +34,10 @@ int l_lovrMeshAttachAttributes(lua_State* L) {
|
|||
int top = lua_gettop(L);
|
||||
for (int i = 4; i <= top; i++) {
|
||||
const char* name = lua_tostring(L, i);
|
||||
MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
|
||||
const MeshAttribute* attribute = lovrMeshGetAttribute(other, name);
|
||||
lovrAssert(attribute, "Tried to attach non-existent attribute %s", name);
|
||||
MeshAttribute attachment = *attribute;
|
||||
attachment.divisor = instanceDivisor;
|
||||
attachment.enabled = true;
|
||||
lovrMeshAttachAttribute(mesh, name, &attachment);
|
||||
}
|
||||
}
|
||||
|
@ -51,9 +49,12 @@ int l_lovrMeshDetachAttributes(lua_State* L) {
|
|||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
if (lua_isuserdata(L, 2)) {
|
||||
Mesh* other = luax_checktype(L, 2, Mesh);
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(other);
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
lovrMeshDetachAttribute(mesh, format->attributes[i].name);
|
||||
for (int i = 0; i < other->attributeCount; i++) {
|
||||
const MeshAttribute* attachment = &other->attributes[i];
|
||||
if (attachment->buffer != other->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
lovrMeshDetachAttribute(mesh, other->attributeNames[i]);
|
||||
}
|
||||
} else if (lua_istable(L, 2)) {
|
||||
int length = lua_objlen(L, 2);
|
||||
|
@ -111,8 +112,22 @@ int l_lovrMeshSetDrawMode(lua_State* L) {
|
|||
|
||||
int l_lovrMeshGetVertexFormat(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
return luax_pushvertexformat(L, format);
|
||||
lua_createtable(L, mesh->attributeCount, 0);
|
||||
for (int i = 0; i < mesh->attributeCount; i++) {
|
||||
const MeshAttribute* attribute = &mesh->attributes[i];
|
||||
if (attribute->buffer != mesh->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
lua_createtable(L, 3, 0);
|
||||
lua_pushstring(L, mesh->attributeNames[i]);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushstring(L, AttributeTypes[attribute->type]);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushinteger(L, attribute->components);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrMeshGetVertexCount(lua_State* L) {
|
||||
|
@ -123,23 +138,78 @@ int l_lovrMeshGetVertexCount(lua_State* L) {
|
|||
|
||||
int l_lovrMeshGetVertex(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
int index = luaL_checkint(L, 2) - 1;
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
AttributePointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
|
||||
return luax_pushvertex(L, &vertex, format);
|
||||
int index = luaL_checkinteger(L, 2) - 1;
|
||||
|
||||
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
|
||||
lovrThrow("Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
lovrAssert(lovrBufferIsReadable(mesh->vertexBuffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, index * mesh->attributes[0].stride) };
|
||||
|
||||
int components = 0;
|
||||
for (int i = 0; i < mesh->attributeCount; i++) {
|
||||
const MeshAttribute* attribute = &mesh->attributes[i];
|
||||
if (attribute->buffer != mesh->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j < attribute->components; j++, components++) {
|
||||
switch (attribute->type) {
|
||||
case I8: lua_pushinteger(L, *data.i8++); break;
|
||||
case U8: lua_pushinteger(L, *data.u8++); break;
|
||||
case I16: lua_pushinteger(L, *data.i16++); break;
|
||||
case U16: lua_pushinteger(L, *data.u16++); break;
|
||||
case I32: lua_pushinteger(L, *data.i32++); break;
|
||||
case U32: lua_pushinteger(L, *data.u32++); break;
|
||||
case F32: lua_pushnumber(L, *data.f32++); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
int l_lovrMeshSetVertex(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index >= 0 && index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
AttributePointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
|
||||
luax_setvertex(L, 3, &vertex, format);
|
||||
lovrBufferMarkRange(buffer, index * format->stride, (index + 1) * format->stride);
|
||||
bool table = lua_istable(L, 3);
|
||||
|
||||
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
|
||||
lovrThrow("Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
size_t stride = mesh->attributes[0].stride;
|
||||
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, index * stride) };
|
||||
int component = 0;
|
||||
for (int i = 0; i < mesh->attributeCount; i++) {
|
||||
const MeshAttribute* attribute = &mesh->attributes[i];
|
||||
if (attribute->buffer != mesh->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int j = 0; j < attribute->components; j++) {
|
||||
int k = 3 + j;
|
||||
if (table) {
|
||||
lua_rawgeti(L, 3, ++component);
|
||||
k = -1;
|
||||
}
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, k, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, k, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, k, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, k, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, k, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, k, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, k, 0.); break;
|
||||
}
|
||||
|
||||
if (table) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
lovrBufferMarkRange(mesh->vertexBuffer, index * stride, (index + 1) * stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -148,67 +218,108 @@ int l_lovrMeshGetVertexAttribute(lua_State* L) {
|
|||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
Attribute attribute = format->attributes[attributeIndex];
|
||||
AttributePointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
|
||||
return luax_pushvertexattribute(L, &vertex, attribute);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < mesh->attributeCount, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
lovrAssert(mesh->attributes[attributeIndex].buffer == mesh->vertexBuffer, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
MeshAttribute* attribute = &mesh->attributes[attributeIndex];
|
||||
AttributeData data = { .raw = lovrBufferMap(buffer, vertexIndex * attribute->stride + attribute->offset) };
|
||||
for (int i = 0; i < attribute->components; i++) {
|
||||
switch (attribute->type) {
|
||||
case I8: lua_pushinteger(L, *data.i8++); break;
|
||||
case U8: lua_pushinteger(L, *data.u8++); break;
|
||||
case I16: lua_pushinteger(L, *data.i16++); break;
|
||||
case U16: lua_pushinteger(L, *data.u16++); break;
|
||||
case I32: lua_pushinteger(L, *data.i32++); break;
|
||||
case U32: lua_pushinteger(L, *data.u32++); break;
|
||||
case F32: lua_pushnumber(L, *data.f32++); break;
|
||||
}
|
||||
}
|
||||
return attribute->components;
|
||||
}
|
||||
|
||||
int l_lovrMeshSetVertexAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
bool table = lua_istable(L, 4);
|
||||
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
Attribute attribute = format->attributes[attributeIndex];
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
AttributePointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
|
||||
luax_setvertexattribute(L, 4, &vertex, attribute);
|
||||
lovrBufferMarkRange(buffer, vertexIndex * format->stride + attribute.offset, vertexIndex * format->stride + attribute.offset + attribute.size);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < mesh->attributeCount, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
lovrAssert(mesh->attributes[attributeIndex].buffer == mesh->vertexBuffer, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
MeshAttribute* attribute = &mesh->attributes[attributeIndex];
|
||||
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, vertexIndex * attribute->stride + attribute->offset) };
|
||||
for (int i = 0; i < attribute->components; i++) {
|
||||
int index = 4 + i;
|
||||
if (table) {
|
||||
lua_rawgeti(L, 4, i + 1);
|
||||
index = -1;
|
||||
}
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, index, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, index, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, index, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, index, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, index, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, index, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, index, 0.); break;
|
||||
}
|
||||
|
||||
if (table) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lovrBufferMarkRange(mesh->vertexBuffer, vertexIndex * attribute->stride, (vertexIndex + 1) * attribute->stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshSetVertices(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
uint32_t capacity = lovrMeshGetVertexCount(mesh);
|
||||
|
||||
VertexData* vertexData = NULL;
|
||||
uint32_t sourceSize;
|
||||
if (lua_istable(L, 2)) {
|
||||
sourceSize = lua_objlen(L, 2);
|
||||
} else {
|
||||
vertexData = luax_checktype(L, 2, VertexData);
|
||||
sourceSize = vertexData->count;
|
||||
bool sameFormat = !memcmp(&vertexData->format, format, sizeof(VertexFormat));
|
||||
lovrAssert(sameFormat, "Mesh and VertexData must have the same format to copy vertices");
|
||||
}
|
||||
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
uint32_t sourceSize = lua_objlen(L, 2);
|
||||
uint32_t start = luaL_optinteger(L, 3, 1) - 1;
|
||||
uint32_t count = luaL_optinteger(L, 4, sourceSize);
|
||||
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
|
||||
lovrAssert(count <= sourceSize, "Cannot set %d vertices on Mesh: source only has %d vertices", count, sourceSize);
|
||||
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
AttributePointer vertices = { .raw = lovrBufferMap(buffer, start * format->stride) };
|
||||
|
||||
if (vertexData) {
|
||||
memcpy(vertices.raw, vertexData->blob.data, count * format->stride);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
luax_setvertex(L, -1, &vertices, format);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if (!mesh->vertexBuffer || mesh->attributeCount == 0 || mesh->attributes[0].buffer != mesh->vertexBuffer) {
|
||||
lovrThrow("Mesh does not have a vertex buffer");
|
||||
}
|
||||
|
||||
lovrBufferMarkRange(buffer, start * format->stride, (start + count) * format->stride);
|
||||
size_t stride = mesh->attributes[0].stride;
|
||||
AttributeData data = { .raw = lovrBufferMap(mesh->vertexBuffer, start * stride) };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
int component = 0;
|
||||
for (int j = 0; j < mesh->attributeCount; j++) {
|
||||
const MeshAttribute* attribute = &mesh->attributes[j];
|
||||
if (attribute->buffer != mesh->vertexBuffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < attribute->components; k++) {
|
||||
lua_rawgeti(L, -1, ++component);
|
||||
|
||||
switch (attribute->type) {
|
||||
case I8: *data.i8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U8: *data.u8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I16: *data.i16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U16: *data.u16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I32: *data.i32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U32: *data.u32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case F32: *data.f32++ = luaL_optnumber(L, -1, 0.); break;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrBufferMarkRange(mesh->vertexBuffer, start * stride, (start + count) * stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -224,7 +335,7 @@ int l_lovrMeshGetVertexMap(lua_State* L) {
|
|||
}
|
||||
|
||||
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertexMap can only be used if the Mesh was created with the readable flag");
|
||||
IndexPointer indices = { .raw = lovrBufferMap(buffer, 0) };
|
||||
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(buffer, 0) };
|
||||
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_settop(L, 2);
|
||||
|
@ -286,7 +397,7 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
|||
indexBuffer = lovrBufferCreate(count * size, NULL, BUFFER_INDEX, usage, readable);
|
||||
}
|
||||
|
||||
IndexPointer indices = { .raw = lovrBufferMap(indexBuffer, 0) };
|
||||
union { void* raw; uint16_t* shorts; uint32_t* ints; } indices = { .raw = lovrBufferMap(indexBuffer, 0) };
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
|
|
|
@ -1,242 +0,0 @@
|
|||
#include "api.h"
|
||||
#include "api/data.h"
|
||||
|
||||
int luax_loadvertices(lua_State* L, int index, VertexFormat* format, AttributePointer vertices) {
|
||||
uint32_t count = lua_objlen(L, index);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
if (!lua_istable(L, -1)) {
|
||||
return luaL_error(L, "Vertex information should be specified as a table");
|
||||
}
|
||||
|
||||
int component = 0;
|
||||
for (int j = 0; j < format->count; j++) {
|
||||
Attribute attribute = format->attributes[j];
|
||||
for (int k = 0; k < attribute.count; k++) {
|
||||
lua_rawgeti(L, -1, ++component);
|
||||
switch (attribute.type) {
|
||||
case I8: *vertices.i8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U8: *vertices.u8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I16: *vertices.i16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U16: *vertices.u16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I32: *vertices.i32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U32: *vertices.u32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case F32: *vertices.u32++ = luaL_optnumber(L, -1, 0); break;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
|
||||
if (!lua_istable(L, index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = lua_objlen(L, index);
|
||||
lovrAssert(length <= 8, "Up to 8 vertex attributes are supported");
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
|
||||
if (!lua_istable(L, -1) || lua_objlen(L, -1) != 3) {
|
||||
luaL_error(L, "Expected vertex format specified as tables containing name, data type, and size");
|
||||
return false;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
lua_rawgeti(L, -2, 2);
|
||||
lua_rawgeti(L, -3, 3);
|
||||
|
||||
const char* name = lua_tostring(L, -3);
|
||||
AttributeType type = luaL_checkoption(L, -2, NULL, AttributeTypes);
|
||||
int count = lua_tointeger(L, -1);
|
||||
lovrAssert(count >= 1 || count <= 4, "Vertex attribute counts must be between 1 and 4");
|
||||
vertexFormatAppend(format, name, type, count);
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int luax_pushvertexformat(lua_State* L, VertexFormat* format) {
|
||||
lua_newtable(L);
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
Attribute attribute = format->attributes[i];
|
||||
lua_newtable(L);
|
||||
|
||||
// Name
|
||||
lua_pushstring(L, attribute.name);
|
||||
lua_rawseti(L, -2, 1);
|
||||
|
||||
// Type
|
||||
lua_pushstring(L, AttributeTypes[attribute.type]);
|
||||
lua_rawseti(L, -2, 2);
|
||||
|
||||
// Count
|
||||
lua_pushinteger(L, attribute.count);
|
||||
lua_rawseti(L, -2, 3);
|
||||
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luax_pushvertexattribute(lua_State* L, AttributePointer* vertex, Attribute attribute) {
|
||||
for (int i = 0; i < attribute.count; i++) {
|
||||
switch (attribute.type) {
|
||||
case I8: lua_pushinteger(L, *vertex->i8++); break;
|
||||
case U8: lua_pushinteger(L, *vertex->u8++); break;
|
||||
case I16: lua_pushinteger(L, *vertex->i16++); break;
|
||||
case U16: lua_pushinteger(L, *vertex->u16++); break;
|
||||
case I32: lua_pushinteger(L, *vertex->i32++); break;
|
||||
case U32: lua_pushinteger(L, *vertex->u32++); break;
|
||||
case F32: lua_pushnumber(L, *vertex->f32++); break;
|
||||
}
|
||||
}
|
||||
return attribute.count;
|
||||
}
|
||||
|
||||
int luax_pushvertex(lua_State* L, AttributePointer* vertex, VertexFormat* format) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
count += luax_pushvertexattribute(L, vertex, format->attributes[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void luax_setvertexattribute(lua_State* L, int index, AttributePointer* vertex, Attribute attribute) {
|
||||
for (int i = 0; i < attribute.count; i++) {
|
||||
switch (attribute.type) {
|
||||
case I8: *vertex->i8++ = luaL_optinteger(L, index++, 0); break;
|
||||
case U8: *vertex->u8++ = luaL_optinteger(L, index++, 0); break;
|
||||
case I16: *vertex->i16++ = luaL_optinteger(L, index++, 0); break;
|
||||
case U16: *vertex->u16++ = luaL_optinteger(L, index++, 0); break;
|
||||
case I32: *vertex->i32++ = luaL_optinteger(L, index++, 0); break;
|
||||
case U32: *vertex->u32++ = luaL_optinteger(L, index++, 0); break;
|
||||
case F32: *vertex->f32++ = luaL_optnumber(L, index++, 0.); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void luax_setvertex(lua_State* L, int index, AttributePointer* vertex, VertexFormat* format) {
|
||||
if (lua_istable(L, index)) {
|
||||
int component = 0;
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
Attribute attribute = format->attributes[i];
|
||||
for (int j = 0; j < attribute.count; j++) {
|
||||
lua_rawgeti(L, index, ++component);
|
||||
switch (attribute.type) {
|
||||
case I8: *vertex->i8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U8: *vertex->u8++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I16: *vertex->i16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U16: *vertex->u16++ = luaL_optinteger(L, -1, 0); break;
|
||||
case I32: *vertex->i32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case U32: *vertex->u32++ = luaL_optinteger(L, -1, 0); break;
|
||||
case F32: *vertex->f32++ = luaL_optnumber(L, -1, 0.); break;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
luax_setvertexattribute(L, index, vertex, format->attributes[i]);
|
||||
index += format->attributes[i].count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
int l_lovrVertexDataGetCount(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
uint32_t count = vertexData->count;
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrVertexDataGetFormat(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
return luax_pushvertexformat(L, &vertexData->format);
|
||||
}
|
||||
|
||||
int l_lovrVertexDataGetVertex(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
uint32_t index = (uint32_t) luaL_checkint(L, 2) - 1;
|
||||
AttributePointer vertex = { .raw = (uint8_t*) vertexData->blob.data + index * vertexData->format.stride };
|
||||
return luax_pushvertex(L, &vertex, &vertexData->format);
|
||||
}
|
||||
|
||||
int l_lovrVertexDataSetVertex(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
uint32_t index = (uint32_t) luaL_checkint(L, 2) - 1;
|
||||
lovrAssert(index < vertexData->count, "Invalid vertex index: %d", index + 1);
|
||||
VertexFormat* format = &vertexData->format;
|
||||
AttributePointer vertex = { .raw = vertexData->blob.data };
|
||||
vertex.u8 += index * format->stride;
|
||||
luax_setvertex(L, 3, &vertex, format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrVertexDataGetVertexAttribute(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
uint32_t vertexIndex = (uint32_t) luaL_checkint(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
||||
VertexFormat* format = &vertexData->format;
|
||||
lovrAssert(vertexIndex < vertexData->count, "Invalid vertex index: %d", vertexIndex + 1);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid attribute index: %d", attributeIndex + 1);
|
||||
Attribute attribute = format->attributes[attributeIndex];
|
||||
AttributePointer vertex = { .raw = vertexData->blob.data };
|
||||
vertex.u8 += vertexIndex * format->stride + attribute.offset;
|
||||
return luax_pushvertexattribute(L, &vertex, attribute);
|
||||
}
|
||||
|
||||
int l_lovrVertexDataSetVertexAttribute(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
uint32_t vertexIndex = (uint32_t) luaL_checkint(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
||||
VertexFormat* format = &vertexData->format;
|
||||
lovrAssert(vertexIndex < vertexData->count, "Invalid vertex index: %d", vertexIndex + 1);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid attribute index: %d", attributeIndex + 1);
|
||||
Attribute attribute = format->attributes[attributeIndex];
|
||||
AttributePointer vertex = { .raw = vertexData->blob.data };
|
||||
vertex.u8 += vertexIndex * format->stride + attribute.offset;
|
||||
luax_setvertexattribute(L, 4, &vertex, attribute);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrVertexDataSetVertices(lua_State* L) {
|
||||
VertexData* vertexData = luax_checktype(L, 1, VertexData);
|
||||
VertexFormat* format = &vertexData->format;
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
uint32_t vertexCount = lua_objlen(L, 2);
|
||||
int start = luaL_optinteger(L, 3, 1) - 1;
|
||||
lovrAssert(start + vertexCount <= vertexData->count, "VertexData can only hold %d vertices", vertexData->count);
|
||||
AttributePointer vertices = { .raw = vertexData->blob.data };
|
||||
vertices.u8 += start * format->stride;
|
||||
|
||||
for (uint32_t i = 0; i < vertexCount; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
luax_setvertex(L, -1, &vertices, format);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrVertexData[] = {
|
||||
{ "getCount", l_lovrVertexDataGetCount },
|
||||
{ "getFormat", l_lovrVertexDataGetFormat },
|
||||
{ "getVertex", l_lovrVertexDataGetVertex },
|
||||
{ "setVertex", l_lovrVertexDataSetVertex },
|
||||
{ "getVertexAttribute", l_lovrVertexDataGetVertexAttribute },
|
||||
{ "setVertexAttribute", l_lovrVertexDataSetVertexAttribute },
|
||||
{ "setVertices", l_lovrVertexDataSetVertices },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,9 +1,9 @@
|
|||
#include "data/modelData.h"
|
||||
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* source, ModelDataIO io) {
|
||||
if (lovrModelDataInitGltf(model, source, io)) {
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* source) {
|
||||
if (lovrModelDataInitGltf(model, source)) {
|
||||
return model;
|
||||
} else if (lovrModelDataInitObj(model, source, io)) {
|
||||
} else if (lovrModelDataInitObj(model, source)) {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "data/blob.h"
|
||||
#include "data/textureData.h"
|
||||
#include "util.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -90,6 +88,17 @@ typedef enum {
|
|||
|
||||
typedef enum { I8, U8, I16, U16, I32, U32, F32 } AttributeType;
|
||||
|
||||
typedef union {
|
||||
void* raw;
|
||||
int8_t* i8;
|
||||
uint8_t* u8;
|
||||
int16_t* i16;
|
||||
uint16_t* u16;
|
||||
int32_t* i32;
|
||||
uint32_t* u32;
|
||||
float* f32;
|
||||
} AttributeData;
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
size_t size;
|
||||
|
@ -196,13 +205,9 @@ typedef struct {
|
|||
int charCount;
|
||||
} ModelData;
|
||||
|
||||
typedef struct {
|
||||
void* (*read)(const char* path, size_t* bytesRead);
|
||||
} ModelDataIO;
|
||||
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* blob, ModelDataIO io);
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* blob, ModelDataIO io);
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* blob, ModelDataIO io);
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* blob);
|
||||
#define lovrModelDataCreate(...) lovrModelDataInit(lovrAlloc(ModelData), __VA_ARGS__)
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* blob);
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* blob);
|
||||
void lovrModelDataDestroy(void* ref);
|
||||
void lovrModelDataAllocate(ModelData* model);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "data/modelData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "lib/math.h"
|
||||
#include "lib/jsmn/jsmn.h"
|
||||
#include <stdbool.h>
|
||||
|
@ -111,7 +112,7 @@ static jsmntok_t* resolveTexture(const char* json, jsmntok_t* token, ModelMateri
|
|||
return token;
|
||||
}
|
||||
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io) {
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||
uint8_t* data = source->data;
|
||||
gltfHeader* header = (gltfHeader*) data;
|
||||
bool glb = header->magic == MAGIC_glTF;
|
||||
|
@ -422,7 +423,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO io)
|
|||
char filename[1024];
|
||||
lovrAssert(uri.length < 1024, "Buffer filename is too long");
|
||||
snprintf(filename, 1023, "%s/%.*s", basePath, (int) uri.length, uri.data);
|
||||
*blob = lovrBlobCreate(io.read(filename, &bytesRead), size, NULL);
|
||||
*blob = lovrBlobCreate(lovrFilesystemRead(filename, &bytesRead), size, NULL);
|
||||
lovrAssert((*blob)->data && bytesRead == size, "Unable to read %s", filename);
|
||||
} else {
|
||||
lovrAssert(glb, "Buffer is missing URI");
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "data/modelData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "lib/math.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
#include "data/vertexData.h"
|
||||
#include <string.h>
|
||||
|
||||
static const size_t attributeTypeSizes[] = {
|
||||
[I8] = 1,
|
||||
[U8] = 1,
|
||||
[I16] = 2,
|
||||
[U16] = 2,
|
||||
[I32] = 4,
|
||||
[U32] = 4,
|
||||
[F32] = 4
|
||||
};
|
||||
|
||||
void vertexFormatInit(VertexFormat* format) {
|
||||
memset(format, 0, sizeof(*format));
|
||||
}
|
||||
|
||||
void vertexFormatAppend(VertexFormat* format, const char* name, AttributeType type, int count) {
|
||||
size_t size = attributeTypeSizes[type];
|
||||
Attribute attribute = { name, type, count, size, format->stride };
|
||||
format->attributes[format->count++] = attribute;
|
||||
format->stride += size * count;
|
||||
}
|
||||
|
||||
VertexData* lovrVertexDataInit(VertexData* vertexData, uint32_t count, VertexFormat* format) {
|
||||
if (format) {
|
||||
vertexData->format = *format;
|
||||
} else {
|
||||
format = &vertexData->format;
|
||||
vertexFormatInit(&vertexData->format);
|
||||
vertexFormatAppend(&vertexData->format, "lovrPosition", F32, 3);
|
||||
vertexFormatAppend(&vertexData->format, "lovrNormal", F32, 3);
|
||||
vertexFormatAppend(&vertexData->format, "lovrTexCoord", F32, 2);
|
||||
vertexFormatAppend(&vertexData->format, "lovrVertexColor", U8, 4);
|
||||
}
|
||||
|
||||
size_t size = format->stride * count;
|
||||
vertexData->blob.data = calloc(1, size);
|
||||
vertexData->blob.size = size;
|
||||
vertexData->count = count;
|
||||
|
||||
return vertexData;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#include "blob.h"
|
||||
#include "data/modelData.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
AttributeType type;
|
||||
int count;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
} Attribute;
|
||||
|
||||
typedef struct {
|
||||
Attribute attributes[8];
|
||||
size_t stride;
|
||||
int count;
|
||||
} VertexFormat;
|
||||
|
||||
typedef union {
|
||||
void* raw;
|
||||
int8_t* i8;
|
||||
uint8_t* u8;
|
||||
int16_t* i16;
|
||||
uint16_t* u16;
|
||||
int32_t* i32;
|
||||
uint32_t* u32;
|
||||
float* f32;
|
||||
} AttributePointer;
|
||||
|
||||
typedef union {
|
||||
void* raw;
|
||||
uint16_t* shorts;
|
||||
uint32_t* ints;
|
||||
} IndexPointer;
|
||||
|
||||
typedef struct {
|
||||
Blob blob;
|
||||
VertexFormat format;
|
||||
uint32_t count;
|
||||
} VertexData;
|
||||
|
||||
void vertexFormatInit(VertexFormat* format);
|
||||
void vertexFormatAppend(VertexFormat* format, const char* name, AttributeType type, int count);
|
||||
|
||||
VertexData* lovrVertexDataInit(VertexData* vertexData, uint32_t count, VertexFormat* format);
|
||||
#define lovrVertexDataCreate(...) lovrVertexDataInit(lovrAlloc(VertexData), __VA_ARGS__)
|
||||
#define lovrVertexDataDestroy NULL
|
|
@ -67,22 +67,22 @@ static void lovrGraphicsInitBuffers() {
|
|||
for (int i = 0; i < 256; i++) id[i] = i;
|
||||
lovrBufferFlushRange(state.identityBuffer, 0, 256);
|
||||
|
||||
VertexFormat empty = { .count = 0 };
|
||||
Buffer* vertexBuffer = state.buffers[STREAM_VERTEX];
|
||||
size_t stride = BUFFER_STRIDES[STREAM_VERTEX];
|
||||
MeshAttribute position = { vertexBuffer, 0, stride, F32, 3, .enabled = true };
|
||||
MeshAttribute normal = { vertexBuffer, 12, stride, F32, 3, .enabled = true };
|
||||
MeshAttribute texCoord = { vertexBuffer, 24, stride, F32, 2, .enabled = true };
|
||||
MeshAttribute drawId = { state.buffers[STREAM_DRAW_ID], 0, 0, U8, 1, .integer = true, .enabled = true };
|
||||
MeshAttribute identity = { state.identityBuffer, 0, 0, U8, 1, .divisor = 1, .integer = true, .enabled = true };
|
||||
|
||||
state.mesh = lovrMeshCreate(DRAW_TRIANGLES, empty, NULL, 0);
|
||||
MeshAttribute position = { .buffer = vertexBuffer, .offset = 0, .stride = stride, .type = F32, .components = 3 };
|
||||
MeshAttribute normal = { .buffer = vertexBuffer, .offset = 12, .stride = stride, .type = F32, .components = 3 };
|
||||
MeshAttribute texCoord = { .buffer = vertexBuffer, .offset = 24, .stride = stride, .type = F32, .components = 2 };
|
||||
MeshAttribute drawId = { .buffer = state.buffers[STREAM_DRAW_ID], .type = U8, .components = 1, .integer = true };
|
||||
MeshAttribute identity = { .buffer = state.identityBuffer, .type = U8, .components = 1, .divisor = 1, .integer = true };
|
||||
|
||||
state.mesh = lovrMeshCreate(DRAW_TRIANGLES, NULL, 0);
|
||||
lovrMeshAttachAttribute(state.mesh, "lovrPosition", &position);
|
||||
lovrMeshAttachAttribute(state.mesh, "lovrNormal", &normal);
|
||||
lovrMeshAttachAttribute(state.mesh, "lovrTexCoord", &texCoord);
|
||||
lovrMeshAttachAttribute(state.mesh, "lovrDrawID", &drawId);
|
||||
|
||||
state.instancedMesh = lovrMeshCreate(DRAW_TRIANGLES, empty, NULL, 0);
|
||||
state.instancedMesh = lovrMeshCreate(DRAW_TRIANGLES, NULL, 0);
|
||||
lovrMeshAttachAttribute(state.instancedMesh, "lovrPosition", &position);
|
||||
lovrMeshAttachAttribute(state.instancedMesh, "lovrNormal", &normal);
|
||||
lovrMeshAttachAttribute(state.instancedMesh, "lovrTexCoord", &texCoord);
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#include "graphics/mesh.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
|
||||
return &mesh->format;
|
||||
}
|
||||
|
||||
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh) {
|
||||
return mesh->vertexBuffer;
|
||||
}
|
||||
|
@ -25,39 +21,59 @@ size_t lovrMeshGetIndexSize(Mesh* mesh) {
|
|||
return mesh->indexSize;
|
||||
}
|
||||
|
||||
int lovrMeshGetAttributeCount(Mesh* mesh) {
|
||||
return mesh->attributeCount;
|
||||
}
|
||||
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
|
||||
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
||||
lovrAssert(!map_get(&mesh->attributeMap, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(mesh->attributeCount < MAX_ATTRIBUTES, "Mesh already has the max number of attributes (%d)", MAX_ATTRIBUTES);
|
||||
lovrGraphicsFlushMesh(mesh);
|
||||
map_set(&mesh->attributes, name, *attribute);
|
||||
int index = mesh->attributeCount++;
|
||||
mesh->attributes[index] = *attribute;
|
||||
mesh->attributeNames[index] = name;
|
||||
map_set(&mesh->attributeMap, name, index);
|
||||
lovrRetain(attribute->buffer);
|
||||
}
|
||||
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "No attached attribute '%s' was found", name);
|
||||
lovrAssert(attribute->buffer != mesh->vertexBuffer, "Attribute '%s' was not attached from another Mesh", name);
|
||||
int* index = map_get(&mesh->attributeMap, name);
|
||||
lovrAssert(index, "No attached attribute named '%s' was found", name);
|
||||
MeshAttribute* attribute = &mesh->attributes[*index];
|
||||
lovrGraphicsFlushMesh(mesh);
|
||||
lovrRelease(attribute->buffer);
|
||||
map_remove(&mesh->attributes, name);
|
||||
map_remove(&mesh->attributeMap, name);
|
||||
mesh->attributeNames[*index] = NULL;
|
||||
memmove(mesh->attributeNames + *index, mesh->attributeNames + *index + 1, (mesh->attributeCount - *index - 1) * sizeof(char*));
|
||||
memmove(mesh->attributes + *index, mesh->attributes + *index + 1, (mesh->attributeCount - *index - 1) * sizeof(MeshAttribute));
|
||||
mesh->attributeCount--;
|
||||
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
|
||||
if (mesh->locations[i] > *index) {
|
||||
mesh->locations[i]--;
|
||||
} else if (mesh->locations[i] == *index) {
|
||||
mesh->locations[i] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
|
||||
return map_get(&mesh->attributes, name);
|
||||
const MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
|
||||
int* index = map_get(&mesh->attributeMap, name);
|
||||
return index ? &mesh->attributes[*index] : NULL;
|
||||
}
|
||||
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
return attribute->enabled;
|
||||
int* index = map_get(&mesh->attributeMap, name);
|
||||
lovrAssert(index, "Mesh does not have an attribute named '%s'", name);
|
||||
return !mesh->attributes[*index].disabled;
|
||||
}
|
||||
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
if (attribute->enabled != enable) {
|
||||
bool disable = !enable;
|
||||
int* index = map_get(&mesh->attributeMap, name);
|
||||
lovrAssert(index, "Mesh does not have an attribute named '%s'", name);
|
||||
if (mesh->attributes[*index].disabled != disable) {
|
||||
lovrGraphicsFlushMesh(mesh);
|
||||
attribute->enabled = enable;
|
||||
mesh->attributes[*index].disabled = disable;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "graphics/material.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/opengl.h"
|
||||
#include "data/vertexData.h"
|
||||
#include "lib/map/map.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -12,21 +11,26 @@
|
|||
|
||||
typedef struct {
|
||||
Buffer* buffer;
|
||||
size_t offset;
|
||||
size_t stride;
|
||||
AttributeType type;
|
||||
uint8_t components;
|
||||
uint8_t divisor;
|
||||
bool integer;
|
||||
bool enabled;
|
||||
uint32_t offset;
|
||||
unsigned stride : 8;
|
||||
unsigned divisor : 8;
|
||||
unsigned type : 3; // AttributeType
|
||||
unsigned components : 3;
|
||||
unsigned normalized : 1;
|
||||
unsigned integer : 1;
|
||||
unsigned disabled : 1;
|
||||
} MeshAttribute;
|
||||
|
||||
typedef map_t(MeshAttribute) map_attribute_t;
|
||||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
DrawMode mode;
|
||||
VertexFormat format;
|
||||
const char* attributeNames[MAX_ATTRIBUTES];
|
||||
MeshAttribute attributes[MAX_ATTRIBUTES];
|
||||
uint8_t locations[MAX_ATTRIBUTES];
|
||||
uint16_t enabledLocations;
|
||||
uint16_t divisors[MAX_ATTRIBUTES];
|
||||
map_int_t attributeMap;
|
||||
int attributeCount;
|
||||
Buffer* vertexBuffer;
|
||||
Buffer* indexBuffer;
|
||||
uint32_t vertexCount;
|
||||
|
@ -36,18 +40,12 @@ typedef struct {
|
|||
uint32_t drawStart;
|
||||
uint32_t drawCount;
|
||||
Material* material;
|
||||
map_attribute_t attributes;
|
||||
MeshAttribute layout[MAX_ATTRIBUTES];
|
||||
uint16_t divisors[MAX_ATTRIBUTES];
|
||||
GPU_MESH_FIELDS
|
||||
} Mesh;
|
||||
|
||||
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer, uint32_t vertexCount);
|
||||
Mesh* lovrMeshInitEmpty(Mesh* mesh, DrawMode drawMode);
|
||||
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, Buffer* vertexBuffer, uint32_t vertexCount);
|
||||
#define lovrMeshCreate(...) lovrMeshInit(lovrAlloc(Mesh), __VA_ARGS__)
|
||||
#define lovrMeshCreateEmpty(...) lovrMeshInitEmpty(lovrAlloc(Mesh), __VA_ARGS__)
|
||||
void lovrMeshDestroy(void* ref);
|
||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
|
||||
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh);
|
||||
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh);
|
||||
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer, uint32_t indexCount, size_t indexSize, size_t offset);
|
||||
|
@ -56,7 +54,7 @@ uint32_t lovrMeshGetIndexCount(Mesh* mesh);
|
|||
size_t lovrMeshGetIndexSize(Mesh* mesh);
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute);
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
|
||||
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
|
||||
const MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enabled);
|
||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
||||
|
|
|
@ -80,7 +80,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
|||
model->meshes = calloc(data->primitiveCount, sizeof(Mesh*));
|
||||
for (int i = 0; i < data->primitiveCount; i++) {
|
||||
ModelPrimitive* primitive = &data->primitives[i];
|
||||
model->meshes[i] = lovrMeshCreateEmpty(primitive->mode);
|
||||
model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, 0);
|
||||
|
||||
bool setDrawRange = false;
|
||||
for (int j = 0; j < MAX_DEFAULT_ATTRIBUTES; j++) {
|
||||
|
@ -98,8 +98,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
|||
.stride = data->buffers[attribute->buffer].stride,
|
||||
.type = attribute->type,
|
||||
.components = attribute->components,
|
||||
.integer = j == ATTR_BONES,
|
||||
.enabled = true
|
||||
.integer = j == ATTR_BONES
|
||||
});
|
||||
|
||||
if (!setDrawRange && !primitive->indices) {
|
||||
|
@ -114,8 +113,7 @@ Model* lovrModelInit(Model* model, ModelData* data) {
|
|||
.type = U8,
|
||||
.components = 1,
|
||||
.divisor = 1,
|
||||
.integer = true,
|
||||
.enabled = true
|
||||
.integer = true
|
||||
});
|
||||
|
||||
if (primitive->indices) {
|
||||
|
|
|
@ -479,19 +479,13 @@ static void lovrGpuBindImage(Image* image, int slot) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attachments);
|
||||
|
||||
MeshAttribute layout[MAX_ATTRIBUTES];
|
||||
memset(layout, 0, MAX_ATTRIBUTES * sizeof(MeshAttribute));
|
||||
|
||||
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int baseDivisor) {
|
||||
lovrGpuBindVertexArray(mesh);
|
||||
|
||||
if (mesh->indexBuffer && mesh->indexCount > 0) {
|
||||
lovrGpuBindBuffer(BUFFER_INDEX, mesh->indexBuffer->id);
|
||||
lovrBufferFlush(mesh->indexBuffer);
|
||||
#ifndef LOVR_GL
|
||||
#ifdef LOVR_GL
|
||||
uint32_t primitiveRestart = mesh->indexSize == 4 ? 0xffffffff : 0xffff;
|
||||
if (state.primitiveRestart != primitiveRestart) {
|
||||
state.primitiveRestart = primitiveRestart;
|
||||
|
@ -500,68 +494,51 @@ static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
|||
#endif
|
||||
}
|
||||
|
||||
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
|
||||
int location = lovrShaderGetAttributeId(shader, key);
|
||||
uint16_t enabledLocations = 0;
|
||||
for (int i = 0; i < mesh->attributeCount; i++) {
|
||||
MeshAttribute* attribute;
|
||||
int location;
|
||||
|
||||
if (location >= 0) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, key);
|
||||
layout[location] = *attribute;
|
||||
if ((attribute = &mesh->attributes[i])->disabled) { continue; }
|
||||
if ((location = lovrShaderGetAttributeLocation(shader, mesh->attributeNames[i])) < 0) { continue; }
|
||||
|
||||
lovrBufferFlush(attribute->buffer);
|
||||
enabledLocations |= (1 << location);
|
||||
|
||||
uint16_t divisor = attribute->divisor * baseDivisor;
|
||||
if (mesh->divisors[location] != divisor) {
|
||||
glVertexAttribDivisor(location, divisor);
|
||||
mesh->divisors[location] = divisor;
|
||||
}
|
||||
|
||||
if (mesh->locations[location] == i) { continue; }
|
||||
|
||||
mesh->locations[location] = i;
|
||||
lovrGpuBindBuffer(BUFFER_VERTEX, attribute->buffer->id);
|
||||
GLenum type = convertAttributeType(attribute->type);
|
||||
GLvoid* offset = (GLvoid*) (intptr_t) attribute->offset;
|
||||
|
||||
if (attribute->integer) {
|
||||
glVertexAttribIPointer(location, attribute->components, type, attribute->stride, offset);
|
||||
} else {
|
||||
glVertexAttribPointer(location, attribute->components, type, attribute->normalized, attribute->stride, offset);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
|
||||
MeshAttribute previous = mesh->layout[i];
|
||||
MeshAttribute current = layout[i];
|
||||
|
||||
if (current.enabled) {
|
||||
lovrBufferFlush(current.buffer);
|
||||
}
|
||||
|
||||
uint16_t divisor = current.divisor * divisorMultiplier;
|
||||
|
||||
if (!memcmp(&previous, ¤t, sizeof(MeshAttribute)) && mesh->divisors[i] == divisor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (previous.enabled != current.enabled) {
|
||||
if (current.enabled) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
mesh->layout[i] = current;
|
||||
continue;
|
||||
uint16_t diff = enabledLocations ^ mesh->enabledLocations;
|
||||
if (diff != 0) {
|
||||
for (int i = 0; i < MAX_ATTRIBUTES; i++) {
|
||||
if (diff & (1 << i)) {
|
||||
if (enabledLocations & (1 << i)) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->divisors[i] != divisor) {
|
||||
glVertexAttribDivisor(i, divisor);
|
||||
mesh->divisors[i] = divisor;
|
||||
}
|
||||
|
||||
bool changed =
|
||||
previous.buffer != current.buffer ||
|
||||
previous.type != current.type ||
|
||||
previous.components != current.components ||
|
||||
previous.offset != current.offset ||
|
||||
previous.stride != current.stride;
|
||||
|
||||
if (changed) {
|
||||
lovrGpuBindBuffer(BUFFER_VERTEX, current.buffer->id);
|
||||
int count = current.components;
|
||||
int stride = current.stride;
|
||||
GLvoid* offset = (GLvoid*) current.offset;
|
||||
GLenum type = convertAttributeType(current.type);
|
||||
|
||||
// TODO
|
||||
if (current.integer) {
|
||||
glVertexAttribIPointer(i, count, type, stride, offset);
|
||||
} else {
|
||||
glVertexAttribPointer(i, count, type, GL_TRUE, stride, offset);
|
||||
}
|
||||
}
|
||||
mesh->enabledLocations = enabledLocations;
|
||||
}
|
||||
|
||||
memcpy(mesh->layout, layout, MAX_ATTRIBUTES * sizeof(MeshAttribute));
|
||||
}
|
||||
|
||||
static void lovrGpuBindCanvas(Canvas* canvas, bool willDraw) {
|
||||
|
@ -1962,34 +1939,14 @@ void lovrShaderDestroy(void* ref) {
|
|||
|
||||
// Mesh
|
||||
|
||||
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer, uint32_t vertexCount) {
|
||||
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, Buffer* vertexBuffer, uint32_t vertexCount) {
|
||||
mesh->mode = mode;
|
||||
mesh->format = format;
|
||||
mesh->vertexBuffer = vertexBuffer;
|
||||
mesh->vertexCount = vertexCount;
|
||||
lovrRetain(mesh->vertexBuffer);
|
||||
glGenVertexArrays(1, &mesh->vao);
|
||||
|
||||
map_init(&mesh->attributes);
|
||||
for (int i = 0; i < format.count; i++) {
|
||||
lovrRetain(mesh->vertexBuffer);
|
||||
map_set(&mesh->attributes, format.attributes[i].name, ((MeshAttribute) {
|
||||
.buffer = mesh->vertexBuffer,
|
||||
.offset = format.attributes[i].offset,
|
||||
.stride = format.stride,
|
||||
.type = format.attributes[i].type,
|
||||
.components = format.attributes[i].count,
|
||||
.enabled = true
|
||||
}));
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Mesh* lovrMeshInitEmpty(Mesh* mesh, DrawMode mode) {
|
||||
mesh->mode = mode;
|
||||
glGenVertexArrays(1, &mesh->vao);
|
||||
map_init(&mesh->attributes);
|
||||
map_init(&mesh->attributeMap);
|
||||
memset(mesh->locations, 0xff, MAX_ATTRIBUTES * sizeof(uint8_t));
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@ -1997,13 +1954,10 @@ void lovrMeshDestroy(void* ref) {
|
|||
Mesh* mesh = ref;
|
||||
lovrGraphicsFlushMesh(mesh);
|
||||
glDeleteVertexArrays(1, &mesh->vao);
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attributes);
|
||||
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, key);
|
||||
lovrRelease(attribute->buffer);
|
||||
for (int i = 0; i < mesh->attributeCount; i++) {
|
||||
lovrRelease(mesh->attributes[i].buffer);
|
||||
}
|
||||
map_deinit(&mesh->attributes);
|
||||
map_deinit(&mesh->attributeMap);
|
||||
lovrRelease(mesh->vertexBuffer);
|
||||
lovrRelease(mesh->indexBuffer);
|
||||
lovrRelease(mesh->material);
|
||||
|
|
|
@ -71,9 +71,9 @@ ShaderType lovrShaderGetType(Shader* shader) {
|
|||
return shader->type;
|
||||
}
|
||||
|
||||
int lovrShaderGetAttributeId(Shader* shader, const char* name) {
|
||||
int* id = map_get(&shader->attributes, name);
|
||||
return id ? *id : -1;
|
||||
int lovrShaderGetAttributeLocation(Shader* shader, const char* name) {
|
||||
int* location = map_get(&shader->attributes, name);
|
||||
return location ? *location : -1;
|
||||
}
|
||||
|
||||
bool lovrShaderHasUniform(Shader* shader, const char* name) {
|
||||
|
|
|
@ -114,7 +114,7 @@ Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type);
|
|||
#define lovrShaderCreateDefault(...) lovrShaderInitDefault(lovrAlloc(Shader), __VA_ARGS__)
|
||||
void lovrShaderDestroy(void* ref);
|
||||
ShaderType lovrShaderGetType(Shader* shader);
|
||||
int lovrShaderGetAttributeId(Shader* shader, const char* name);
|
||||
int lovrShaderGetAttributeLocation(Shader* shader, const char* name);
|
||||
bool lovrShaderHasUniform(Shader* shader, const char* name);
|
||||
const Uniform* lovrShaderGetUniform(Shader* shader, const char* name);
|
||||
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count);
|
||||
|
|
Loading…
Reference in New Issue