diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index 8929eaa57..6f4996d10 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -48,6 +48,9 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector= t->getArrayLength()) return luaL_error(L, "Invalid Buffer element index: %ld", index); - size_t offset = index * t->getArrayStride(); + size_t stride = t->getArrayStride(); + size_t offset = index * stride; char *data = (char *) t->map() + offset; const auto &members = t->getDataMembers(); @@ -350,6 +349,7 @@ static int w_Buffer_setElement(lua_State *L) } } + t->setMappedRangeModified(offset, stride); return 0; } diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 90a1d6595..ec897c9ec 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -1514,6 +1515,192 @@ static void luax_optbuffersettings(lua_State *L, int idx, Buffer::Settings &sett settings.mapFlags = (Buffer::MapFlags)(settings.mapFlags & (~Buffer::MAP_READ)); } +static void luax_checkbufferformat(lua_State *L, int idx, std::vector &format) +{ + luaL_checktype(L, idx, LUA_TTABLE); + int tablelen = luax_objlen(L, idx); + + for (int i = 1; i <= tablelen; i++) + { + lua_rawgeti(L, idx, i); + luaL_checktype(L, -1, LUA_TTABLE); + + Buffer::DataDeclaration decl("", DATAFORMAT_MAX_ENUM); + + lua_getfield(L, -1, "name"); + if (lua_type(L, -1) != LUA_TSTRING) + { + std::ostringstream ss; + ss << "'name' field expected in array element #"; + ss << i; + ss << " of format table"; + std::string str = ss.str(); + luaL_argerror(L, idx, str.c_str()); + } + decl.name = luax_checkstring(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "format"); + if (lua_type(L, -1) != LUA_TSTRING) + { + std::ostringstream ss; + ss << "'format' field expected in array element #"; + ss << i; + ss << " of format table"; + std::string str = ss.str(); + luaL_argerror(L, idx, str.c_str()); + } + const char *formatstr = luaL_checkstring(L, -1); + if (!getConstant(formatstr, decl.format)) + luax_enumerror(L, "data format", getConstants(decl.format), formatstr); + lua_pop(L, 1); + + decl.arrayLength = luax_intflag(L, -1, "arraylength", 0); + + format.push_back(decl); + lua_pop(L, 1); + } +} + +static Buffer *luax_newbuffer(lua_State *L, int idx, const Buffer::Settings &settings, const std::vector &format) +{ + size_t arraylength = 0; + size_t bytesize = 0; + Data *data = nullptr; + const void *initialdata = nullptr; + + int ncomponents = 0; + for (const Buffer::DataDeclaration &decl : format) + ncomponents += getDataFormatInfo(decl.format).components; + + if (luax_istype(L, idx, Data::type)) + { + data = luax_checktype(L, idx); + initialdata = data->getData(); + bytesize = data->getSize(); + } + + bool tableoftables = false; + + if (lua_istable(L, idx)) + { + arraylength = luax_objlen(L, idx); + + lua_rawgeti(L, idx, 1); + tableoftables = lua_istable(L, -1); + lua_pop(L, 1); + + if (!tableoftables) + { + if (arraylength % ncomponents != 0) + luaL_error(L, "Array length in flat array variant of newBuffer must be a multiple of the total number of components (%d)", ncomponents); + arraylength /= ncomponents; + } + } + else if (data == nullptr) + { + lua_Integer len = luaL_checkinteger(L, idx); + if (len <= 0) + luaL_argerror(L, idx, "number of elements must be greater than 0"); + arraylength = (size_t) len; + } + + Buffer *b = nullptr; + luax_catchexcept(L, [&] { b = instance()->newBuffer(settings, format, initialdata, bytesize, arraylength); }); + + if (lua_istable(L, idx)) + { + Buffer::Mapper mapper(*b); + char *data = (char *) mapper.data; + const auto &members = b->getDataMembers(); + size_t stride = b->getArrayStride(); + + if (tableoftables) + { + for (size_t i = 0; i < arraylength; i++) + { + // get arraydata[index] + lua_rawgeti(L, 2, i + 1); + luaL_checktype(L, -1, LUA_TTABLE); + + // get arraydata[index][j] + for (int j = 1; j <= ncomponents; j++) + lua_rawgeti(L, -j, j); + + int idx = -ncomponents; + + for (const Buffer::DataMember &member : members) + { + luax_writebufferdata(L, idx, member.decl.format, data + member.offset); + idx += member.info.components; + } + + lua_pop(L, ncomponents + 1); + data += stride; + } + } + else // Flat array + { + for (size_t i = 0; i < arraylength; i++) + { + // get arraydata[arrayindex * ncomponents + componentindex] + for (int componentindex = 1; componentindex <= ncomponents; componentindex++) + lua_rawgeti(L, 2, i * ncomponents + componentindex); + + int idx = -ncomponents; + + for (const Buffer::DataMember &member : members) + { + luax_writebufferdata(L, idx, member.decl.format, data + member.offset); + idx += member.info.components; + } + + lua_pop(L, ncomponents); + data += stride; + } + } + } + + return b; +} + +int w_newBuffer(lua_State *L) +{ + Buffer::Settings settings(0, Buffer::MAP_EXPLICIT_RANGE_MODIFY, BUFFERUSAGE_DYNAMIC); + + luaL_checktype(L, 3, LUA_TTABLE); + if (luax_boolflag(L, 3, "vertex", false)) + settings.typeFlags = (Buffer::TypeFlags)(settings.typeFlags | Buffer::TYPEFLAG_VERTEX); + if (luax_boolflag(L, 3, "index", false)) + settings.typeFlags = (Buffer::TypeFlags)(settings.typeFlags | Buffer::TYPEFLAG_INDEX); + + luax_optbuffersettings(L, 3, settings); + + std::vector format; + luax_checkbufferformat(L, 1, format); + + Buffer *b = luax_newbuffer(L, 2, settings, format); + + luax_pushtype(L, b); + b->release(); + return 1; +} + +int w_newVertexBuffer(lua_State *L) +{ + Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, Buffer::MAP_EXPLICIT_RANGE_MODIFY, BUFFERUSAGE_DYNAMIC); + luax_optbuffersettings(L, 3, settings); + + std::vector format; + luax_checkbufferformat(L, 1, format); + + Buffer *b = luax_newbuffer(L, 2, settings, format); + + luax_pushtype(L, b); + b->release(); + return 1; +} + int w_newIndexBuffer(lua_State *L) { Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, Buffer::MAP_EXPLICIT_RANGE_MODIFY, BUFFERUSAGE_DYNAMIC); @@ -1534,7 +1721,7 @@ int w_newIndexBuffer(lua_State *L) if (lua_istable(L, 1)) { - arraylength = (size_t) luax_objlen(L, 1); + arraylength = luax_objlen(L, 1); // Scan array for invalid types and the max value. lua_Integer maxvalue = 0; @@ -3192,6 +3379,8 @@ static const luaL_Reg functions[] = { "newSpriteBatch", w_newSpriteBatch }, { "newParticleSystem", w_newParticleSystem }, { "newShader", w_newShader }, + { "newBuffer", w_newBuffer }, + { "newVertexBuffer", w_newVertexBuffer }, { "newIndexBuffer", w_newIndexBuffer }, { "newMesh", w_newMesh }, { "newText", w_newText },