Browse Source

Add Buffer methods

flush, setArrayData, setElement, getElement, getElementCount, getElementStride, getSize, getFormat
Alex Szpakowski 5 years ago
parent
commit
d75f5df80d

+ 1 - 1
src/modules/graphics/Buffer.cpp

@@ -69,7 +69,7 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
 
 		if (vertexbuffer)
 		{
-			if (decl.arraySize > 0)
+			if (decl.arrayLength > 0)
 				throw love::Exception("Arrays are not supported in vertex buffers.");
 
 			if (info.isMatrix)

+ 3 - 3
src/modules/graphics/Buffer.h

@@ -66,12 +66,12 @@ public:
 	{
 		std::string name;
 		DataFormat format;
-		int arraySize;
+		int arrayLength;
 
-		DataDeclaration(const std::string &name, DataFormat format, int arraySize = 0)
+		DataDeclaration(const std::string &name, DataFormat format, int arrayLength = 0)
 			: name(name)
 			, format(format)
-			, arraySize(arraySize)
+			, arrayLength(arrayLength)
 		{}
 	};
 

+ 1 - 1
src/modules/graphics/opengl/Buffer.cpp

@@ -200,7 +200,7 @@ void Buffer::setMappedRangeModified(size_t offset, size_t modifiedsize)
 	if (!isMappedDataModified)
 	{
 		modifiedOffset = offset;
-		modifiedSize = size;
+		modifiedSize = modifiedsize;
 		isMappedDataModified = true;
 		return;
 	}

+ 255 - 0
src/modules/graphics/wrap_Buffer.cpp

@@ -20,6 +20,7 @@
 
 #include "wrap_Buffer.h"
 #include "Buffer.h"
+#include "common/Data.h"
 
 namespace love
 {
@@ -185,8 +186,262 @@ Buffer *luax_checkbuffer(lua_State *L, int idx)
 	return luax_checktype<Buffer>(L, idx);
 }
 
+static int w_Buffer_flush(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	t->unmap();
+	return 0;
+}
+
+static int w_Buffer_setArrayData(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+
+	int startindex = (int) luaL_optnumber(L, 3, 1) - 1;
+
+	int count = -1;
+	if (!lua_isnoneornil(L, 4))
+	{
+		count = (int) luaL_checknumber(L, 4);
+		if (count <= 0)
+			return luaL_error(L, "Element count must be greater than 0.");
+	}
+
+	size_t stride = t->getArrayStride();
+	size_t offset = startindex * stride;
+	int arraylength = (int) t->getArrayLength();
+
+	if (startindex >= arraylength || startindex < 0)
+		return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", arraylength);
+
+	if (luax_istype(L, 2, Data::type))
+	{
+		Data *d = luax_checktype<Data>(L, 2);
+
+		count = count >= 0 ? count : (arraylength - startindex);
+		if (startindex + count > arraylength)
+			return luaL_error(L, "Too many array elements (expected at most %d, got %d)", arraylength - startindex, count);
+
+		size_t datasize = std::min(d->getSize(), count * stride);
+		char *bytedata = (char *) t->map() + offset;
+
+		memcpy(bytedata, d->getData(), datasize);
+
+		t->setMappedRangeModified(offset, datasize);
+		t->unmap();
+		return 0;
+	}
+
+	const std::vector<Buffer::DataMember> &members = t->getDataMembers();
+
+	int ncomponents = 0;
+	for (const Buffer::DataMember &member : members)
+		ncomponents += member.info.components;
+
+	luaL_checktype(L, 2, LUA_TTABLE);
+	int tablelen = (int) luax_objlen(L, 2);
+
+	lua_rawgeti(L, 2, 1);
+	bool tableoftables = lua_istable(L, -1);
+	lua_pop(L, 1);
+
+	if (!tableoftables)
+	{
+		if (tablelen % ncomponents != 0)
+			return luaL_error(L, "Array length in flat array variant of Buffer:setArrayData must be a multiple of the number of the total number of components (%d)", ncomponents);
+		tablelen /= ncomponents;
+	}
+
+	count = count >= 0 ? std::min(count, tablelen) : tablelen;
+	if (startindex + count > arraylength)
+		return luaL_error(L, "Too many array elements (expected at most %d, got %d)", arraylength - startindex, count);
+
+	char *data = (char *) t->map() + offset;
+
+	if (tableoftables)
+	{
+		for (int i = 0; i < count; 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 (int i = 0; i < count; 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;
+		}
+	}
+
+	t->setMappedRangeModified(offset, count * stride);
+	t->unmap();
+
+	return 0;
+}
+
+static int w_Buffer_setElement(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+
+	size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
+	if (index >= t->getArrayLength())
+		return luaL_error(L, "Invalid Buffer element index: %ld", index);
+
+	size_t offset = index * t->getArrayStride();
+	char *data = (char *) t->map() + offset;
+	const auto &members = t->getDataMembers();
+
+	bool istable = lua_istable(L, 3);
+	int idx = istable ? 1 : 3;
+
+	if (istable)
+	{
+		for (const Buffer::DataMember &member : members)
+		{
+			int components = member.info.components;
+
+			for (int i = idx; i < idx + components; i++)
+				lua_rawgeti(L, 3, i);
+
+			luax_writebufferdata(L, -components, member.decl.format, data + member.offset);
+
+			idx += components;
+			lua_pop(L, components);
+		}
+	}
+	else
+	{
+		for (const Buffer::DataMember &member : members)
+		{
+			luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
+			idx += member.info.components;
+		}
+	}
+
+	return 0;
+}
+
+static int w_Buffer_getElement(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	if ((t->getMapFlags() & Buffer::MAP_READ) == 0)
+		return luaL_error(L, "Buffer:getElement requires the buffer to be created with the 'cpureadable' setting set to true.");
+
+	size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
+	if (index >= t->getArrayLength())
+		return luaL_error(L, "Invalid Buffer element index: %ld", index);
+
+	size_t offset = index * t->getArrayStride();
+	const char *data = (const char *) t->map() + offset;
+	const auto &members = t->getDataMembers();
+
+	int n = 0;
+
+	for (const Buffer::DataMember &member : members)
+	{
+		luax_readbufferdata(L, member.decl.format, data + member.offset);
+		n += member.info.components;
+	}
+
+	return n;
+}
+
+static int w_Buffer_getElementCount(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	lua_pushinteger(L, t->getArrayLength());
+	return 1;
+}
+
+static int w_Buffer_getElementStride(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	lua_pushinteger(L, t->getArrayStride());
+	return 1;
+}
+
+static int w_Buffer_getSize(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	lua_pushinteger(L, t->getSize());
+	return 1;
+}
+
+static int w_Buffer_getFormat(lua_State *L)
+{
+	Buffer *t = luax_checkbuffer(L, 1);
+	const auto &members = t->getDataMembers();
+
+	lua_createtable(L, (int) members.size(), 0);
+
+	for (size_t i = 0; i < members.size(); i++)
+	{
+		const Buffer::DataMember &member = members[i];
+
+		lua_createtable(L, 0, 4);
+
+		lua_pushstring(L, member.decl.name.c_str());
+		lua_setfield(L, -2, "name");
+
+		const char *formatstr = "unknown";
+		getConstant(member.decl.format, formatstr);
+		lua_pushstring(L, formatstr);
+		lua_setfield(L, -2, "format");
+
+		lua_pushinteger(L, member.decl.arrayLength);
+		lua_setfield(L, -2, "arraylength");
+
+		lua_pushinteger(L, member.offset);
+		lua_setfield(L, -2, "offset");
+
+		lua_rawseti(L, -2, i + 1);
+	}
+
+	return 1;
+}
+
 static const luaL_Reg w_Buffer_functions[] =
 {
+	{ "flush", w_Buffer_flush },
+	{ "setArrayData", w_Buffer_setArrayData },
+	{ "setElement", w_Buffer_setElement },
+	{ "getElement", w_Buffer_getElement },
+	{ "getElementCount", w_Buffer_getElementCount },
+	{ "getElementStride", w_Buffer_getElementStride },
+	{ "getSize", w_Buffer_getSize },
+	{ "getFormat", w_Buffer_getFormat },
 	{ 0, 0 }
 };
 

+ 1 - 1
src/modules/graphics/wrap_Mesh.cpp

@@ -55,7 +55,7 @@ int w_Mesh_setVertices(lua_State *L)
 	size_t byteoffset = vertstart * stride;
 	int totalverts = (int) t->getVertexCount();
 
-	if (vertstart >= totalverts)
+	if (vertstart >= totalverts || vertstart < 0)
 		return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", totalverts);
 
 	if (luax_istype(L, 2, Data::type))

+ 3 - 0
src/modules/graphics/wrap_SpriteBatch.cpp

@@ -226,6 +226,9 @@ int w_SpriteBatch_attachAttribute(lua_State *L)
 	{
 		Mesh *mesh = luax_checktype<Mesh>(L, 3);
 		buffer = mesh->getVertexBuffer();
+		if (buffer == nullptr)
+			return luaL_error(L, "Mesh does not have its own vertex buffer.");
+		luax_markdeprecated(L, "SpriteBatch:attachAttribute(name, mesh)", API_METHOD, DEPRECATED_REPLACED, "SpriteBatch:attachAttribute(name, buffer)");
 	}
 
 	luax_catchexcept(L, [&](){ t->attachAttribute(name, buffer); });