Mesh.cpp 10 KB

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