wrap_Mesh.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /**
  2. * Copyright (c) 2006-2021 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->getVertexData() + byteoffset;
  59. memcpy(bytedata, d->getData(), datasize);
  60. t->setVertexDataModified(byteoffset, datasize);
  61. t->flush();
  62. return 0;
  63. }
  64. luaL_checktype(L, 2, LUA_TTABLE);
  65. int tablelen = (int) luax_objlen(L, 2);
  66. vertcount = vertcount >= 0 ? std::min(vertcount, tablelen) : tablelen;
  67. if (vertstart + vertcount > totalverts)
  68. return luaL_error(L, "Too many vertices (expected at most %d, got %d)", totalverts - vertstart, vertcount);
  69. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  70. int ncomponents = 0;
  71. for (const Buffer::DataMember &member : vertexformat)
  72. ncomponents += member.info.components;
  73. char *data = (char *) t->getVertexData() + byteoffset;
  74. for (int i = 0; i < vertcount; i++)
  75. {
  76. // get vertices[vertindex]
  77. lua_rawgeti(L, 2, i + 1);
  78. luaL_checktype(L, -1, LUA_TTABLE);
  79. // get vertices[vertindex][j]
  80. for (int j = 1; j <= ncomponents; j++)
  81. lua_rawgeti(L, -j, j);
  82. int idx = -ncomponents;
  83. for (const Buffer::DataMember &member : vertexformat)
  84. {
  85. // Fetch the values from Lua and store them in data buffer.
  86. luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
  87. idx += member.info.components;
  88. }
  89. lua_pop(L, ncomponents + 1);
  90. data += stride;
  91. }
  92. t->setVertexDataModified(byteoffset, vertcount * stride);
  93. t->flush();
  94. return 0;
  95. }
  96. int w_Mesh_setVertex(lua_State *L)
  97. {
  98. Mesh *t = luax_checkmesh(L, 1);
  99. size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
  100. bool istable = lua_istable(L, 3);
  101. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  102. char *data = nullptr;
  103. size_t offset = 0;
  104. luax_catchexcept(L, [&](){ data = (char *) t->checkVertexDataOffset(index, &offset); });
  105. int idx = istable ? 1 : 3;
  106. if (istable)
  107. {
  108. for (const Buffer::DataMember &member : vertexformat)
  109. {
  110. int components = member.info.components;
  111. for (int i = idx; i < idx + components; i++)
  112. lua_rawgeti(L, 3, i);
  113. // Fetch the values from Lua and store them in data buffer.
  114. luax_writebufferdata(L, -components, member.decl.format, data + member.offset);
  115. idx += components;
  116. lua_pop(L, components);
  117. }
  118. }
  119. else
  120. {
  121. for (const Buffer::DataMember &member : vertexformat)
  122. {
  123. // Fetch the values from Lua and store them in data buffer.
  124. luax_writebufferdata(L, idx, member.decl.format, data + member.offset);
  125. idx += member.info.components;
  126. }
  127. }
  128. t->setVertexDataModified(offset, t->getVertexStride());
  129. return 0;
  130. }
  131. int w_Mesh_getVertex(lua_State *L)
  132. {
  133. Mesh *t = luax_checkmesh(L, 1);
  134. size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
  135. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  136. const char *data = nullptr;
  137. luax_catchexcept(L, [&](){ data = (const char *) t->checkVertexDataOffset(index, nullptr); });
  138. int n = 0;
  139. for (const Buffer::DataMember &member : vertexformat)
  140. {
  141. luax_readbufferdata(L, member.decl.format, data + member.offset);
  142. n += member.info.components;
  143. }
  144. return n;
  145. }
  146. int w_Mesh_setVertexAttribute(lua_State *L)
  147. {
  148. Mesh *t = luax_checkmesh(L, 1);
  149. size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
  150. int attribindex = (int) luaL_checkinteger(L, 3) - 1;
  151. const auto &vertexformat = t->getVertexFormat();
  152. if (attribindex < 0 || attribindex >= (int) vertexformat.size())
  153. return luaL_error(L, "Invalid vertex attribute index: %d", attribindex + 1);
  154. const Buffer::DataMember &member = vertexformat[attribindex];
  155. char *data = nullptr;
  156. size_t offset = 0;
  157. luax_catchexcept(L, [&](){ data = (char *) t->checkVertexDataOffset(vertindex, &offset); });
  158. // Fetch the values from Lua and store them in the data buffer.
  159. luax_writebufferdata(L, 4, member.decl.format, data + member.offset);
  160. t->setVertexDataModified(offset + member.offset, member.size);
  161. return 0;
  162. }
  163. int w_Mesh_getVertexAttribute(lua_State *L)
  164. {
  165. Mesh *t = luax_checkmesh(L, 1);
  166. size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
  167. int attribindex = (int) luaL_checkinteger(L, 3) - 1;
  168. const auto &vertexformat = t->getVertexFormat();
  169. if (attribindex < 0 || attribindex >= (int) vertexformat.size())
  170. return luaL_error(L, "Invalid vertex attribute index: %d", attribindex + 1);
  171. const Buffer::DataMember &member = vertexformat[attribindex];
  172. const char *data = nullptr;
  173. luax_catchexcept(L, [&](){ data = (const char *) t->checkVertexDataOffset(vertindex, nullptr); });
  174. luax_readbufferdata(L, member.decl.format, data + member.offset);
  175. return member.info.components;
  176. }
  177. int w_Mesh_getVertexCount(lua_State *L)
  178. {
  179. Mesh *t = luax_checkmesh(L, 1);
  180. lua_pushinteger(L, t->getVertexCount());
  181. return 1;
  182. }
  183. int w_Mesh_getVertexFormat(lua_State *L)
  184. {
  185. Mesh *t = luax_checkmesh(L, 1);
  186. const std::vector<Buffer::DataMember> &vertexformat = t->getVertexFormat();
  187. lua_createtable(L, (int) vertexformat.size(), 0);
  188. const char *tname = nullptr;
  189. for (size_t i = 0; i < vertexformat.size(); i++)
  190. {
  191. const auto &decl = vertexformat[i].decl;
  192. if (!getConstant(decl.format, tname))
  193. return luax_enumerror(L, "vertex attribute data type", getConstants(decl.format), tname);
  194. lua_createtable(L, 3, 0);
  195. lua_pushstring(L, decl.name.c_str());
  196. lua_rawseti(L, -2, 1);
  197. lua_pushstring(L, tname);
  198. lua_rawseti(L, -2, 2);
  199. // format[i] = {name, type}
  200. lua_rawseti(L, -2, (int) i + 1);
  201. }
  202. return 1;
  203. }
  204. int w_Mesh_setAttributeEnabled(lua_State *L)
  205. {
  206. Mesh *t = luax_checkmesh(L, 1);
  207. const char *name = luaL_checkstring(L, 2);
  208. bool enable = luax_checkboolean(L, 3);
  209. luax_catchexcept(L, [&](){ t->setAttributeEnabled(name, enable); });
  210. return 0;
  211. }
  212. int w_Mesh_isAttributeEnabled(lua_State *L)
  213. {
  214. Mesh *t = luax_checkmesh(L, 1);
  215. const char *name = luaL_checkstring(L, 2);
  216. bool enabled = false;
  217. luax_catchexcept(L, [&](){ enabled = t->isAttributeEnabled(name); });
  218. lua_pushboolean(L, enabled);
  219. return 1;
  220. }
  221. int w_Mesh_attachAttribute(lua_State *L)
  222. {
  223. Mesh *t = luax_checkmesh(L, 1);
  224. const char *name = luaL_checkstring(L, 2);
  225. Buffer *buffer = nullptr;
  226. Mesh *mesh = nullptr;
  227. if (luax_istype(L, 3, Buffer::type))
  228. {
  229. buffer = luax_checktype<Buffer>(L, 3);
  230. }
  231. else
  232. {
  233. mesh = luax_checkmesh(L, 3);
  234. buffer = mesh->getVertexBuffer();
  235. if (buffer == nullptr)
  236. return luaL_error(L, "Mesh does not have its own vertex buffer.");
  237. }
  238. AttributeStep step = STEP_PER_VERTEX;
  239. const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
  240. if (stepstr != nullptr && !getConstant(stepstr, step))
  241. return luax_enumerror(L, "vertex attribute step", getConstants(step), stepstr);
  242. const char *attachname = luaL_optstring(L, 5, name);
  243. luax_catchexcept(L, [&](){ t->attachAttribute(name, buffer, mesh, attachname, step); });
  244. return 0;
  245. }
  246. int w_Mesh_detachAttribute(lua_State *L)
  247. {
  248. Mesh *t = luax_checkmesh(L, 1);
  249. const char *name = luaL_checkstring(L, 2);
  250. bool success = false;
  251. luax_catchexcept(L, [&](){ success = t->detachAttribute(name); });
  252. luax_pushboolean(L, success);
  253. return 1;
  254. }
  255. int w_Mesh_getAttachedAttributes(lua_State *L)
  256. {
  257. Mesh *t = luax_checkmesh(L, 1);
  258. const auto &attributes = t->getAttachedAttributes();
  259. lua_createtable(L, (int) attributes.size(), 0);
  260. for (int i = 0; i < (int) attributes.size(); i++)
  261. {
  262. const auto &attrib = attributes[i];
  263. lua_createtable(L, 4, 0);
  264. luax_pushstring(L, attrib.name);
  265. lua_rawseti(L, -1, 1);
  266. luax_pushtype(L, attrib.buffer.get());
  267. lua_rawseti(L, -1, 2);
  268. const char *stepstr = nullptr;
  269. if (!getConstant(attrib.step, stepstr))
  270. return luaL_error(L, "Invalid vertex attribute step.");
  271. lua_pushstring(L, stepstr);
  272. lua_rawseti(L, -1, 3);
  273. const Buffer::DataMember &member = attrib.buffer->getDataMember(attrib.indexInBuffer);
  274. luax_pushstring(L, member.decl.name);
  275. lua_rawseti(L, -1, 4);
  276. lua_rawseti(L, -1, i + 1);
  277. }
  278. return 1;
  279. }
  280. int w_Mesh_getVertexBuffer(lua_State *L)
  281. {
  282. Mesh *t = luax_checkmesh(L, 1);
  283. luax_pushtype(L, t->getVertexBuffer());
  284. return 1;
  285. }
  286. int w_Mesh_flush(lua_State *L)
  287. {
  288. Mesh *t = luax_checkmesh(L, 1);
  289. t->flush();
  290. return 0;
  291. }
  292. int w_Mesh_setVertexMap(lua_State *L)
  293. {
  294. Mesh *t = luax_checkmesh(L, 1);
  295. if (lua_isnoneornil(L, 2))
  296. {
  297. // Disable the vertex map / index buffer.
  298. luax_catchexcept(L, [&](){ t->setVertexMap(); });
  299. return 0;
  300. }
  301. if (luax_istype(L, 2, Data::type))
  302. {
  303. Data *d = luax_totype<Data>(L, 2, Data::type);
  304. const char *indextypestr = luaL_checkstring(L, 3);
  305. IndexDataType indextype;
  306. if (!getConstant(indextypestr, indextype))
  307. return luax_enumerror(L, "index data type", getConstants(indextype), indextypestr);
  308. size_t datatypesize = getIndexDataSize(indextype);
  309. int indexcount = (int) luaL_optinteger(L, 4, d->getSize() / datatypesize);
  310. if (indexcount < 1 || indexcount * datatypesize > d->getSize())
  311. return luaL_error(L, "Invalid index count: %d", indexcount);
  312. luax_catchexcept(L, [&]() { t->setVertexMap(indextype, d->getData(), indexcount * datatypesize); });
  313. return 0;
  314. }
  315. bool is_table = lua_istable(L, 2);
  316. int nargs = is_table ? (int) luax_objlen(L, 2) : lua_gettop(L) - 1;
  317. std::vector<uint32> vertexmap;
  318. vertexmap.reserve(nargs);
  319. if (is_table)
  320. {
  321. for (int i = 0; i < nargs; i++)
  322. {
  323. lua_rawgeti(L, 2, i + 1);
  324. vertexmap.push_back(uint32(luaL_checkinteger(L, -1) - 1));
  325. lua_pop(L, 1);
  326. }
  327. }
  328. else
  329. {
  330. for (int i = 0; i < nargs; i++)
  331. vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
  332. }
  333. luax_catchexcept(L, [&](){ t->setVertexMap(vertexmap); });
  334. return 0;
  335. }
  336. int w_Mesh_getVertexMap(lua_State *L)
  337. {
  338. Mesh *t = luax_checkmesh(L, 1);
  339. std::vector<uint32> vertex_map;
  340. bool has_vertex_map = false;
  341. luax_catchexcept(L, [&](){ has_vertex_map = t->getVertexMap(vertex_map); });
  342. if (!has_vertex_map)
  343. {
  344. lua_pushnil(L);
  345. return 1;
  346. }
  347. int element_count = (int) vertex_map.size();
  348. lua_createtable(L, element_count, 0);
  349. for (int i = 0; i < element_count; i++)
  350. {
  351. lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
  352. lua_rawseti(L, -2, i + 1);
  353. }
  354. return 1;
  355. }
  356. int w_Mesh_setIndexBuffer(lua_State *L)
  357. {
  358. Mesh *t = luax_checkmesh(L, 1);
  359. Buffer *b = nullptr;
  360. if (!lua_isnoneornil(L, 2))
  361. b = luax_checkbuffer(L, 2);
  362. luax_catchexcept(L, [&]() { t->setIndexBuffer(b); });
  363. return 0;
  364. }
  365. int w_Mesh_getIndexBuffer(lua_State *L)
  366. {
  367. Mesh *t = luax_checkmesh(L, 1);
  368. luax_pushtype(L, t->getIndexBuffer());
  369. return 1;
  370. }
  371. int w_Mesh_setTexture(lua_State *L)
  372. {
  373. Mesh *t = luax_checkmesh(L, 1);
  374. if (lua_isnoneornil(L, 2))
  375. t->setTexture();
  376. else
  377. {
  378. Texture *tex = luax_checktexture(L, 2);
  379. luax_catchexcept(L, [&](){ t->setTexture(tex); });
  380. }
  381. return 0;
  382. }
  383. int w_Mesh_getTexture(lua_State *L)
  384. {
  385. Mesh *t = luax_checkmesh(L, 1);
  386. Texture *tex = t->getTexture();
  387. if (tex == nullptr)
  388. return 0;
  389. luax_pushtype(L, tex);
  390. return 1;
  391. }
  392. int w_Mesh_setDrawMode(lua_State *L)
  393. {
  394. Mesh *t = luax_checkmesh(L, 1);
  395. const char *str = luaL_checkstring(L, 2);
  396. PrimitiveType mode;
  397. if (!getConstant(str, mode))
  398. return luax_enumerror(L, "mesh draw mode", getConstants(mode), str);
  399. t->setDrawMode(mode);
  400. return 0;
  401. }
  402. int w_Mesh_getDrawMode(lua_State *L)
  403. {
  404. Mesh *t = luax_checkmesh(L, 1);
  405. PrimitiveType mode = t->getDrawMode();
  406. const char *str;
  407. if (!getConstant(mode, str))
  408. return luaL_error(L, "Unknown mesh draw mode.");
  409. lua_pushstring(L, str);
  410. return 1;
  411. }
  412. int w_Mesh_setDrawRange(lua_State *L)
  413. {
  414. Mesh *t = luax_checkmesh(L, 1);
  415. if (lua_isnoneornil(L, 2))
  416. t->setDrawRange();
  417. else
  418. {
  419. int start = (int) luaL_checkinteger(L, 2) - 1;
  420. int count = (int) luaL_checkinteger(L, 3);
  421. luax_catchexcept(L, [&](){ t->setDrawRange(start, count); });
  422. }
  423. return 0;
  424. }
  425. int w_Mesh_getDrawRange(lua_State *L)
  426. {
  427. Mesh *t = luax_checkmesh(L, 1);
  428. int start = 0;
  429. int count = 1;
  430. if (!t->getDrawRange(start, count))
  431. return 0;
  432. lua_pushinteger(L, start + 1);
  433. lua_pushinteger(L, count);
  434. return 2;
  435. }
  436. static const luaL_Reg w_Mesh_functions[] =
  437. {
  438. { "setVertices", w_Mesh_setVertices },
  439. { "setVertex", w_Mesh_setVertex },
  440. { "getVertex", w_Mesh_getVertex },
  441. { "setVertexAttribute", w_Mesh_setVertexAttribute },
  442. { "getVertexAttribute", w_Mesh_getVertexAttribute },
  443. { "getVertexCount", w_Mesh_getVertexCount },
  444. { "getVertexFormat", w_Mesh_getVertexFormat },
  445. { "setAttributeEnabled", w_Mesh_setAttributeEnabled },
  446. { "isAttributeEnabled", w_Mesh_isAttributeEnabled },
  447. { "attachAttribute", w_Mesh_attachAttribute },
  448. { "detachAttribute", w_Mesh_detachAttribute },
  449. { "getAttachedAttributes", w_Mesh_getAttachedAttributes },
  450. { "getVertexBuffer", w_Mesh_getVertexBuffer },
  451. { "flush", w_Mesh_flush },
  452. { "setVertexMap", w_Mesh_setVertexMap },
  453. { "getVertexMap", w_Mesh_getVertexMap },
  454. { "setIndexBuffer", w_Mesh_setIndexBuffer },
  455. { "getIndexBuffer", w_Mesh_getIndexBuffer },
  456. { "setTexture", w_Mesh_setTexture },
  457. { "getTexture", w_Mesh_getTexture },
  458. { "setDrawMode", w_Mesh_setDrawMode },
  459. { "getDrawMode", w_Mesh_getDrawMode },
  460. { "setDrawRange", w_Mesh_setDrawRange },
  461. { "getDrawRange", w_Mesh_getDrawRange },
  462. { 0, 0 }
  463. };
  464. extern "C" int luaopen_mesh(lua_State *L)
  465. {
  466. return luax_register_type(L, &Mesh::type, w_Mesh_functions, nullptr);
  467. }
  468. } // graphics
  469. } // love