Mesh.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /**
  2. * Copyright (c) 2006-2023 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 (const auto &attrib : attachedAttributes)
  92. {
  93. if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
  94. throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
  95. if (getAttachedAttributeIndex(attrib.name) != -1)
  96. throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str());
  97. vertexCount = std::min(vertexCount, attrib.buffer->getArrayLength());
  98. }
  99. indexDataType = getIndexDataTypeFromMax(vertexCount);
  100. }
  101. Mesh::~Mesh()
  102. {
  103. delete vertexData;
  104. if (indexData != nullptr)
  105. free(indexData);
  106. }
  107. void Mesh::setupAttachedAttributes()
  108. {
  109. for (size_t i = 0; i < vertexFormat.size(); i++)
  110. {
  111. const std::string &name = vertexFormat[i].decl.name;
  112. if (getAttachedAttributeIndex(name) != -1)
  113. throw love::Exception("Duplicate vertex attribute name: %s", name.c_str());
  114. attachedAttributes.push_back({name, vertexBuffer, nullptr, (int) i, 0, STEP_PER_VERTEX, true});
  115. }
  116. }
  117. int Mesh::getAttachedAttributeIndex(const std::string &name) const
  118. {
  119. for (int i = 0; i < (int) attachedAttributes.size(); i++)
  120. {
  121. if (attachedAttributes[i].name == name)
  122. return i;
  123. }
  124. return -1;
  125. }
  126. void *Mesh::checkVertexDataOffset(size_t vertindex, size_t *byteoffset)
  127. {
  128. if (vertindex >= vertexCount)
  129. throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
  130. if (vertexData == nullptr)
  131. throw love::Exception("Mesh must own its own vertex buffer.");
  132. size_t offset = vertindex * vertexStride;
  133. if (byteoffset != nullptr)
  134. *byteoffset = offset;
  135. return vertexData + offset;
  136. }
  137. size_t Mesh::getVertexCount() const
  138. {
  139. return vertexCount;
  140. }
  141. size_t Mesh::getVertexStride() const
  142. {
  143. return vertexStride;
  144. }
  145. Buffer *Mesh::getVertexBuffer() const
  146. {
  147. return vertexBuffer;
  148. }
  149. const std::vector<Buffer::DataMember> &Mesh::getVertexFormat() const
  150. {
  151. return vertexFormat;
  152. }
  153. void Mesh::setAttributeEnabled(const std::string &name, bool enable)
  154. {
  155. int index = getAttachedAttributeIndex(name);
  156. if (index == -1)
  157. throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
  158. attachedAttributes[index].enabled = enable;
  159. }
  160. bool Mesh::isAttributeEnabled(const std::string &name) const
  161. {
  162. int index = getAttachedAttributeIndex(name);
  163. if (index == -1)
  164. throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
  165. return attachedAttributes[index].enabled;
  166. }
  167. void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, int startindex, AttributeStep step)
  168. {
  169. if ((buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
  170. throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
  171. auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  172. if (step == STEP_PER_INSTANCE && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
  173. throw love::Exception("Vertex attribute instancing is not supported on this system.");
  174. if (startindex < 0 || startindex >= (int) buffer->getArrayLength())
  175. throw love::Exception("Invalid start array index %d.", startindex + 1);
  176. BufferAttribute oldattrib = {};
  177. BufferAttribute newattrib = {};
  178. int oldindex = getAttachedAttributeIndex(name);
  179. if (oldindex != -1)
  180. oldattrib = attachedAttributes[oldindex];
  181. else if (attachedAttributes.size() + 1 > VertexAttributes::MAX)
  182. throw love::Exception("A maximum of %d attributes can be attached at once.", VertexAttributes::MAX);
  183. newattrib.name = name;
  184. newattrib.buffer = buffer;
  185. newattrib.mesh = mesh;
  186. newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true;
  187. newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname);
  188. newattrib.startArrayIndex = startindex;
  189. newattrib.step = step;
  190. if (newattrib.indexInBuffer < 0)
  191. throw love::Exception("The specified vertex buffer does not have a vertex attribute named '%s'", attachname.c_str());
  192. if (oldindex != -1)
  193. attachedAttributes[oldindex] = newattrib;
  194. else
  195. attachedAttributes.push_back(newattrib);
  196. }
  197. bool Mesh::detachAttribute(const std::string &name)
  198. {
  199. int index = getAttachedAttributeIndex(name);
  200. if (index == -1)
  201. return false;
  202. attachedAttributes.erase(attachedAttributes.begin() + index);
  203. if (vertexBuffer.get() && vertexBuffer->getDataMemberIndex(name) != -1)
  204. attachAttribute(name, vertexBuffer, nullptr, name);
  205. return true;
  206. }
  207. const std::vector<Mesh::BufferAttribute> &Mesh::getAttachedAttributes() const
  208. {
  209. return attachedAttributes;
  210. }
  211. void *Mesh::getVertexData() const
  212. {
  213. return vertexData;
  214. }
  215. void Mesh::setVertexDataModified(size_t offset, size_t size)
  216. {
  217. if (vertexData != nullptr)
  218. modifiedVertexData.encapsulate(offset, size);
  219. }
  220. void Mesh::flush()
  221. {
  222. if (vertexBuffer.get() && vertexData != nullptr && modifiedVertexData.isValid())
  223. {
  224. if (vertexBuffer->getDataUsage() == BUFFERDATAUSAGE_STREAM)
  225. {
  226. vertexBuffer->fill(0, vertexBuffer->getSize(), vertexData);
  227. }
  228. else
  229. {
  230. size_t offset = modifiedVertexData.getOffset();
  231. size_t size = modifiedVertexData.getSize();
  232. vertexBuffer->fill(offset, size, vertexData + offset);
  233. }
  234. modifiedVertexData.invalidate();
  235. }
  236. if (indexDataModified && indexData != nullptr && indexBuffer != nullptr)
  237. {
  238. indexBuffer->fill(0, indexBuffer->getSize(), indexData);
  239. indexDataModified = false;
  240. }
  241. }
  242. /**
  243. * Copies index data from a vector to a mapped index buffer.
  244. **/
  245. template <typename T>
  246. static void copyToIndexBuffer(const std::vector<uint32> &indices, void *data, size_t maxval)
  247. {
  248. T *elems = (T *) data;
  249. for (size_t i = 0; i < indices.size(); i++)
  250. {
  251. if (indices[i] >= maxval)
  252. throw love::Exception("Invalid vertex map value: %d", indices[i] + 1);
  253. elems[i] = (T) indices[i];
  254. }
  255. }
  256. void Mesh::setVertexMap(const std::vector<uint32> &map)
  257. {
  258. size_t maxval = getVertexCount();
  259. IndexDataType datatype = getIndexDataTypeFromMax(maxval);
  260. DataFormat dataformat = getIndexDataFormat(datatype);
  261. // Calculate the size in bytes of the index buffer data.
  262. size_t size = map.size() * getIndexDataSize(datatype);
  263. bool recreate = indexData == nullptr || indexBuffer.get() == nullptr
  264. || size > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat;
  265. if (recreate)
  266. {
  267. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  268. auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
  269. Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
  270. auto buffer = StrongRef<Buffer>(gfx->newBuffer(settings, dataformat, nullptr, size, 0), Acquire::NORETAIN);
  271. auto data = (uint8 *) realloc(indexData, size);
  272. if (data == nullptr)
  273. throw love::Exception("Out of memory.");
  274. indexData = data;
  275. indexBuffer = buffer;
  276. }
  277. indexCount = map.size();
  278. useIndexBuffer = true;
  279. indexDataType = datatype;
  280. if (indexCount == 0)
  281. return;
  282. // Fill the buffer with the index values from the vector.
  283. switch (datatype)
  284. {
  285. case INDEX_UINT16:
  286. copyToIndexBuffer<uint16>(map, indexData, maxval);
  287. break;
  288. case INDEX_UINT32:
  289. default:
  290. copyToIndexBuffer<uint32>(map, indexData, maxval);
  291. break;
  292. }
  293. indexDataModified = true;
  294. }
  295. void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize)
  296. {
  297. DataFormat dataformat = getIndexDataFormat(datatype);
  298. bool recreate = indexData == nullptr || indexBuffer.get() == nullptr
  299. || datasize > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat;
  300. if (recreate)
  301. {
  302. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  303. auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
  304. Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
  305. auto buffer = StrongRef<Buffer>(gfx->newBuffer(settings, dataformat, nullptr, datasize, 0), Acquire::NORETAIN);
  306. auto data = (uint8 *) realloc(indexData, datasize);
  307. if (data == nullptr)
  308. throw love::Exception("Out of memory.");
  309. indexData = data;
  310. indexBuffer = buffer;
  311. }
  312. indexCount = datasize / getIndexDataSize(datatype);
  313. useIndexBuffer = true;
  314. indexDataType = datatype;
  315. if (indexCount == 0)
  316. return;
  317. memcpy(indexData, data, datasize);
  318. indexDataModified = true;
  319. }
  320. void Mesh::setVertexMap()
  321. {
  322. useIndexBuffer = false;
  323. }
  324. /**
  325. * Copies index data from a mapped buffer to a vector.
  326. **/
  327. template <typename T>
  328. static void copyFromIndexBuffer(const void *buffer, size_t count, std::vector<uint32> &indices)
  329. {
  330. const T *elems = (const T *) buffer;
  331. for (size_t i = 0; i < count; i++)
  332. indices.push_back((uint32) elems[i]);
  333. }
  334. bool Mesh::getVertexMap(std::vector<uint32> &map) const
  335. {
  336. if (!useIndexBuffer)
  337. return false;
  338. map.clear();
  339. if (indexData == nullptr || indexCount == 0)
  340. return true;
  341. map.reserve(indexCount);
  342. // Fill the vector from the buffer.
  343. switch (indexDataType)
  344. {
  345. case INDEX_UINT16:
  346. copyFromIndexBuffer<uint16>(indexData, indexCount, map);
  347. break;
  348. case INDEX_UINT32:
  349. default:
  350. copyFromIndexBuffer<uint32>(indexData, indexCount, map);
  351. break;
  352. }
  353. return true;
  354. }
  355. void Mesh::setIndexBuffer(Buffer *buffer)
  356. {
  357. // Buffer constructor does the rest of the validation for index buffers
  358. // (data member formats, etc.)
  359. if (buffer != nullptr && (buffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX) == 0)
  360. throw love::Exception("setIndexBuffer requires a Buffer created as an index buffer.");
  361. indexBuffer.set(buffer);
  362. useIndexBuffer = buffer != nullptr;
  363. indexCount = buffer != nullptr ? buffer->getArrayLength() : 0;
  364. if (buffer != nullptr)
  365. indexDataType = getIndexDataType(buffer->getDataMember(0).decl.format);
  366. if (indexData != nullptr)
  367. {
  368. free(indexData);
  369. indexData = nullptr;
  370. }
  371. }
  372. Buffer *Mesh::getIndexBuffer() const
  373. {
  374. return indexBuffer;
  375. }
  376. size_t Mesh::getIndexCount() const
  377. {
  378. return indexCount;
  379. }
  380. void Mesh::setTexture(Texture *tex)
  381. {
  382. texture.set(tex);
  383. }
  384. void Mesh::setTexture()
  385. {
  386. texture.set(nullptr);
  387. }
  388. Texture *Mesh::getTexture() const
  389. {
  390. return texture.get();
  391. }
  392. void Mesh::setDrawMode(PrimitiveType mode)
  393. {
  394. primitiveType = mode;
  395. }
  396. PrimitiveType Mesh::getDrawMode() const
  397. {
  398. return primitiveType;
  399. }
  400. void Mesh::setDrawRange(int start, int count)
  401. {
  402. if (start < 0 || count <= 0)
  403. throw love::Exception("Invalid draw range.");
  404. drawRange = Range(start, count);
  405. }
  406. void Mesh::setDrawRange()
  407. {
  408. drawRange.invalidate();
  409. }
  410. bool Mesh::getDrawRange(int &start, int &count) const
  411. {
  412. if (!drawRange.isValid())
  413. return false;
  414. start = (int) drawRange.getOffset();
  415. count = (int) drawRange.getSize();
  416. return true;
  417. }
  418. void Mesh::draw(Graphics *gfx, const love::Matrix4 &m)
  419. {
  420. drawInternal(gfx, m, 1, nullptr, 0);
  421. }
  422. void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
  423. {
  424. drawInternal(gfx, m, instancecount, nullptr, 0);
  425. }
  426. void Mesh::drawIndirect(Graphics *gfx, const Matrix4 &m, Buffer *indirectargs, int argsindex)
  427. {
  428. drawInternal(gfx, m, 0, indirectargs, argsindex);
  429. }
  430. void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buffer *indirectargs, int argsindex)
  431. {
  432. if (vertexCount <= 0 || (instancecount <= 0 && indirectargs == nullptr))
  433. return;
  434. if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
  435. throw love::Exception("Instancing is not supported on this system.");
  436. if (indirectargs != nullptr)
  437. {
  438. if (primitiveType == PRIMITIVE_TRIANGLE_FAN)
  439. throw love::Exception("The fan draw mode is not supported in indirect draws.");
  440. if (useIndexBuffer && indexBuffer != nullptr)
  441. gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_INDICES, indirectargs, argsindex);
  442. else
  443. gfx->validateIndirectArgsBuffer(Graphics::INDIRECT_ARGS_DRAW_VERTICES, indirectargs, argsindex);
  444. }
  445. // Some graphics backends don't natively support triangle fans. So we'd
  446. // have to emulate them with triangles plus an index buffer... which doesn't
  447. // work so well when there's already a custom index buffer.
  448. if (primitiveType == PRIMITIVE_TRIANGLE_FAN && useIndexBuffer && indexBuffer != nullptr)
  449. throw love::Exception("The 'fan' Mesh draw mode cannot be used with an index buffer / vertex map.");
  450. gfx->flushBatchedDraws();
  451. flush();
  452. if (Shader::isDefaultActive())
  453. Shader::attachDefault(Shader::STANDARD_DEFAULT);
  454. if (Shader::current)
  455. Shader::current->validateDrawState(primitiveType, texture);
  456. VertexAttributes attributes;
  457. BufferBindings buffers;
  458. int activebuffers = 0;
  459. for (const auto &attrib : attachedAttributes)
  460. {
  461. if (!attrib.enabled)
  462. continue;
  463. Buffer *buffer = attrib.buffer.get();
  464. int attributeindex = -1;
  465. // If the attribute is one of the LOVE-defined ones, use the constant
  466. // attribute index for it, otherwise query the index from the shader.
  467. BuiltinVertexAttribute builtinattrib;
  468. if (getConstant(attrib.name.c_str(), builtinattrib))
  469. attributeindex = (int) builtinattrib;
  470. else if (Shader::current)
  471. attributeindex = Shader::current->getVertexAttributeIndex(attrib.name);
  472. if (attributeindex >= 0)
  473. {
  474. if (attrib.mesh.get())
  475. attrib.mesh->flush();
  476. const auto &member = buffer->getDataMember(attrib.indexInBuffer);
  477. uint16 offset = (uint16) member.offset;
  478. uint16 stride = (uint16) buffer->getArrayStride();
  479. size_t bufferoffset = (size_t) stride * attrib.startArrayIndex;
  480. attributes.set(attributeindex, member.decl.format, offset, activebuffers);
  481. attributes.setBufferLayout(activebuffers, stride, attrib.step);
  482. // TODO: Ideally we want to reuse buffers with the same stride+step.
  483. buffers.set(activebuffers, buffer, bufferoffset);
  484. activebuffers++;
  485. }
  486. }
  487. // Not supported on all platforms or GL versions, I believe.
  488. if (!attributes.isEnabled(ATTRIB_POS))
  489. throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
  490. Graphics::TempTransform transform(gfx, m);
  491. Buffer *indexbuffer = useIndexBuffer ? indexBuffer : nullptr;
  492. int indexcount = (int) indexCount;
  493. Range range = drawRange;
  494. // Emulated triangle fan via an index buffer.
  495. if (primitiveType == PRIMITIVE_TRIANGLE_FAN && indexbuffer == nullptr && gfx->getFanIndexBuffer())
  496. {
  497. indexbuffer = gfx->getFanIndexBuffer();
  498. indexcount = graphics::getIndexCount(TRIANGLEINDEX_FAN, vertexCount);
  499. if (range.isValid())
  500. {
  501. int start = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getOffset());
  502. int count = graphics::getIndexCount(TRIANGLEINDEX_FAN, (int) range.getSize());
  503. range = Range(start, count);
  504. }
  505. }
  506. if (indexbuffer != nullptr && (indexcount > 0 || indirectargs != nullptr))
  507. {
  508. Range r(0, indexcount);
  509. if (range.isValid())
  510. r.intersect(range);
  511. Graphics::DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
  512. cmd.primitiveType = primitiveType;
  513. cmd.indexType = indexDataType;
  514. cmd.instanceCount = instancecount;
  515. cmd.texture = texture;
  516. cmd.cullMode = gfx->getMeshCullMode();
  517. cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride();
  518. cmd.indexCount = (int) r.getSize();
  519. cmd.indirectBuffer = indirectargs;
  520. cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
  521. if (cmd.indexCount > 0)
  522. gfx->draw(cmd);
  523. }
  524. else if (vertexCount > 0 || indirectargs != nullptr)
  525. {
  526. Range r(0, vertexCount);
  527. if (range.isValid())
  528. r.intersect(range);
  529. Graphics::DrawCommand cmd(&attributes, &buffers);
  530. cmd.primitiveType = primitiveType;
  531. cmd.vertexStart = (int) r.getOffset();
  532. cmd.vertexCount = (int) r.getSize();
  533. cmd.instanceCount = instancecount;
  534. cmd.texture = texture;
  535. cmd.cullMode = gfx->getMeshCullMode();
  536. cmd.indirectBuffer = indirectargs;
  537. cmd.indirectBufferOffset = argsindex * (indirectargs != nullptr ? indirectargs->getArrayStride() : 0);
  538. if (cmd.vertexCount > 0)
  539. gfx->draw(cmd);
  540. }
  541. }
  542. } // graphics
  543. } // love