Files
love/src/modules/graphics/opengl/wrap_Mesh.cpp
T

483 lines
12 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:
return data + writeData<uint8>(L, startidx, components, data);
case Mesh::DATA_FLOAT:
return data + writeData<float>(L, startidx, components, data);
default:
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:
return data + readData<uint8>(L, components, data);
case Mesh::DATA_FLOAT:
return data + readData<float>(L, components, data);
default:
return data;
}
}
int w_Mesh_setVertices(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
luaL_checktype(L, 2, LUA_TTABLE);
size_t nvertices = lua_objlen(L, 2);
if (nvertices != t->getVertexCount())
return luaL_error(L, "Invalid number of vertices (expected %d, got %d)", (int) t->getVertexCount(), (int) nvertices);
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
int ncomponents = 0;
for (const Mesh::AttribFormat &format : vertexformat)
ncomponents += format.components;
char *data = (char *) t->mapVertexData();
for (size_t i = 0; i < nvertices; i++)
{
// get vertices[vertindex]
lua_rawgeti(L, 2, i + 1);
luaL_checktype(L, -1, LUA_TTABLE);
// get vertices[vertindex][j]
for (int j = 1; j <= ncomponents; j++)
lua_rawgeti(L, -j, j);
int idx = -ncomponents;
for (const Mesh::AttribFormat &format : vertexformat)
{
// Fetch the values from Lua and store them in data buffer.
data = writeAttributeData(L, idx, format.type, format.components, data);
idx += format.components;
}
lua_pop(L, ncomponents + 1);
}
t->unmapVertexData();
return 0;
}
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[] =
{
{ "setVertices", w_Mesh_setVertices },
{ "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