Mesh.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /**
  2. * Copyright (c) 2006-2024 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 "Mesh.h"
  22. #include "common/Matrix.h"
  23. #include "common/Exception.h"
  24. #include "Shader.h"
  25. #include "Graphics.h"
  26. // C++
  27. #include <algorithm>
  28. #include <limits>
  29. namespace love
  30. {
  31. namespace graphics
  32. {
  33. static_assert(offsetof(Vertex, x) == sizeof(float) * 0, "Incorrect position offset in Vertex struct");
  34. static_assert(offsetof(Vertex, s) == sizeof(float) * 2, "Incorrect texture coordinate offset in Vertex struct");
  35. static_assert(offsetof(Vertex, color.r) == sizeof(float) * 4, "Incorrect color offset in Vertex struct");
  36. std::vector<Buffer::DataDeclaration> Mesh::getDefaultVertexFormat()
  37. {
  38. return Buffer::getCommonFormatDeclaration(CommonFormat::XYf_STf_RGBAub);
  39. }
  40. love::Type Mesh::type("Mesh", &Drawable::type);
  41. Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage)
  42. : primitiveType(drawmode)
  43. {
  44. try
  45. {
  46. vertexData = new uint8[datasize];
  47. }
  48. catch (std::exception &)
  49. {
  50. throw love::Exception("Out of memory");
  51. }
  52. memcpy(vertexData, data, datasize);
  53. Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, usage);
  54. vertexBuffer.set(gfx->newBuffer(settings, vertexformat, vertexData, datasize, 0), Acquire::NORETAIN);
  55. vertexCount = vertexBuffer->getArrayLength();
  56. vertexStride = vertexBuffer->getArrayStride();
  57. vertexFormat = vertexBuffer->getDataMembers();
  58. setupAttachedAttributes();
  59. indexDataType = getIndexDataTypeFromMax(vertexCount);
  60. }
  61. Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage)
  62. : vertexCount((size_t) vertexcount)
  63. , indexDataType(getIndexDataTypeFromMax(vertexcount))
  64. , primitiveType(drawmode)
  65. {
  66. if (vertexcount <= 0)
  67. throw love::Exception("Invalid number of vertices (%d).", vertexcount);
  68. Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, usage);
  69. vertexBuffer.set(gfx->newBuffer(settings, vertexformat, nullptr, 0, vertexcount), Acquire::NORETAIN);
  70. vertexStride = vertexBuffer->getArrayStride();
  71. vertexFormat = vertexBuffer->getDataMembers();
  72. setupAttachedAttributes();
  73. try
  74. {
  75. vertexData = new uint8[vertexBuffer->getSize()];
  76. }
  77. catch (std::exception &)
  78. {
  79. throw love::Exception("Out of memory");
  80. }
  81. memset(vertexData, 0, vertexBuffer->getSize());
  82. vertexBuffer->fill(0, vertexBuffer->getSize(), vertexData);
  83. }
  84. Mesh::Mesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode)
  85. : primitiveType(drawmode)
  86. {
  87. if (attributes.size() == 0)
  88. throw love::Exception("At least one buffer attribute must be specified in this constructor.");
  89. attachedAttributes = attributes;
  90. vertexCount = attachedAttributes.size() > 0 ? LOVE_UINT32_MAX : 0;
  91. for (int i = 0; i < (int) attachedAttributes.size(); i++)
  92. {
  93. auto &attrib = attachedAttributes[i];
  94. finalizeAttribute(attrib);
  95. if (attrib.bindingLocation >= 0)
  96. {
  97. int attributeIndex = getAttachedAttributeIndex(attrib.bindingLocation);
  98. if (attributeIndex != i && attributeIndex != -1)
  99. throw love::Exception("Duplicate vertex attribute binding location: %d", attrib.bindingLocation);
  100. }
  101. if (!attrib.name.empty())
  102. {
  103. int attributeIndex = getAttachedAttributeIndex(attrib.name);
  104. if (attributeIndex != i && attributeIndex != -1)
  105. throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str());
  106. }
  107. vertexCount = std::min(vertexCount, attrib.buffer->getArrayLength());
  108. }
  109. indexDataType = getIndexDataTypeFromMax(vertexCount);
  110. }
  111. Mesh::~Mesh()
  112. {
  113. delete vertexData;
  114. if (indexData != nullptr)
  115. free(indexData);
  116. }
  117. void Mesh::setupAttachedAttributes()
  118. {
  119. for (size_t i = 0; i < vertexFormat.size(); i++)
  120. {
  121. const std::string &name = vertexFormat[i].decl.name;
  122. int bindingLocation = vertexFormat[i].decl.bindingLocation;
  123. if (bindingLocation >= 0)
  124. {
  125. if (getAttachedAttributeIndex(bindingLocation) != -1)
  126. throw love::Exception("Duplicate vertex attribute binding location: %d", bindingLocation);
  127. }
  128. if (!name.empty())
  129. {
  130. if (getAttachedAttributeIndex(name) != -1)
  131. throw love::Exception("Duplicate vertex attribute name: %s", name.c_str());
  132. }
  133. if (bindingLocation < 0)
  134. {
  135. BuiltinVertexAttribute builtinattrib;
  136. if (getConstant(name.c_str(), builtinattrib))
  137. bindingLocation = (int)builtinattrib;
  138. }
  139. attachedAttributes.push_back({name, vertexBuffer, nullptr, name, bindingLocation, (int) i, 0, STEP_PER_VERTEX, bindingLocation, true});
  140. }
  141. }
  142. int Mesh::getAttachedAttributeIndex(const std::string &name) const
  143. {
  144. for (int i = 0; i < (int) attachedAttributes.size(); i++)
  145. {
  146. if (attachedAttributes[i].name == name)
  147. return i;
  148. }
  149. return -1;
  150. }
  151. int Mesh::getAttachedAttributeIndex(int bindingLocation) const
  152. {
  153. for (int i = 0; i < (int)attachedAttributes.size(); i++)
  154. {
  155. if (attachedAttributes[i].bindingLocation == bindingLocation)
  156. return i;
  157. }
  158. return -1;
  159. }
  160. void Mesh::finalizeAttribute(BufferAttribute &attrib) const
  161. {
  162. if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
  163. throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
  164. if (attrib.startArrayIndex < 0 || attrib.startArrayIndex >= (int)attrib.buffer->getArrayLength())
  165. throw love::Exception("Invalid start array index %d.", attrib.startArrayIndex + 1);
  166. if (attrib.bindingLocationInBuffer >= 0)
  167. {
  168. int indexInBuffer = attrib.buffer->getDataMemberIndex(attrib.bindingLocationInBuffer);
  169. if (indexInBuffer < 0)
  170. throw love::Exception("Buffer does not have a vertex attribute with binding location %d.", attrib.bindingLocationInBuffer);
  171. attrib.indexInBuffer = indexInBuffer;
  172. }
  173. else
  174. {
  175. int indexInBuffer = attrib.buffer->getDataMemberIndex(attrib.nameInBuffer);
  176. if (indexInBuffer < 0)
  177. throw love::Exception("Buffer does not have a vertex attribute with name '%s'.", attrib.nameInBuffer.c_str());
  178. attrib.indexInBuffer = indexInBuffer;
  179. }
  180. if (attrib.bindingLocation < 0)
  181. attrib.bindingLocation = attrib.buffer->getDataMember(attrib.indexInBuffer).decl.bindingLocation;
  182. if (attrib.bindingLocation < 0)
  183. {
  184. BuiltinVertexAttribute builtinattrib;
  185. if (getConstant(attrib.name.c_str(), builtinattrib))
  186. attrib.bindingLocation = (int)builtinattrib;
  187. }
  188. if (attrib.bindingLocation >= (int) VertexAttributes::MAX || (attrib.bindingLocation < 0 && attrib.name.empty()))
  189. throw love::Exception("Vertex attributes must have a valid binding location value within [0, %d).", VertexAttributes::MAX);
  190. }
  191. void *Mesh::checkVertexDataOffset(size_t vertindex, size_t *byteoffset)
  192. {
  193. if (vertindex >= vertexCount)
  194. throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
  195. if (vertexData == nullptr)
  196. throw love::Exception("Mesh must own its own vertex buffer.");
  197. size_t offset = vertindex * vertexStride;
  198. if (byteoffset != nullptr)
  199. *byteoffset = offset;
  200. return vertexData + offset;
  201. }
  202. size_t Mesh::getVertexCount() const
  203. {
  204. return vertexCount;
  205. }
  206. size_t Mesh::getVertexStride() const
  207. {
  208. return vertexStride;
  209. }
  210. Buffer *Mesh::getVertexBuffer() const
  211. {
  212. return vertexBuffer;
  213. }
  214. const std::vector<Buffer::DataMember> &Mesh::getVertexFormat() const
  215. {
  216. return vertexFormat;
  217. }
  218. void Mesh::setAttributeEnabled(const std::string &name, bool enable)
  219. {
  220. int index = getAttachedAttributeIndex(name);
  221. if (index == -1)
  222. throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
  223. attachedAttributes[index].enabled = enable;
  224. attributesID.invalidate();
  225. }
  226. bool Mesh::isAttributeEnabled(const std::string &name) const
  227. {
  228. int index = getAttachedAttributeIndex(name);
  229. if (index == -1)
  230. throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
  231. return attachedAttributes[index].enabled;
  232. }
  233. void Mesh::setAttributeEnabled(int bindingLocation, bool enable)
  234. {
  235. int index = getAttachedAttributeIndex(bindingLocation);
  236. if (index == -1)
  237. throw love::Exception("Mesh does not have an attached vertex attribute with binding location %d", bindingLocation);
  238. attachedAttributes[index].enabled = enable;
  239. attributesID.invalidate();
  240. }
  241. bool Mesh::isAttributeEnabled(int bindingLocation) const
  242. {
  243. int index = getAttachedAttributeIndex(bindingLocation);
  244. if (index == -1)
  245. throw love::Exception("Mesh does not have an attached vertex attribute with binding location %d", bindingLocation);
  246. return attachedAttributes[index].enabled;
  247. }
  248. void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, int startindex, AttributeStep step)
  249. {
  250. BufferAttribute oldattrib;
  251. BufferAttribute newattrib;
  252. int oldindex = getAttachedAttributeIndex(name);
  253. if (oldindex != -1)
  254. oldattrib = attachedAttributes[oldindex];
  255. else if (attachedAttributes.size() + 1 > VertexAttributes::MAX)
  256. throw love::Exception("A maximum of %d attributes can be attached at once.", VertexAttributes::MAX);
  257. newattrib.name = name;
  258. newattrib.buffer = buffer;
  259. newattrib.mesh = mesh;
  260. newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
  261. newattrib.nameInBuffer = attachname;
  262. newattrib.indexInBuffer = -1;
  263. newattrib.startArrayIndex = startindex;
  264. newattrib.step = step;
  265. finalizeAttribute(newattrib);
  266. if (oldindex != -1)
  267. attachedAttributes[oldindex] = newattrib;
  268. else
  269. attachedAttributes.push_back(newattrib);
  270. attributesID.invalidate();
  271. }
  272. void Mesh::attachAttribute(int bindingLocation, Buffer *buffer, Mesh *mesh, int attachBindingLocation, int startindex, AttributeStep step)
  273. {
  274. BufferAttribute oldattrib;
  275. BufferAttribute newattrib;
  276. int oldindex = getAttachedAttributeIndex(bindingLocation);
  277. if (oldindex != -1)
  278. oldattrib = attachedAttributes[oldindex];
  279. else if (attachedAttributes.size() + 1 > VertexAttributes::MAX)
  280. throw love::Exception("A maximum of %d attributes can be attached at once.", VertexAttributes::MAX);
  281. newattrib.bindingLocation = bindingLocation;
  282. newattrib.buffer = buffer;
  283. newattrib.mesh = mesh;
  284. newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
  285. newattrib.bindingLocationInBuffer = attachBindingLocation;
  286. newattrib.indexInBuffer = -1;
  287. newattrib.startArrayIndex = startindex;
  288. newattrib.step = step;
  289. finalizeAttribute(newattrib);
  290. if (oldindex != -1)
  291. attachedAttributes[oldindex] = newattrib;
  292. else
  293. attachedAttributes.push_back(newattrib);
  294. attributesID.invalidate();
  295. }
  296. bool Mesh::detachAttribute(const std::string &name)
  297. {
  298. int index = getAttachedAttributeIndex(name);
  299. if (index == -1)
  300. return false;
  301. attachedAttributes.erase(attachedAttributes.begin() + index);
  302. if (vertexBuffer.get() && vertexBuffer->getDataMemberIndex(name) != -1)
  303. attachAttribute(name, vertexBuffer, nullptr, name);
  304. attributesID.invalidate();
  305. return true;
  306. }
  307. bool Mesh::detachAttribute(int bindingLocation)
  308. {
  309. int index = getAttachedAttributeIndex(bindingLocation);
  310. if (index == -1)
  311. return false;
  312. attachedAttributes.erase(attachedAttributes.begin() + index);
  313. if (vertexBuffer.get() && vertexBuffer->getDataMemberIndex(bindingLocation) != -1)
  314. attachAttribute(bindingLocation, vertexBuffer, nullptr, bindingLocation);
  315. attributesID.invalidate();
  316. return true;
  317. }
  318. const std::vector<Mesh::BufferAttribute> &Mesh::getAttachedAttributes() const
  319. {
  320. return attachedAttributes;
  321. }
  322. void *Mesh::getVertexData() const
  323. {
  324. return vertexData;
  325. }
  326. void Mesh::setVertexDataModified(size_t offset, size_t size)
  327. {
  328. if (vertexData != nullptr)
  329. modifiedVertexData.encapsulate(offset, size);
  330. }
  331. void Mesh::flush()
  332. {
  333. if (vertexBuffer.get() && vertexData != nullptr && modifiedVertexData.isValid())
  334. {
  335. if (vertexBuffer->getDataUsage() == BUFFERDATAUSAGE_STREAM)
  336. {
  337. vertexBuffer->fill(0, vertexBuffer->getSize(), vertexData);
  338. }
  339. else
  340. {
  341. size_t offset = modifiedVertexData.getOffset();
  342. size_t size = modifiedVertexData.getSize();
  343. vertexBuffer->fill(offset, size, vertexData + offset);
  344. }
  345. modifiedVertexData.invalidate();
  346. }
  347. if (indexDataModified && indexData != nullptr && indexBuffer != nullptr)
  348. {
  349. indexBuffer->fill(0, indexBuffer->getSize(), indexData);
  350. indexDataModified = false;
  351. }
  352. }
  353. /**
  354. * Copies index data from a vector to a mapped index buffer.
  355. **/
  356. template <typename T>
  357. static void copyToIndexBuffer(const std::vector<uint32> &indices, void *data, size_t maxval)
  358. {
  359. T *elems = (T *) data;
  360. for (size_t i = 0; i < indices.size(); i++)
  361. {
  362. if (indices[i] >= maxval)
  363. throw love::Exception("Invalid vertex map value: %d", indices[i] + 1);
  364. elems[i] = (T) indices[i];
  365. }
  366. }
  367. void Mesh::setVertexMap(const std::vector<uint32> &map)
  368. {
  369. if (map.empty())
  370. throw love::Exception("Vertex map array must not be empty.");
  371. size_t maxval = getVertexCount();
  372. IndexDataType datatype = getIndexDataTypeFromMax(maxval);
  373. DataFormat dataformat = getIndexDataFormat(datatype);
  374. // Calculate the size in bytes of the index buffer data.
  375. size_t size = map.size() * getIndexDataSize(datatype);
  376. bool recreate = indexData == nullptr || indexBuffer.get() == nullptr
  377. || size > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat;
  378. if (recreate)
  379. {
  380. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  381. auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
  382. Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
  383. auto buffer = StrongRef<Buffer>(gfx->newBuffer(settings, dataformat, nullptr, size, 0), Acquire::NORETAIN);
  384. auto data = (uint8 *) realloc(indexData, size);
  385. if (data == nullptr)
  386. throw love::Exception("Out of memory.");
  387. indexData = data;
  388. indexBuffer = buffer;
  389. }
  390. indexCount = map.size();
  391. useIndexBuffer = true;
  392. indexDataType = datatype;
  393. if (indexCount == 0)
  394. return;
  395. // Fill the buffer with the index values from the vector.
  396. switch (datatype)
  397. {
  398. case INDEX_UINT16:
  399. copyToIndexBuffer<uint16>(map, indexData, maxval);
  400. break;
  401. case INDEX_UINT32:
  402. default:
  403. copyToIndexBuffer<uint32>(map, indexData, maxval);
  404. break;
  405. }
  406. indexDataModified = true;
  407. }
  408. void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize)
  409. {
  410. DataFormat dataformat = getIndexDataFormat(datatype);
  411. bool recreate = indexData == nullptr || indexBuffer.get() == nullptr
  412. || datasize > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat;
  413. if (recreate)
  414. {
  415. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  416. auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
  417. Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
  418. auto buffer = StrongRef<Buffer>(gfx->newBuffer(settings, dataformat, nullptr, datasize, 0), Acquire::NORETAIN);
  419. auto data = (uint8 *) realloc(indexData, datasize);
  420. if (data == nullptr)
  421. throw love::Exception("Out of memory.");
  422. indexData = data;
  423. indexBuffer = buffer;
  424. }
  425. indexCount = datasize / getIndexDataSize(datatype);
  426. useIndexBuffer = true;
  427. indexDataType = datatype;
  428. if (indexCount == 0)
  429. return;
  430. memcpy(indexData, data, datasize);
  431. indexDataModified = true;
  432. }
  433. void Mesh::setVertexMap()
  434. {
  435. useIndexBuffer = false;
  436. }
  437. /**
  438. * Copies index data from a mapped buffer to a vector.
  439. **/
  440. template <typename T>
  441. static void copyFromIndexBuffer(const void *buffer, size_t count, std::vector<uint32> &indices)
  442. {
  443. const T *elems = (const T *) buffer;
  444. for (size_t i = 0; i < count; i++)
  445. indices.push_back((uint32) elems[i]);
  446. }
  447. bool Mesh::getVertexMap(std::vector<uint32> &map) const
  448. {
  449. if (!useIndexBuffer)
  450. return false;
  451. map.clear();
  452. if (indexData == nullptr || indexCount == 0)
  453. return true;
  454. map.reserve(indexCount);
  455. // Fill the vector from the buffer.
  456. switch (indexDataType)
  457. {
  458. case INDEX_UINT16:
  459. copyFromIndexBuffer<uint16>(indexData, indexCount, map);
  460. break;
  461. case INDEX_UINT32:
  462. default:
  463. copyFromIndexBuffer<uint32>(indexData, indexCount, map);
  464. break;
  465. }
  466. return true;
  467. }
  468. void Mesh::setIndexBuffer(Buffer *buffer)
  469. {
  470. // Buffer constructor does the rest of the validation for index buffers
  471. // (data member formats, etc.)
  472. if (buffer != nullptr && (buffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX) == 0)
  473. throw love::Exception("setIndexBuffer requires a Buffer created as an index buffer.");
  474. indexBuffer.set(buffer);
  475. useIndexBuffer = buffer != nullptr;
  476. indexCount = buffer != nullptr ? buffer->getArrayLength() : 0;
  477. if (buffer != nullptr)
  478. indexDataType = getIndexDataType(buffer->getDataMember(0).decl.format);
  479. if (indexData != nullptr)
  480. {
  481. free(indexData);
  482. indexData = nullptr;
  483. }
  484. }
  485. Buffer *Mesh::getIndexBuffer() const
  486. {
  487. return indexBuffer;
  488. }
  489. size_t Mesh::getIndexCount() const
  490. {
  491. return indexCount;
  492. }
  493. void Mesh::setTexture(Texture *tex)
  494. {
  495. texture.set(tex);
  496. }
  497. void Mesh::setTexture()
  498. {
  499. texture.set(nullptr);
  500. }
  501. Texture *Mesh::getTexture() const
  502. {
  503. return texture.get();
  504. }
  505. void Mesh::setDrawMode(PrimitiveType mode)
  506. {
  507. primitiveType = mode;
  508. }
  509. PrimitiveType Mesh::getDrawMode() const
  510. {
  511. return primitiveType;
  512. }
  513. void Mesh::setDrawRange(int start, int count)
  514. {
  515. if (start < 0 || count <= 0)
  516. throw love::Exception("Invalid draw range.");
  517. drawRange = Range(start, count);
  518. }
  519. void Mesh::setDrawRange()
  520. {
  521. drawRange.invalidate();
  522. }
  523. bool Mesh::getDrawRange(int &start, int &count) const
  524. {
  525. if (!drawRange.isValid())
  526. return false;
  527. start = (int) drawRange.getOffset();
  528. count = (int) drawRange.getSize();
  529. return true;
  530. }
  531. void Mesh::updateVertexAttributes(Graphics *gfx)
  532. {
  533. VertexAttributes attributes;
  534. BufferBindings &buffers = bufferBindings;
  535. int activebuffers = 0;
  536. for (const auto &attrib : attachedAttributes)
  537. {
  538. if (!attrib.enabled)
  539. continue;
  540. Buffer *buffer = attrib.buffer.get();
  541. int bindinglocation = attrib.bindingLocation;
  542. // Query the index from the shader as a fallback to support old code that
  543. // hasn't set a binding location.
  544. if (bindinglocation < 0 && Shader::current)
  545. bindinglocation = Shader::current->getVertexAttributeIndex(attrib.name);
  546. if (bindinglocation >= 0)
  547. {
  548. const auto &member = buffer->getDataMember(attrib.indexInBuffer);
  549. uint16 offset = (uint16)member.offset;
  550. uint16 stride = (uint16)buffer->getArrayStride();
  551. size_t bufferoffset = (size_t)stride * attrib.startArrayIndex;
  552. int bufferindex = activebuffers;
  553. for (int i = 0; i < activebuffers; i++)
  554. {
  555. if (buffers.info[i].buffer == buffer && buffers.info[i].offset == bufferoffset
  556. && attributes.bufferLayouts[i].stride == stride && attributes.getBufferStep(i) == attrib.step)
  557. {
  558. bufferindex = i;
  559. break;
  560. }
  561. }
  562. attributes.set(bindinglocation, member.decl.format, offset, bufferindex);
  563. attributes.setBufferLayout(bufferindex, stride, attrib.step);
  564. buffers.set(bufferindex, buffer, bufferoffset);
  565. activebuffers = std::max(activebuffers, bufferindex + 1);
  566. }
  567. }
  568. attributesID = gfx->registerVertexAttributes(attributes);
  569. }
  570. void Mesh::draw(Graphics *gfx, const love::Matrix4 &m)
  571. {
  572. drawInternal(gfx, m, 1, nullptr, 0);
  573. }
  574. void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
  575. {
  576. drawInternal(gfx, m, instancecount, nullptr, 0);
  577. }
  578. void Mesh::drawIndirect(Graphics *gfx, const Matrix4 &m, Buffer *indirectargs, int argsindex)
  579. {
  580. drawInternal(gfx, m, 0, indirectargs, argsindex);
  581. }
  582. void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buffer *indirectargs, int argsindex)
  583. {
  584. if (vertexCount <= 0 || (instancecount <= 0 && indirectargs == nullptr))
  585. return;
  586. if (indirectargs != nullptr)
  587. {
  588. if (primitiveType == PRIMITIVE_TRIANGLE_FAN)
  589. throw love::Exception("The fan draw mode is not supported in indirect draws.");
  590. if (useIndexBuffer && indexBuffer != nullptr)
  591. gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_INDICES, indirectargs, argsindex);
  592. else
  593. gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_VERTICES, indirectargs, argsindex);
  594. }
  595. // Some graphics backends don't natively support triangle fans. So we'd
  596. // have to emulate them with triangles plus an index buffer... which doesn't
  597. // work so well when there's already a custom index buffer.
  598. if (primitiveType == PRIMITIVE_TRIANGLE_FAN && useIndexBuffer && indexBuffer != nullptr)
  599. throw love::Exception("The 'fan' Mesh draw mode cannot be used with an index buffer / vertex map.");
  600. gfx->flushBatchedDraws();
  601. flush();
  602. if (Shader::isDefaultActive())
  603. Shader::attachDefault(primitiveType == PRIMITIVE_POINTS ? Shader::STANDARD_POINTS : Shader::STANDARD_DEFAULT);
  604. if (Shader::current)
  605. Shader::current->validateDrawState(primitiveType, texture);
  606. bool attributesIDneedsupdate = !attributesID.isValid();
  607. for (const auto &attrib : attachedAttributes)
  608. {
  609. if (!attrib.enabled)
  610. continue;
  611. if (attrib.mesh.get())
  612. attrib.mesh->flush();
  613. // Query the index from the shader as a fallback to support old code that
  614. // hasn't set a binding location.
  615. if (attrib.bindingLocation < 0)
  616. attributesIDneedsupdate = true;
  617. }
  618. if (attributesIDneedsupdate)
  619. updateVertexAttributes(gfx);
  620. Graphics::TempTransform transform(gfx, m);
  621. Buffer *indexbuffer = useIndexBuffer ? indexBuffer : nullptr;
  622. int indexcount = (int) indexCount;
  623. Range range = drawRange;
  624. // Emulated triangle fan via an index buffer.
  625. if (primitiveType == PRIMITIVE_TRIANGLE_FAN && indexbuffer == nullptr && gfx->getFanIndexBuffer())
  626. {
  627. indexbuffer = gfx->getFanIndexBuffer();
  628. indexcount = graphics::getIndexCount(TRIANGLEINDEX_FAN, vertexCount);
  629. if (range.isValid())
  630. {
  631. int start = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getOffset());
  632. int count = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getSize());
  633. range = Range(start, count);
  634. }
  635. }
  636. if (indexbuffer != nullptr && (indexcount > 0 || indirectargs != nullptr))
  637. {
  638. Range r(0, indexcount);
  639. if (range.isValid())
  640. r.intersect(range);
  641. Graphics::DrawIndexedCommand cmd(attributesID, &bufferBindings, indexbuffer);
  642. cmd.primitiveType = primitiveType;
  643. cmd.indexType = indexDataType;
  644. cmd.instanceCount = instancecount;
  645. cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture);
  646. cmd.cullMode = gfx->getMeshCullMode();
  647. cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride();
  648. cmd.indexCount = (int) r.getSize();
  649. cmd.indirectBuffer = indirectargs;
  650. cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
  651. if (cmd.indexCount > 0)
  652. gfx->draw(cmd);
  653. }
  654. else if (vertexCount > 0 || indirectargs != nullptr)
  655. {
  656. Range r(0, vertexCount);
  657. if (range.isValid())
  658. r.intersect(range);
  659. Graphics::DrawCommand cmd(attributesID, &bufferBindings);
  660. cmd.primitiveType = primitiveType;
  661. cmd.vertexStart = (int) r.getOffset();
  662. cmd.vertexCount = (int) r.getSize();
  663. cmd.instanceCount = instancecount;
  664. cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture);
  665. cmd.cullMode = gfx->getMeshCullMode();
  666. cmd.indirectBuffer = indirectargs;
  667. cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
  668. if (cmd.vertexCount > 0)
  669. gfx->draw(cmd);
  670. }
  671. }
  672. } // graphics
  673. } // love