Skip to content

Commit

Permalink
Rework Buffer formats;
Browse files Browse the repository at this point in the history
Summary:

- Buffer length can be zero (indicates single value instead of array)
- Internally, arrays aren't coerced to array-of-single-struct
- Removes support for "flat table" data (array-of-structs w/o wrapping
  each struct in a nested table)
- Use consistent syntax for reading table data into buffers:
  - Numbers are numbers
  - Vectors are numbers, tables, or vectors
  - Structs are tables with any combination of integer/string keys
    - Fields are assigned from integer keys in order, then any remaining
      fields use the string keys
  - Arrays are tables of elements, formatted as above
- Try to improve error messages for Buffer:setData errors
  • Loading branch information
bjornbytes committed Apr 18, 2024
1 parent e08217e commit a784321
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 413 deletions.
11 changes: 2 additions & 9 deletions src/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,10 @@ bool luax_writefile(const char* filename, const void* data, size_t size);
struct DataField;
struct Material;
struct ColoredString;
void luax_checkfieldn(lua_State* L, int index, int type, void* data);
void luax_checkfieldv(lua_State* L, int index, int type, void* data);
void luax_checkfieldt(lua_State* L, int index, int type, void* data);
uint32_t luax_checkfieldarray(lua_State* L, int index, const struct DataField* array, char* data);
void luax_checkdataflat(lua_State* L, int index, int subindex, uint32_t count, const struct DataField* format, char* data);
void luax_checkdatatuples(lua_State* L, int index, int start, uint32_t count, const struct DataField* format, char* data);
void luax_checkdatakeys(lua_State* L, int index, int start, uint32_t count, const struct DataField* array, char* data);
void luax_checkstruct(lua_State* L, int index, const struct DataField* fields, uint32_t count, char* data);
void luax_checkbufferdata(lua_State* L, int index, const struct DataField* format, char* data);
int luax_pushbufferdata(lua_State* L, const struct DataField* format, uint32_t count, char* data);
void luax_pushbufferformat(lua_State* L, const struct DataField* fields, uint32_t count);
uint32_t luax_gettablestride(lua_State* L, int index, int subindex, struct DataField* fields, uint32_t count);
int luax_gettablestride(lua_State* L, int type);
uint32_t luax_checkcomparemode(lua_State* L, int index);
struct Material* luax_optmaterial(lua_State* L, int index);
struct ColoredString* luax_checkcoloredstrings(lua_State* L, int index, uint32_t* count, struct ColoredString* stack);
Expand Down
50 changes: 18 additions & 32 deletions src/api/l_graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,12 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
lovrCheck(blob->size < UINT32_MAX, "Blob is too big to create a Buffer");
info.size = (uint32_t) blob->size;
} else if (type == LUA_TSTRING) {
info.fieldCount = 2;
info.fieldCount = 1;
info.format = format;
format[0] = (DataField) { .fieldCount = 1 };
format[1] = (DataField) { .type = luax_checkdatatype(L, 1) };
format[0] = (DataField) { .type = luax_checkdatatype(L, 1) };
} else if (type == LUA_TTABLE) {
info.format = format;
format[0] = (DataField) { .fieldCount = luax_len(L, 1) };
format[0] = (DataField) { .fieldCount = luax_len(L, 1), .fields = format + 1 };

lua_rawgeti(L, 1, 1);
bool anonymous = lua_type(L, -1) == LUA_TSTRING;
Expand All @@ -646,6 +645,12 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
format[i] = (DataField) { .type = luax_checkdatatype(L, -1) };
lua_pop(L, 1);
}

// Convert single-field anonymous formats to regular arrays
if (format->fieldCount == 1) {
format->type = format[1].type;
format->fieldCount = 0;
}
} else {
info.fieldCount = 1;
luax_checkbufferformat(L, 1, format, &info.fieldCount, COUNTOF(format));
Expand All @@ -664,19 +669,18 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {

// Length/size
if (info.format) {
format->fields = format + 1;
lovrGraphicsAlignFields(format, layout);
switch (lua_type(L, 2)) {
case LUA_TNIL: case LUA_TNONE: format->length = 1; break;
case LUA_TNIL: case LUA_TNONE: format->length = 0; break;
case LUA_TNUMBER: format->length = luax_checku32(L, 2); break;
case LUA_TTABLE:
lua_rawgeti(L, 2, 1);
if (lua_istable(L, -1)) {
format->length = luax_len(L, -2);
} else if (lua_isnil(L, -1) && format->fields[0].name) {
format->length = 1;
if (lua_type(L, -1) == LUA_TNUMBER) {
lovrCheck(format->fieldCount <= 1, "Struct data must be provided as a table of tables");
DataType type = format->fieldCount == 0 ? format->type : format->fields[0].type;
format->length = luax_len(L, -2) / luax_gettablestride(L, type);
} else {
format->length = luax_len(L, -2) / luax_gettablestride(L, 2, 1, format->fields, format->fieldCount);
format->length = luax_len(L, -2);
}
lua_pop(L, 1);
hasData = true;
Expand All @@ -688,7 +692,7 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
format->length = info.size / format->stride;
break;
} else if (luax_tovector(L, 2, NULL)) {
format->length = 1;
format->length = 0;
hasData = true;
break;
}
Expand All @@ -703,25 +707,7 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
if (blob) {
memcpy(data, blob->data, info.size);
} else if (hasData) {
if (luax_tovector(L, 2, NULL)) {
luax_checkfieldv(L, 2, format->fields[0].type, data);
} else if (luax_len(L, 2) == 0 && format->fields[0].name) {
luax_checkstruct(L, 2, format->fields, format->fieldCount, data);
} else {
lua_rawgeti(L, 2, 1);
bool complexFormat = lovrBufferGetInfo(buffer)->complexFormat;
bool tableOfTables = complexFormat || lua_istable(L, -1);
bool tuples = tableOfTables && !complexFormat && (luax_len(L, -1) > 0 || !format->fields[0].name);
lua_pop(L, 1);

if (tuples) {
luax_checkdatatuples(L, 2, 1, format->length, format, data);
} else if (tableOfTables) {
luax_checkdatakeys(L, 2, 1, format->length, format, data);
} else {
luax_checkdataflat(L, 2, 1, format->length, format, data);
}
}
luax_checkbufferdata(L, 2, format, data);
}

luax_pushtype(L, Buffer, buffer);
Expand Down Expand Up @@ -1403,7 +1389,7 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
if (blob) {
memcpy(vertices, blob->data, blob->size);
} else if (hasData) {
luax_checkdatatuples(L, index, 1, format->length, lovrMeshGetVertexFormat(mesh), vertices);
luax_checkbufferdata(L, index, lovrMeshGetVertexFormat(mesh), vertices);
}

luax_pushtype(L, Mesh, mesh);
Expand Down
Loading

0 comments on commit a784321

Please sign in to comment.