Mesh.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /**
  2. * Copyright (c) 2006-2014 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. // C++
  25. #include <algorithm>
  26. namespace love
  27. {
  28. namespace graphics
  29. {
  30. namespace opengl
  31. {
  32. Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
  33. : vbo(nullptr)
  34. , vertex_count(0)
  35. , ibo(nullptr)
  36. , element_count(0)
  37. , element_data_type(getGLDataTypeFromMax(verts.size()))
  38. , instance_count(1)
  39. , draw_mode(mode)
  40. , range_min(-1)
  41. , range_max(-1)
  42. , texture(nullptr)
  43. , colors_enabled(false)
  44. {
  45. setVertices(verts);
  46. }
  47. Mesh::Mesh(int vertexcount, Mesh::DrawMode mode)
  48. : vbo(nullptr)
  49. , vertex_count(0)
  50. , ibo(nullptr)
  51. , element_count(0)
  52. , element_data_type(getGLDataTypeFromMax(vertexcount))
  53. , draw_mode(mode)
  54. , range_min(-1)
  55. , range_max(-1)
  56. , texture(nullptr)
  57. , colors_enabled(false)
  58. {
  59. if (vertexcount < 1)
  60. throw love::Exception("Invalid number of vertices.");
  61. std::vector<Vertex> verts(vertexcount);
  62. // Default-initialized vertices should have a white opaque color.
  63. for (size_t i = 0; i < verts.size(); i++)
  64. {
  65. verts[i].r = 255;
  66. verts[i].g = 255;
  67. verts[i].b = 255;
  68. verts[i].a = 255;
  69. }
  70. setVertices(verts);
  71. }
  72. Mesh::~Mesh()
  73. {
  74. delete vbo;
  75. delete ibo;
  76. }
  77. void Mesh::setVertices(const std::vector<Vertex> &verts)
  78. {
  79. if (verts.size() == 0)
  80. throw love::Exception("At least one vertex is required.");
  81. size_t size = sizeof(Vertex) * verts.size();
  82. if (vbo && size > vbo->getSize())
  83. {
  84. delete vbo;
  85. vbo = nullptr;
  86. }
  87. if (!vbo)
  88. {
  89. // Full memory backing because we might access the data at any time.
  90. vbo = VertexBuffer::Create(size, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
  91. }
  92. vertex_count = verts.size();
  93. VertexBuffer::Bind vbo_bind(*vbo);
  94. VertexBuffer::Mapper vbo_mapper(*vbo);
  95. // Fill the buffer with the vertices.
  96. memcpy(vbo_mapper.get(), &verts[0], size);
  97. }
  98. const Vertex *Mesh::getVertices() const
  99. {
  100. if (vbo)
  101. {
  102. VertexBuffer::Bind vbo_bind(*vbo);
  103. return (Vertex *) vbo->map();
  104. }
  105. return nullptr;
  106. }
  107. void Mesh::setVertex(size_t index, const Vertex &v)
  108. {
  109. if (index >= vertex_count)
  110. throw love::Exception("Invalid vertex index: %ld", index + 1);
  111. VertexBuffer::Bind vbo_bind(*vbo);
  112. // We unmap the vertex buffer in Mesh::draw. This lets us coalesce the
  113. // buffer transfer calls into just one.
  114. Vertex *vertices = (Vertex *) vbo->map();
  115. vertices[index] = v;
  116. }
  117. Vertex Mesh::getVertex(size_t index) const
  118. {
  119. if (index >= vertex_count)
  120. throw love::Exception("Invalid vertex index: %ld", index + 1);
  121. VertexBuffer::Bind vbo_bind(*vbo);
  122. // We unmap the vertex buffer in Mesh::draw.
  123. Vertex *vertices = (Vertex *) vbo->map();
  124. return vertices[index];
  125. }
  126. size_t Mesh::getVertexCount() const
  127. {
  128. return vertex_count;
  129. }
  130. /**
  131. * Copies index data from a vector to a mapped index buffer.
  132. **/
  133. template <typename T>
  134. static void copyToIndexBuffer(const std::vector<uint32> &indices, VertexBuffer::Mapper &buffermap, size_t maxval)
  135. {
  136. T *elems = (T *) buffermap.get();
  137. for (size_t i = 0; i < indices.size(); i++)
  138. {
  139. if (indices[i] >= maxval)
  140. throw love::Exception("Invalid vertex map value: %d", indices[i] + 1);
  141. elems[i] = (T) indices[i];
  142. }
  143. }
  144. void Mesh::setVertexMap(const std::vector<uint32> &map)
  145. {
  146. GLenum datatype = getGLDataTypeFromMax(vertex_count);
  147. // Calculate the size in bytes of the index buffer data.
  148. size_t size = map.size();
  149. switch (datatype)
  150. {
  151. case GL_UNSIGNED_BYTE:
  152. size *= sizeof(uint8);
  153. break;
  154. case GL_UNSIGNED_SHORT:
  155. size *= sizeof(uint16);
  156. break;
  157. case GL_UNSIGNED_INT:
  158. default:
  159. size *= sizeof(uint32);
  160. break;
  161. }
  162. if (ibo && size > ibo->getSize())
  163. {
  164. delete ibo;
  165. ibo = nullptr;
  166. }
  167. if (!ibo && size > 0)
  168. {
  169. // Full memory backing because we might access the data at any time.
  170. ibo = VertexBuffer::Create(size, GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
  171. }
  172. element_count = map.size();
  173. if (!ibo || element_count == 0)
  174. return;
  175. VertexBuffer::Bind ibo_bind(*ibo);
  176. VertexBuffer::Mapper ibo_map(*ibo);
  177. // Fill the buffer with the index values from the vector.
  178. switch (datatype)
  179. {
  180. case GL_UNSIGNED_BYTE:
  181. copyToIndexBuffer<uint8>(map, ibo_map, vertex_count);
  182. break;
  183. case GL_UNSIGNED_SHORT:
  184. copyToIndexBuffer<uint16>(map, ibo_map, vertex_count);
  185. break;
  186. case GL_UNSIGNED_INT:
  187. default:
  188. copyToIndexBuffer<uint32>(map, ibo_map, vertex_count);
  189. break;
  190. }
  191. element_data_type = datatype;
  192. }
  193. /**
  194. * Copies index data from a mapped buffer to a vector.
  195. **/
  196. template <typename T>
  197. static void copyFromIndexBuffer(void *buffer, std::vector<uint32> &indices, size_t maxval)
  198. {
  199. T *elems = (T *) buffer;
  200. for (size_t i = 0; i < maxval; i++)
  201. indices.push_back((uint32) elems[i]);
  202. }
  203. void Mesh::getVertexMap(std::vector<uint32> &map) const
  204. {
  205. if (!ibo || element_count == 0)
  206. return;
  207. map.clear();
  208. map.reserve(element_count);
  209. VertexBuffer::Bind ibo_bind(*ibo);
  210. // We unmap the buffer in Mesh::draw and Mesh::setVertexMap.
  211. void *buffer = ibo->map();
  212. // Fill the vector from the buffer.
  213. switch (element_data_type)
  214. {
  215. case GL_UNSIGNED_BYTE:
  216. copyFromIndexBuffer<uint8>(buffer, map, vertex_count);
  217. break;
  218. case GL_UNSIGNED_SHORT:
  219. copyFromIndexBuffer<uint16>(buffer, map, vertex_count);
  220. break;
  221. case GL_UNSIGNED_INT:
  222. default:
  223. copyFromIndexBuffer<uint32>(buffer, map, vertex_count);
  224. break;
  225. }
  226. }
  227. size_t Mesh::getVertexMapCount() const
  228. {
  229. return element_count;
  230. }
  231. void Mesh::setInstanceCount(int count)
  232. {
  233. instance_count = std::max(count, 1);
  234. }
  235. int Mesh::getInstanceCount() const
  236. {
  237. return instance_count;
  238. }
  239. void Mesh::setTexture(Texture *tex)
  240. {
  241. tex->retain();
  242. if (texture)
  243. texture->release();
  244. texture = tex;
  245. }
  246. void Mesh::setTexture()
  247. {
  248. if (texture)
  249. texture->release();
  250. texture = nullptr;
  251. }
  252. Texture *Mesh::getTexture() const
  253. {
  254. return texture;
  255. }
  256. void Mesh::setDrawMode(Mesh::DrawMode mode)
  257. {
  258. draw_mode = mode;
  259. }
  260. Mesh::DrawMode Mesh::getDrawMode() const
  261. {
  262. return draw_mode;
  263. }
  264. void Mesh::setDrawRange(int min, int max)
  265. {
  266. if (min < 0 || max < 0 || min > max)
  267. throw love::Exception("Invalid draw range.");
  268. range_min = min;
  269. range_max = max;
  270. }
  271. void Mesh::setDrawRange()
  272. {
  273. range_min = range_max = -1;
  274. }
  275. void Mesh::getDrawRange(int &min, int &max) const
  276. {
  277. min = range_min;
  278. max = range_max;
  279. }
  280. void Mesh::setVertexColors(bool enable)
  281. {
  282. colors_enabled = enable;
  283. }
  284. bool Mesh::hasVertexColors() const
  285. {
  286. return colors_enabled;
  287. }
  288. void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  289. {
  290. const size_t pos_offset = offsetof(Vertex, x);
  291. const size_t tex_offset = offsetof(Vertex, s);
  292. const size_t color_offset = offsetof(Vertex, r);
  293. if (vertex_count == 0)
  294. return;
  295. if (texture)
  296. texture->predraw();
  297. else
  298. gl.bindTexture(gl.getDefaultTexture());
  299. Matrix m;
  300. m.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  301. gl.matrices.transform.push(gl.matrices.transform.top());
  302. gl.matrices.transform.top() *= m;
  303. VertexBuffer::Bind vbo_bind(*vbo);
  304. // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.)
  305. vbo->unmap();
  306. gl.enableVertexAttribArray(OpenGL::ATTRIB_POS);
  307. gl.enableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
  308. gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(pos_offset));
  309. gl.setVertexAttribArray(OpenGL::ATTRIB_TEXCOORD, 2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(tex_offset));
  310. if (hasVertexColors())
  311. {
  312. // Per-vertex colors.
  313. gl.enableVertexAttribArray(OpenGL::ATTRIB_COLOR);
  314. gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset));
  315. }
  316. GLenum mode = getGLDrawMode(draw_mode);
  317. gl.prepareDraw();
  318. if (ibo && element_count > 0)
  319. {
  320. // Use the custom vertex map (index buffer) to draw the vertices.
  321. VertexBuffer::Bind ibo_bind(*ibo);
  322. // Make sure the index buffer isn't mapped (sends data to GPU if needed.)
  323. ibo->unmap();
  324. int max = element_count - 1;
  325. if (range_max >= 0)
  326. max = std::min(std::max(range_max, 0), (int) element_count - 1);
  327. int min = 0;
  328. if (range_min >= 0)
  329. min = std::min(std::max(range_min, 0), max);
  330. const void *indices = ibo->getPointer(min * sizeof(uint32));
  331. GLenum type = element_data_type;
  332. if (instance_count > 1)
  333. gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count);
  334. else
  335. glDrawElements(mode, max - min + 1, type, indices);
  336. }
  337. else
  338. {
  339. int max = vertex_count - 1;
  340. if (range_max >= 0)
  341. max = std::min(std::max(range_max, 0), (int) vertex_count - 1);
  342. int min = 0;
  343. if (range_min >= 0)
  344. min = std::min(std::max(range_min, 0), max);
  345. // Normal non-indexed drawing (no custom vertex map.)
  346. if (instance_count > 1)
  347. gl.drawArraysInstanced(mode, min, max - min + 1, instance_count);
  348. else
  349. glDrawArrays(mode, min, max - min + 1);
  350. }
  351. gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
  352. gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
  353. if (hasVertexColors())
  354. {
  355. gl.disableVertexAttribArray(OpenGL::ATTRIB_COLOR);
  356. // Using the color array leaves the GL constant color undefined.
  357. gl.setColor(gl.getColor());
  358. }
  359. gl.matrices.transform.pop();
  360. if (texture)
  361. texture->postdraw();
  362. }
  363. GLenum Mesh::getGLDrawMode(DrawMode mode) const
  364. {
  365. switch (mode)
  366. {
  367. case DRAW_MODE_FAN:
  368. return GL_TRIANGLE_FAN;
  369. case DRAW_MODE_STRIP:
  370. return GL_TRIANGLE_STRIP;
  371. case DRAW_MODE_TRIANGLES:
  372. return GL_TRIANGLES;
  373. case DRAW_MODE_POINTS:
  374. return GL_POINTS;
  375. default:
  376. break;
  377. }
  378. return GL_TRIANGLES;
  379. }
  380. GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) const
  381. {
  382. if (maxvalue > LOVE_UINT16_MAX)
  383. return GL_UNSIGNED_INT;
  384. else if (maxvalue > LOVE_UINT8_MAX)
  385. return GL_UNSIGNED_SHORT;
  386. else
  387. return GL_UNSIGNED_BYTE;
  388. }
  389. bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
  390. {
  391. return drawModes.find(in, out);
  392. }
  393. bool Mesh::getConstant(Mesh::DrawMode in, const char *&out)
  394. {
  395. return drawModes.find(in, out);
  396. }
  397. StringMap<Mesh::DrawMode, Mesh::DRAW_MODE_MAX_ENUM>::Entry Mesh::drawModeEntries[] =
  398. {
  399. {"fan", Mesh::DRAW_MODE_FAN},
  400. {"strip", Mesh::DRAW_MODE_STRIP},
  401. {"triangles", Mesh::DRAW_MODE_TRIANGLES},
  402. {"points", Mesh::DRAW_MODE_POINTS},
  403. };
  404. StringMap<Mesh::DrawMode, Mesh::DRAW_MODE_MAX_ENUM> Mesh::drawModes(Mesh::drawModeEntries, sizeof(Mesh::drawModeEntries));
  405. } // opengl
  406. } // graphics
  407. } // love