wrap_Mesh.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /**
  2. * Copyright (c) 2006-2020 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "wrap_Mesh.h"
  22. #include "wrap_Buffer.h"
  23. #include "Texture.h"
  24. #include "wrap_Texture.h"
  25. // C++
  26. #include <algorithm>
  27. namespace love
  28. {
  29. namespace graphics
  30. {
  31. Mesh *luax_checkmesh(lua_State *L, int idx)
  32. {
  33. return luax_checktype<Mesh>(L, idx);
  34. }
  35. int w_Mesh_setVertices(lua_State *L)
  36. {
  37. Mesh *t = luax_checkmesh(L, 1);
  38. int vertstart = (int) luaL_optnumber(L, 3, 1) - 1;
  39. int vertcount = -1;
  40. if (!lua_isnoneornil(L, 4))
  41. {
  42. vertcount = (int) luaL_checknumber(L, 4);
  43. if (vertcount <= 0)
  44. return luaL_error(L, "Vertex count must be greater than 0.");
  45. }
  46. size_t stride = t->getVertexStride();
  47. size_t byteoffset = vertstart * stride;
  48. int totalverts = (int) t->getVertexCount();
  49. if (vertstart >= totalverts || vertstart < 0)
  50. return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", totalverts);
  51. if (luax_istype(L, 2, Data::type))
  52. {
  53. Data *d = luax_checktype<Data>(L, 2);
  54. vertcount = vertcount >= 0 ? vertcount : (totalverts - vertstart);
  55. if (vertstart + vertcount > totalverts)
  56. return luaL_error(L, "Too many vertices (expected at most %d, got %d)", totalverts - vertstart, vertcount);
  57. size_t datasize = std::min(d->getSize(), vertcount * stride);
  58. char *bytedata = (char *) t->mapVertexData() + byteoffset;
  59. memcpy(bytedata, d->getData(), datasize);
  60. t->unmapVertexData(byteoffset, datasize);
  61. return 0;
  62. }
  63. luaL_checktype(L, 2, LUA_TTABLE);
  64. int tablelen = (int) luax_objlen(L, 2);
  65. vertcount = vertcount >= 0 ? std::min(vertcount, tablelen) : tablelen;
  66. if (vertstart + vertcount > totalverts)
  67. return luaL_error(L, "Too many vertices (expected at most %d, got %d)", totalverts - vertstart, vertcount);
  68. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  69. int ncomponents = 0;
  70. for (const Buffer::DataMember &member : vertexformat)
  71. ncomponents += member.info.components;
  72. char *data = (char *) t->mapVertexData() + byteoffset;
  73. for (int i = 0; i < vertcount; i++)
  74. {
  75. // get vertices[vertindex]
  76. lua_rawgeti(L, 2, i + 1);
  77. luaL_checktype(L, -1, LUA_TTABLE);
  78. // get vertices[vertindex][j]
  79. for (int j = 1; j <= ncomponents; j++)
  80. lua_rawgeti(L, -j, j);
  81. int idx = -ncomponents;
  82. for (const Buffer::DataMember &member : vertexformat)
  83. {
  84. // Fetch the values from Lua and store them in data buffer.
  85. luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
  86. idx += member.info.components;
  87. }
  88. lua_pop(L, ncomponents + 1);
  89. data += stride;
  90. }
  91. t->unmapVertexData(byteoffset, vertcount * stride);
  92. return 0;
  93. }
  94. int w_Mesh_setVertex(lua_State *L)
  95. {
  96. Mesh *t = luax_checkmesh(L, 1);
  97. size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
  98. bool istable = lua_istable(L, 3);
  99. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  100. char *data = (char *) t->getVertexScratchBuffer();
  101. int idx = istable ? 1 : 3;
  102. if (istable)
  103. {
  104. for (const Buffer::DataMember &member : vertexformat)
  105. {
  106. int components = member.info.components;
  107. for (int i = idx; i < idx + components; i++)
  108. lua_rawgeti(L, 3, i);
  109. // Fetch the values from Lua and store them in data buffer.
  110. luax_writebufferdata(L, -components, member.decl.format, data + member.offset);
  111. idx += components;
  112. lua_pop(L, components);
  113. }
  114. }
  115. else
  116. {
  117. for (const Buffer::DataMember &member : vertexformat)
  118. {
  119. // Fetch the values from Lua and store them in data buffer.
  120. luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
  121. idx += member.info.components;
  122. }
  123. }
  124. luax_catchexcept(L, [&](){ t->setVertex(index, data, t->getVertexStride()); });
  125. return 0;
  126. }
  127. int w_Mesh_getVertex(lua_State *L)
  128. {
  129. Mesh *t = luax_checkmesh(L, 1);
  130. size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
  131. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  132. char *data = (char *) t->getVertexScratchBuffer();
  133. luax_catchexcept(L, [&](){ t->getVertex(index, data, t->getVertexStride()); });
  134. int n = 0;
  135. for (const Buffer::DataMember &member : vertexformat)
  136. {
  137. luax_readbufferdata(L, member.decl.format, data + member.offset);
  138. n += member.info.components;
  139. }
  140. return n;
  141. }
  142. int w_Mesh_setVertexAttribute(lua_State *L)
  143. {
  144. Mesh *t = luax_checkmesh(L, 1);
  145. size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
  146. int attribindex = (int) luaL_checkinteger(L, 3) - 1;
  147. const auto &vertexformat = t->getVertexFormat();
  148. if (attribindex < 0 || attribindex >= (int) vertexformat.size())
  149. return luaL_error(L, "Invalid vertex attribute index: %d", attribindex + 1);
  150. const Buffer::DataMember &member = vertexformat[attribindex];
  151. // Maximum possible size for a single vertex attribute.
  152. char data[sizeof(float) * 4];
  153. // Fetch the values from Lua and store them in the data buffer.
  154. luax_writebufferdata(L, 4, member.decl.format, data);
  155. luax_catchexcept(L, [&](){ t->setVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
  156. return 0;
  157. }
  158. int w_Mesh_getVertexAttribute(lua_State *L)
  159. {
  160. Mesh *t = luax_checkmesh(L, 1);
  161. size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
  162. int attribindex = (int) luaL_checkinteger(L, 3) - 1;
  163. const auto &vertexformat = t->getVertexFormat();
  164. if (attribindex < 0 || attribindex >= (int) vertexformat.size())
  165. return luaL_error(L, "Invalid vertex attribute index: %d", attribindex + 1);
  166. const Buffer::DataMember &member = vertexformat[attribindex];
  167. // Maximum possible size for a single vertex attribute.
  168. char data[sizeof(float) * 4];
  169. luax_catchexcept(L, [&](){ t->getVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
  170. luax_readbufferdata(L, member.decl.format, data);
  171. return member.info.components;
  172. }
  173. int w_Mesh_getVertexCount(lua_State *L)
  174. {
  175. Mesh *t = luax_checkmesh(L, 1);
  176. lua_pushinteger(L, t->getVertexCount());
  177. return 1;
  178. }
  179. int w_Mesh_getVertexFormat(lua_State *L)
  180. {
  181. Mesh *t = luax_checkmesh(L, 1);
  182. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  183. lua_createtable(L, (int) vertexformat.size(), 0);
  184. const char *tname = nullptr;
  185. for (size_t i = 0; i < vertexformat.size(); i++)
  186. {
  187. const auto &decl = vertexformat[i].decl;
  188. if (!getConstant(decl.format, tname))
  189. return luax_enumerror(L, "vertex attribute data type", getConstants(decl.format), tname);
  190. lua_createtable(L, 3, 0);
  191. lua_pushstring(L, decl.name.c_str());
  192. lua_rawseti(L, -2, 1);
  193. lua_pushstring(L, tname);
  194. lua_rawseti(L, -2, 2);
  195. // format[i] = {name, type}
  196. lua_rawseti(L, -2, (int) i + 1);
  197. }
  198. return 1;
  199. }
  200. int w_Mesh_setAttributeEnabled(lua_State *L)
  201. {
  202. Mesh *t = luax_checkmesh(L, 1);
  203. const char *name = luaL_checkstring(L, 2);
  204. bool enable = luax_checkboolean(L, 3);
  205. luax_catchexcept(L, [&](){ t->setAttributeEnabled(name, enable); });
  206. return 0;
  207. }
  208. int w_Mesh_isAttributeEnabled(lua_State *L)
  209. {
  210. Mesh *t = luax_checkmesh(L, 1);
  211. const char *name = luaL_checkstring(L, 2);
  212. bool enabled = false;
  213. luax_catchexcept(L, [&](){ enabled = t->isAttributeEnabled(name); });
  214. lua_pushboolean(L, enabled);
  215. return 1;
  216. }
  217. int w_Mesh_attachAttribute(lua_State *L)
  218. {
  219. Mesh *t = luax_checkmesh(L, 1);
  220. const char *name = luaL_checkstring(L, 2);
  221. Buffer *buffer = nullptr;
  222. if (luax_istype(L, 3, Buffer::type))
  223. {
  224. buffer = luax_checktype<Buffer>(L, 3);
  225. }
  226. else
  227. {
  228. Mesh *mesh = luax_checkmesh(L, 3);
  229. buffer = mesh->getVertexBuffer();
  230. if (buffer == nullptr)
  231. return luaL_error(L, "Mesh does not have its own vertex buffer.");
  232. luax_markdeprecated(L, "Mesh:attachAttribute(name, mesh, ...)", API_METHOD, DEPRECATED_REPLACED, "Mesh:attachAttribute(name, buffer, ...)");
  233. }
  234. AttributeStep step = STEP_PER_VERTEX;
  235. const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
  236. if (stepstr != nullptr && !getConstant(stepstr, step))
  237. return luax_enumerror(L, "vertex attribute step", getConstants(step), stepstr);
  238. const char *attachname = luaL_optstring(L, 5, name);
  239. luax_catchexcept(L, [&](){ t->attachAttribute(name, buffer, attachname, step); });
  240. return 0;
  241. }
  242. int w_Mesh_detachAttribute(lua_State *L)
  243. {
  244. Mesh *t = luax_checkmesh(L, 1);
  245. const char *name = luaL_checkstring(L, 2);
  246. bool success = false;
  247. luax_catchexcept(L, [&](){ success = t->detachAttribute(name); });
  248. luax_pushboolean(L, success);
  249. return 1;
  250. }
  251. int w_Mesh_getAttachedAttributes(lua_State *L)
  252. {
  253. Mesh *t = luax_checkmesh(L, 1);
  254. const auto &attributes = t->getAttachedAttributes();
  255. lua_createtable(L, (int) attributes.size(), 0);
  256. for (int i = 0; i < (int) attributes.size(); i++)
  257. {
  258. const auto &attrib = attributes[i];
  259. lua_createtable(L, 4, 0);
  260. luax_pushstring(L, attrib.name);
  261. lua_rawseti(L, -1, 1);
  262. luax_pushtype(L, attrib.buffer.get());
  263. lua_rawseti(L, -1, 2);
  264. const char *stepstr = nullptr;
  265. if (!getConstant(attrib.step, stepstr))
  266. return luaL_error(L, "Invalid vertex attribute step.");
  267. lua_pushstring(L, stepstr);
  268. lua_rawseti(L, -1, 3);
  269. const Buffer::DataMember &member = attrib.buffer->getDataMember(attrib.indexInBuffer);
  270. luax_pushstring(L, member.decl.name);
  271. lua_rawseti(L, -1, 4);
  272. lua_rawseti(L, -1, i + 1);
  273. }
  274. return 1;
  275. }
  276. int w_Mesh_getVertexBuffer(lua_State *L)
  277. {
  278. Mesh *t = luax_checkmesh(L, 1);
  279. luax_pushtype(L, t->getVertexBuffer());
  280. return 1;
  281. }
  282. int w_Mesh_flush(lua_State *L)
  283. {
  284. Mesh *t = luax_checkmesh(L, 1);
  285. t->flush();
  286. return 0;
  287. }
  288. int w_Mesh_setVertexMap(lua_State *L)
  289. {
  290. Mesh *t = luax_checkmesh(L, 1);
  291. if (lua_isnoneornil(L, 2))
  292. {
  293. // Disable the vertex map / index buffer.
  294. luax_catchexcept(L, [&](){ t->setVertexMap(); });
  295. return 0;
  296. }
  297. if (luax_istype(L, 2, Data::type))
  298. {
  299. Data *d = luax_totype<Data>(L, 2, Data::type);
  300. const char *indextypestr = luaL_checkstring(L, 3);
  301. IndexDataType indextype;
  302. if (!getConstant(indextypestr, indextype))
  303. return luax_enumerror(L, "index data type", getConstants(indextype), indextypestr);
  304. size_t datatypesize = getIndexDataSize(indextype);
  305. int indexcount = (int) luaL_optinteger(L, 4, d->getSize() / datatypesize);
  306. if (indexcount < 1 || indexcount * datatypesize > d->getSize())
  307. return luaL_error(L, "Invalid index count: %d", indexcount);
  308. luax_catchexcept(L, [&]() { t->setVertexMap(indextype, d->getData(), indexcount * datatypesize); });
  309. return 0;
  310. }
  311. bool is_table = lua_istable(L, 2);
  312. int nargs = is_table ? (int) luax_objlen(L, 2) : lua_gettop(L) - 1;
  313. std::vector<uint32> vertexmap;
  314. vertexmap.reserve(nargs);
  315. if (is_table)
  316. {
  317. for (int i = 0; i < nargs; i++)
  318. {
  319. lua_rawgeti(L, 2, i + 1);
  320. vertexmap.push_back(uint32(luaL_checkinteger(L, -1) - 1));
  321. lua_pop(L, 1);
  322. }
  323. }
  324. else
  325. {
  326. for (int i = 0; i < nargs; i++)
  327. vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
  328. }
  329. luax_catchexcept(L, [&](){ t->setVertexMap(vertexmap); });
  330. return 0;
  331. }
  332. int w_Mesh_getVertexMap(lua_State *L)
  333. {
  334. Mesh *t = luax_checkmesh(L, 1);
  335. std::vector<uint32> vertex_map;
  336. bool has_vertex_map = false;
  337. luax_catchexcept(L, [&](){ has_vertex_map = t->getVertexMap(vertex_map); });
  338. if (!has_vertex_map)
  339. {
  340. lua_pushnil(L);
  341. return 1;
  342. }
  343. int element_count = (int) vertex_map.size();
  344. lua_createtable(L, element_count, 0);
  345. for (int i = 0; i < element_count; i++)
  346. {
  347. lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
  348. lua_rawseti(L, -2, i + 1);
  349. }
  350. return 1;
  351. }
  352. int w_Mesh_setIndexBuffer(lua_State *L)
  353. {
  354. Mesh *t = luax_checkmesh(L, 1);
  355. Buffer *b = nullptr;
  356. if (!lua_isnoneornil(L, 2))
  357. b = luax_checkbuffer(L, 2);
  358. luax_catchexcept(L, [&]() { t->setIndexBuffer(b); });
  359. return 0;
  360. }
  361. int w_Mesh_getIndexBuffer(lua_State *L)
  362. {
  363. Mesh *t = luax_checkmesh(L, 1);
  364. luax_pushtype(L, t->getIndexBuffer());
  365. return 1;
  366. }
  367. int w_Mesh_setTexture(lua_State *L)
  368. {
  369. Mesh *t = luax_checkmesh(L, 1);
  370. if (lua_isnoneornil(L, 2))
  371. t->setTexture();
  372. else
  373. {
  374. Texture *tex = luax_checktexture(L, 2);
  375. luax_catchexcept(L, [&](){ t->setTexture(tex); });
  376. }
  377. return 0;
  378. }
  379. int w_Mesh_getTexture(lua_State *L)
  380. {
  381. Mesh *t = luax_checkmesh(L, 1);
  382. Texture *tex = t->getTexture();
  383. if (tex == nullptr)
  384. return 0;
  385. luax_pushtype(L, tex);
  386. return 1;
  387. }
  388. int w_Mesh_setDrawMode(lua_State *L)
  389. {
  390. Mesh *t = luax_checkmesh(L, 1);
  391. const char *str = luaL_checkstring(L, 2);
  392. PrimitiveType mode;
  393. if (!getConstant(str, mode))
  394. return luax_enumerror(L, "mesh draw mode", getConstants(mode), str);
  395. t->setDrawMode(mode);
  396. return 0;
  397. }
  398. int w_Mesh_getDrawMode(lua_State *L)
  399. {
  400. Mesh *t = luax_checkmesh(L, 1);
  401. PrimitiveType mode = t->getDrawMode();
  402. const char *str;
  403. if (!getConstant(mode, str))
  404. return luaL_error(L, "Unknown mesh draw mode.");
  405. lua_pushstring(L, str);
  406. return 1;
  407. }
  408. int w_Mesh_setDrawRange(lua_State *L)
  409. {
  410. Mesh *t = luax_checkmesh(L, 1);
  411. if (lua_isnoneornil(L, 2))
  412. t->setDrawRange();
  413. else
  414. {
  415. int start = (int) luaL_checkinteger(L, 2) - 1;
  416. int count = (int) luaL_checkinteger(L, 3);
  417. luax_catchexcept(L, [&](){ t->setDrawRange(start, count); });
  418. }
  419. return 0;
  420. }
  421. int w_Mesh_getDrawRange(lua_State *L)
  422. {
  423. Mesh *t = luax_checkmesh(L, 1);
  424. int start = 0;
  425. int count = 1;
  426. if (!t->getDrawRange(start, count))
  427. return 0;
  428. lua_pushinteger(L, start + 1);
  429. lua_pushinteger(L, count);
  430. return 2;
  431. }
  432. static const luaL_Reg w_Mesh_functions[] =
  433. {
  434. { "setVertices", w_Mesh_setVertices },
  435. { "setVertex", w_Mesh_setVertex },
  436. { "getVertex", w_Mesh_getVertex },
  437. { "setVertexAttribute", w_Mesh_setVertexAttribute },
  438. { "getVertexAttribute", w_Mesh_getVertexAttribute },
  439. { "getVertexCount", w_Mesh_getVertexCount },
  440. { "getVertexFormat", w_Mesh_getVertexFormat },
  441. { "setAttributeEnabled", w_Mesh_setAttributeEnabled },
  442. { "isAttributeEnabled", w_Mesh_isAttributeEnabled },
  443. { "attachAttribute", w_Mesh_attachAttribute },
  444. { "detachAttribute", w_Mesh_detachAttribute },
  445. { "getAttachedAttributes", w_Mesh_getAttachedAttributes },
  446. { "getVertexBuffer", w_Mesh_getVertexBuffer },
  447. { "flush", w_Mesh_flush },
  448. { "setVertexMap", w_Mesh_setVertexMap },
  449. { "getVertexMap", w_Mesh_getVertexMap },
  450. { "setIndexBuffer", w_Mesh_setIndexBuffer },
  451. { "getIndexBuffer", w_Mesh_getIndexBuffer },
  452. { "setTexture", w_Mesh_setTexture },
  453. { "getTexture", w_Mesh_getTexture },
  454. { "setDrawMode", w_Mesh_setDrawMode },
  455. { "getDrawMode", w_Mesh_getDrawMode },
  456. { "setDrawRange", w_Mesh_setDrawRange },
  457. { "getDrawRange", w_Mesh_getDrawRange },
  458. { 0, 0 }
  459. };
  460. extern "C" int luaopen_mesh(lua_State *L)
  461. {
  462. return luax_register_type(L, &Mesh::type, w_Mesh_functions, nullptr);
  463. }
  464. } // graphics
  465. } // love