mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
2844499ef7
Added new love.graphics.newMesh variants: newMesh(vertexformat, vertices [, drawmode, meshusage]) and newMesh(vertexformat, numvertices [, drawmode, meshusage]).
Replaced the regular love.graphics.newMesh variants with newMesh(vertices [, drawmode, meshusage]) and newMesh(numvertices [, drawmode, meshusage]). To use an image or canvas with a mesh, use Mesh:setTexture.
vertexformat is a table with the following prototype:
{
{attributename, datatype, components},
{attributename, datatype, components},
...
}
Where attributename is the name of the vertex attribute (can be the built-in names 'VertexPosition', 'VertexTexCoord', or 'VertexColor', or a custom name for use in a vertex shader), datatype is the type of values used for the attribute ('float' or 'byte'), and components is the number of components in the vertex attribute (between 1 and 4.)
The vertex format is used to determine the layout of the vertices in the mesh, for example the 'regular' newMesh variants use this vertex format:
format = {
{"VertexPosition", "float", 2},
{"VertexTexCoord", "float", 2},
{"VertexColor", "byte", 4},
}
The mesh usage parameter accepts the same constants as the spritebatch usage hint in love.graphics.newSpriteBatch - "dynamic", "static", and "stream".
Mesh:setVertex now sets *all* vertex attributes for a specific vertex in the Mesh.
Added Mesh:setVertexAttribute(vertexindex, attributeindex, attributevalue1, ...), which sets the values for a specific vertex attribute in a specific vertex in the Mesh (resolves issue #784.)
Added Mesh:getVertexFormat and Mesh:flush.
Added Mesh:setAttributeEnabled(attributename, enable) and Mesh:isAttributeEnabled(attributename), to enable or disable the use of a specific attribute when drawing the Mesh.
Added Mesh:attachAttribute(attributename, mesh), which makes the Mesh use a vertex attribute from another mesh when drawing the Mesh. This can be used to separate out vertex attributes which are updated at different rates into different meshes, and to share vertex data between multiple meshes.
Removed Mesh:setVertices, Mesh:getVertices, and Mesh:setVertexColors.
446 lines
10 KiB
C++
446 lines
10 KiB
C++
/**
|
|
* Copyright (c) 2006-2015 LOVE Development Team
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
**/
|
|
|
|
// LOVE
|
|
#include "wrap_Mesh.h"
|
|
#include "Image.h"
|
|
#include "Canvas.h"
|
|
#include "graphics/wrap_Texture.h"
|
|
|
|
// C++
|
|
#include <typeinfo>
|
|
|
|
namespace love
|
|
{
|
|
namespace graphics
|
|
{
|
|
namespace opengl
|
|
{
|
|
|
|
Mesh *luax_checkmesh(lua_State *L, int idx)
|
|
{
|
|
return luax_checktype<Mesh>(L, idx, GRAPHICS_MESH_ID);
|
|
}
|
|
|
|
template <typename T>
|
|
static inline size_t writeData(lua_State *L, int startidx, int components, char *data)
|
|
{
|
|
T *componentdata = (T *) data;
|
|
for (int i = 0; i < components; i++)
|
|
componentdata[i] = (T) luaL_checknumber(L, startidx + i);
|
|
|
|
return sizeof(T) * components;
|
|
}
|
|
|
|
static inline char *writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Mesh::DATA_BYTE:
|
|
data += writeData<uint8>(L, startidx, components, data);
|
|
break;
|
|
case Mesh::DATA_FLOAT:
|
|
data += writeData<float>(L, startidx, components, data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
template <typename T>
|
|
static inline size_t readData(lua_State *L, int components, const char *data)
|
|
{
|
|
const T *componentdata = (const T *) data;
|
|
for (int i = 0; i < components; i++)
|
|
lua_pushnumber(L, (lua_Number) componentdata[i]);
|
|
|
|
return sizeof(T) * components;
|
|
}
|
|
|
|
static inline const char *readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Mesh::DATA_BYTE:
|
|
data += readData<uint8>(L, components, data);
|
|
break;
|
|
case Mesh::DATA_FLOAT:
|
|
data += readData<float>(L, components, data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
int w_Mesh_setVertex(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
|
|
|
|
bool istable = lua_istable(L, 3);
|
|
|
|
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
|
|
|
char *data = (char *) t->getVertexScratchBuffer();
|
|
char *writtendata = data;
|
|
|
|
int idx = istable ? 1 : 3;
|
|
|
|
if (istable)
|
|
{
|
|
for (const Mesh::AttribFormat &format : vertexformat)
|
|
{
|
|
for (int i = idx; i < idx + format.components; i++)
|
|
lua_rawgeti(L, 3, i);
|
|
|
|
// Fetch the values from Lua and store them in data buffer.
|
|
writtendata = writeAttributeData(L, -format.components, format.type, format.components, writtendata);
|
|
|
|
idx += format.components;
|
|
lua_pop(L, format.components);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (const Mesh::AttribFormat &format : vertexformat)
|
|
{
|
|
// Fetch the values from Lua and store them in data buffer.
|
|
writtendata = writeAttributeData(L, idx, format.type, format.components, writtendata);
|
|
idx += format.components;
|
|
}
|
|
}
|
|
|
|
luax_catchexcept(L, [&](){ t->setVertex(index, data, t->getVertexStride()); });
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getVertex(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
|
|
|
|
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
|
|
|
char *data = (char *) t->getVertexScratchBuffer();
|
|
const char *readdata = data;
|
|
|
|
luax_catchexcept(L, [&](){ t->getVertex(index, data, t->getVertexStride()); });
|
|
|
|
int n = 0;
|
|
|
|
for (const Mesh::AttribFormat &format : vertexformat)
|
|
{
|
|
readdata = readAttributeData(L, format.type, format.components, readdata);
|
|
n += format.components;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
int w_Mesh_setVertexAttribute(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
|
|
int attribindex = (int) luaL_checkinteger(L, 3) - 1;
|
|
|
|
Mesh::DataType type;
|
|
int components;
|
|
luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
|
|
|
|
// Maximum possible size for a single vertex attribute.
|
|
char data[sizeof(float) * 4];
|
|
|
|
// Fetch the values from Lua and store them in the data buffer.
|
|
writeAttributeData(L, 4, type, components, data);
|
|
|
|
luax_catchexcept(L, [&](){ t->setVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getVertexAttribute(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
|
|
int attribindex = (int) luaL_checkinteger(L, 3) - 1;
|
|
|
|
Mesh::DataType type;
|
|
int components;
|
|
luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
|
|
|
|
// Maximum possible size for a single vertex attribute.
|
|
char data[sizeof(float) * 4];
|
|
|
|
luax_catchexcept(L, [&](){ t->getVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
|
|
|
|
readAttributeData(L, type, components, data);
|
|
return components;
|
|
}
|
|
|
|
int w_Mesh_getVertexCount(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
lua_pushinteger(L, t->getVertexCount());
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_getVertexFormat(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
|
lua_createtable(L, (int) vertexformat.size(), 0);
|
|
|
|
const char *tname = nullptr;
|
|
|
|
for (size_t i = 0; i < vertexformat.size(); i++)
|
|
{
|
|
if (!Mesh::getConstant(vertexformat[i].type, tname))
|
|
return luaL_error(L, "Unknown vertex attribute data type.");
|
|
|
|
lua_createtable(L, 3, 0);
|
|
|
|
lua_pushstring(L, vertexformat[i].name.c_str());
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushstring(L, tname);
|
|
lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushinteger(L, vertexformat[i].components);
|
|
lua_rawseti(L, -2, 3);
|
|
|
|
// format[i] = {name, type, components}
|
|
lua_rawseti(L, -2, (int) i + 1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_setAttributeEnabled(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
const char *name = luaL_checkstring(L, 2);
|
|
bool enable = luax_toboolean(L, 3);
|
|
luax_catchexcept(L, [&](){ t->setAttributeEnabled(name, enable); });
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_isAttributeEnabled(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
const char *name = luaL_checkstring(L, 2);
|
|
bool enabled = false;
|
|
luax_catchexcept(L, [&](){ enabled = t->isAttributeEnabled(name); });
|
|
lua_pushboolean(L, enabled);
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_attachAttribute(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
const char *name = luaL_checkstring(L, 2);
|
|
Mesh *mesh = luax_checkmesh(L, 3);
|
|
luax_catchexcept(L, [&](){ t->attachAttribute(name, mesh); });
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_flush(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
t->flush();
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_setVertexMap(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
bool is_table = lua_istable(L, 2);
|
|
int nargs = is_table ? (int) lua_objlen(L, 2) : lua_gettop(L) - 1;
|
|
|
|
std::vector<uint32> vertexmap;
|
|
vertexmap.reserve(nargs);
|
|
|
|
if (is_table)
|
|
{
|
|
for (int i = 0; i < nargs; i++)
|
|
{
|
|
lua_rawgeti(L, 2, i + 1);
|
|
vertexmap.push_back(uint32(luaL_checkinteger(L, -1) - 1));
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < nargs; i++)
|
|
vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
|
|
}
|
|
|
|
luax_catchexcept(L, [&](){ t->setVertexMap(vertexmap); });
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getVertexMap(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
std::vector<uint32> vertex_map;
|
|
luax_catchexcept(L, [&](){ t->getVertexMap(vertex_map); });
|
|
|
|
int element_count = (int) vertex_map.size();
|
|
|
|
lua_createtable(L, element_count, 0);
|
|
|
|
for (int i = 0; i < element_count; i++)
|
|
{
|
|
lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_setTexture(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
if (lua_isnoneornil(L, 2))
|
|
t->setTexture();
|
|
else
|
|
{
|
|
Texture *tex = luax_checktexture(L, 2);
|
|
t->setTexture(tex);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getTexture(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
Texture *tex = t->getTexture();
|
|
|
|
if (tex == nullptr)
|
|
return 0;
|
|
|
|
// FIXME: big hack right here.
|
|
if (typeid(*tex) == typeid(Image))
|
|
luax_pushtype(L, GRAPHICS_IMAGE_ID, tex);
|
|
else if (typeid(*tex) == typeid(Canvas))
|
|
luax_pushtype(L, GRAPHICS_CANVAS_ID, tex);
|
|
else
|
|
return luaL_error(L, "Unable to determine texture type.");
|
|
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_setDrawMode(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
const char *str = luaL_checkstring(L, 2);
|
|
Mesh::DrawMode mode;
|
|
|
|
if (!Mesh::getConstant(str, mode))
|
|
return luaL_error(L, "Invalid mesh draw mode: %s", str);
|
|
|
|
t->setDrawMode(mode);
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getDrawMode(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
Mesh::DrawMode mode = t->getDrawMode();
|
|
const char *str;
|
|
|
|
if (!Mesh::getConstant(mode, str))
|
|
return luaL_error(L, "Unknown mesh draw mode.");
|
|
|
|
lua_pushstring(L, str);
|
|
return 1;
|
|
}
|
|
|
|
int w_Mesh_setDrawRange(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
if (lua_isnoneornil(L, 2))
|
|
t->setDrawRange();
|
|
else
|
|
{
|
|
int rangemin = luaL_checkint(L, 2) - 1;
|
|
int rangemax = luaL_checkint(L, 3) - 1;
|
|
luax_catchexcept(L, [&](){ t->setDrawRange(rangemin, rangemax); });
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int w_Mesh_getDrawRange(lua_State *L)
|
|
{
|
|
Mesh *t = luax_checkmesh(L, 1);
|
|
|
|
int rangemin = -1;
|
|
int rangemax = -1;
|
|
t->getDrawRange(rangemin, rangemax);
|
|
|
|
if (rangemin < 0 || rangemax < 0)
|
|
return 0;
|
|
|
|
lua_pushinteger(L, rangemin + 1);
|
|
lua_pushinteger(L, rangemax + 1);
|
|
return 2;
|
|
}
|
|
|
|
static const luaL_Reg functions[] =
|
|
{
|
|
{ "setVertex", w_Mesh_setVertex },
|
|
{ "getVertex", w_Mesh_getVertex },
|
|
{ "setVertexAttribute", w_Mesh_setVertexAttribute },
|
|
{ "getVertexAttribute", w_Mesh_getVertexAttribute },
|
|
{ "getVertexCount", w_Mesh_getVertexCount },
|
|
{ "getVertexFormat", w_Mesh_getVertexFormat },
|
|
{ "setAttributeEnabled", w_Mesh_setAttributeEnabled },
|
|
{ "isAttributeEnabled", w_Mesh_isAttributeEnabled },
|
|
{ "attachAttribute", w_Mesh_attachAttribute },
|
|
{ "flush", w_Mesh_flush },
|
|
{ "setVertexMap", w_Mesh_setVertexMap },
|
|
{ "getVertexMap", w_Mesh_getVertexMap },
|
|
{ "setTexture", w_Mesh_setTexture },
|
|
{ "getTexture", w_Mesh_getTexture },
|
|
{ "setDrawMode", w_Mesh_setDrawMode },
|
|
{ "getDrawMode", w_Mesh_getDrawMode },
|
|
{ "setDrawRange", w_Mesh_setDrawRange },
|
|
{ "getDrawRange", w_Mesh_getDrawRange },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
extern "C" int luaopen_mesh(lua_State *L)
|
|
{
|
|
return luax_register_type(L, GRAPHICS_MESH_ID, functions);
|
|
}
|
|
|
|
} // opengl
|
|
} // graphics
|
|
} // love
|