SpriteBatch.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /**
  2. * Copyright (c) 2006-2013 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. #include "common/config.h"
  21. #include "SpriteBatch.h"
  22. // OpenGL
  23. #include "OpenGL.h"
  24. // LOVE
  25. #include "Image.h"
  26. #include "modules/graphics/Geometry.h"
  27. #include "VertexBuffer.h"
  28. // stdlib
  29. #include <algorithm>
  30. namespace love
  31. {
  32. namespace graphics
  33. {
  34. namespace opengl
  35. {
  36. SpriteBatch::SpriteBatch(Image *image, int size, int usage)
  37. : image(image)
  38. , size(size)
  39. , next(0)
  40. , color(0)
  41. , array_buf(0)
  42. , element_buf(0)
  43. {
  44. if (size <= 0)
  45. throw love::Exception("Invalid SpriteBatch size.");
  46. GLenum gl_usage;
  47. switch (usage)
  48. {
  49. default:
  50. case USAGE_DYNAMIC:
  51. gl_usage = GL_DYNAMIC_DRAW;
  52. break;
  53. case USAGE_STATIC:
  54. gl_usage = GL_STATIC_DRAW;
  55. break;
  56. case USAGE_STREAM:
  57. gl_usage = GL_STREAM_DRAW;
  58. break;
  59. }
  60. const size_t vertex_size = sizeof(vertex) * 4 * size;
  61. try
  62. {
  63. array_buf = VertexBuffer::Create(vertex_size, GL_ARRAY_BUFFER, gl_usage);
  64. element_buf = new VertexIndex(size);
  65. }
  66. catch (love::Exception &)
  67. {
  68. delete array_buf;
  69. delete element_buf;
  70. throw;
  71. }
  72. catch (std::bad_alloc &)
  73. {
  74. delete array_buf;
  75. delete element_buf;
  76. throw love::Exception("Out of memory.");
  77. }
  78. image->retain();
  79. }
  80. SpriteBatch::~SpriteBatch()
  81. {
  82. image->release();
  83. delete color;
  84. delete array_buf;
  85. delete element_buf;
  86. }
  87. int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
  88. {
  89. // Only do this if there's a free slot.
  90. if ((index == -1 && next >= size) || index < -1 || index >= size)
  91. return -1;
  92. // Needed for colors.
  93. memcpy(sprite, image->getVertices(), sizeof(vertex)*4);
  94. // Transform.
  95. static Matrix t;
  96. t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
  97. t.transform(sprite, sprite, 4);
  98. if (color)
  99. setColorv(sprite, *color);
  100. addv(sprite, (index == -1) ? next : index);
  101. // Increment counter.
  102. if (index == -1)
  103. return next++;
  104. return index;
  105. }
  106. int SpriteBatch::addg(Geometry *geom, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
  107. {
  108. // Only do this if there's a free slot.
  109. if ((index == -1 && next >= size) || index < -1 || index >= next)
  110. return -1;
  111. size_t vertexcount = geom->getVertexCount();
  112. if (vertexcount > 4)
  113. throw love::Exception("Cannot add Geometries with more than 4 vertices to SpriteBatch");
  114. // Which vertices to add to the SpriteBatch.
  115. size_t vertex_indices[4] = {0, 1, 2, 3};
  116. if (geom->getDrawMode() == Geometry::DRAW_MODE_STRIP)
  117. {
  118. // We have to do some vertex reordering shenanigans to get 4-vertex
  119. // triangle strip Geometries to render properly.
  120. std::swap(vertex_indices[0], vertex_indices[1]);
  121. }
  122. // If the Geometry has 3 vertices, then 2 triangles will be added to the
  123. // SpriteBatch: 0-1-2 and 0-2-0. 0-2-0 will get ignored during rasterization.
  124. for (size_t i = geom->getVertexCount(); i < 4; i++)
  125. vertex_indices[i] = vertex_indices[0];
  126. for (size_t i = 0; i < 4; i++)
  127. sprite[i] = geom->getVertex(vertex_indices[i]);
  128. static Matrix t;
  129. t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
  130. t.transform(sprite, sprite, 4);
  131. if (color && !geom->hasVertexColors())
  132. setColorv(sprite, *color);
  133. addv(sprite, (index == -1) ? next : index);
  134. // Make sure SpriteBatch colors are enabled if the Geometry has custom colors.
  135. if (!color && geom->hasVertexColors())
  136. setColor(Color(255, 255, 255, 255));
  137. // Increment counter.
  138. if (index == -1)
  139. return next++;
  140. return index;
  141. }
  142. void SpriteBatch::clear()
  143. {
  144. // Reset the position of the next index.
  145. next = 0;
  146. }
  147. void *SpriteBatch::lock()
  148. {
  149. VertexBuffer::Bind bind(*array_buf);
  150. return array_buf->map();
  151. }
  152. void SpriteBatch::unlock()
  153. {
  154. VertexBuffer::Bind bind(*array_buf);
  155. array_buf->unmap();
  156. }
  157. void SpriteBatch::setImage(Image *newimage)
  158. {
  159. Object::AutoRelease imagerelease(image);
  160. newimage->retain();
  161. image = newimage;
  162. }
  163. Image *SpriteBatch::getImage()
  164. {
  165. return image;
  166. }
  167. void SpriteBatch::setColor(const Color &color)
  168. {
  169. if (!this->color)
  170. this->color = new Color(color);
  171. else
  172. *(this->color) = color;
  173. }
  174. void SpriteBatch::setColor()
  175. {
  176. delete color;
  177. color = 0;
  178. }
  179. const Color *SpriteBatch::getColor() const
  180. {
  181. return color;
  182. }
  183. int SpriteBatch::getCount() const
  184. {
  185. return next;
  186. }
  187. void SpriteBatch::setBufferSize(int newsize)
  188. {
  189. if (newsize <= 0)
  190. throw love::Exception("Invalid SpriteBatch size.");
  191. if (newsize == size)
  192. return;
  193. // Map (lock) the old VertexBuffer to get a pointer to its data.
  194. void *old_data = lock();
  195. size_t vertex_size = sizeof(vertex) * 4 * newsize;
  196. VertexBuffer *new_array_buf = 0;
  197. VertexIndex *new_element_buf = 0;
  198. void *new_data = 0;
  199. try
  200. {
  201. new_array_buf = VertexBuffer::Create(vertex_size, array_buf->getTarget(), array_buf->getUsage());
  202. new_element_buf = new VertexIndex(newsize);
  203. // VBO::map can throw an exception. Also we want to scope the bind.
  204. VertexBuffer::Bind bind(*new_array_buf);
  205. new_data = new_array_buf->map();
  206. }
  207. catch (love::Exception &)
  208. {
  209. delete new_array_buf;
  210. delete new_element_buf;
  211. unlock();
  212. throw;
  213. }
  214. // Copy as much of the old data into the new VertexBuffer as can fit.
  215. memcpy(new_data, old_data, sizeof(vertex) * 4 * std::min(newsize, size));
  216. // We don't need to unmap the old VertexBuffer since we're deleting it.
  217. delete array_buf;
  218. delete element_buf;
  219. array_buf = new_array_buf;
  220. element_buf = new_element_buf;
  221. size = newsize;
  222. next = std::min(next, newsize);
  223. // But we should unmap (unlock) the new one!
  224. unlock();
  225. }
  226. int SpriteBatch::getBufferSize() const
  227. {
  228. return size;
  229. }
  230. void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
  231. {
  232. const int color_offset = 0;
  233. const int vertex_offset = sizeof(unsigned char) * 4;
  234. const int texel_offset = sizeof(unsigned char) * 4 + sizeof(float) * 2;
  235. if (next == 0)
  236. return;
  237. static Matrix t;
  238. glPushMatrix();
  239. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  240. glMultMatrixf((const GLfloat *)t.getElements());
  241. image->bind();
  242. VertexBuffer::Bind array_bind(*array_buf);
  243. VertexBuffer::Bind element_bind(*element_buf->getVertexBuffer());
  244. Color curcolor = gl.getColor();
  245. // Apply per-sprite color, if a color is set.
  246. if (color)
  247. {
  248. glEnableClientState(GL_COLOR_ARRAY);
  249. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), array_buf->getPointer(color_offset));
  250. }
  251. glEnableClientState(GL_VERTEX_ARRAY);
  252. glVertexPointer(2, GL_FLOAT, sizeof(vertex), array_buf->getPointer(vertex_offset));
  253. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  254. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), array_buf->getPointer(texel_offset));
  255. glDrawElements(GL_TRIANGLES, element_buf->getIndexCount(next), element_buf->getType(), element_buf->getPointer(0));
  256. glDisableClientState(GL_VERTEX_ARRAY);
  257. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  258. if (color)
  259. {
  260. glDisableClientState(GL_COLOR_ARRAY);
  261. gl.setColor(curcolor);
  262. }
  263. glPopMatrix();
  264. }
  265. void SpriteBatch::addv(const vertex *v, int index)
  266. {
  267. static const int sprite_size = 4 * sizeof(vertex); // bytecount
  268. VertexBuffer::Bind bind(*array_buf);
  269. array_buf->fill(index * sprite_size, sprite_size, v);
  270. }
  271. void SpriteBatch::setColorv(vertex *v, const Color &color)
  272. {
  273. for (size_t i = 0; i < 4; ++i)
  274. {
  275. v[i].r = color.r;
  276. v[i].g = color.g;
  277. v[i].b = color.b;
  278. v[i].a = color.a;
  279. }
  280. }
  281. bool SpriteBatch::getConstant(const char *in, UsageHint &out)
  282. {
  283. return usageHints.find(in, out);
  284. }
  285. bool SpriteBatch::getConstant(UsageHint in, const char *&out)
  286. {
  287. return usageHints.find(in, out);
  288. }
  289. StringMap<SpriteBatch::UsageHint, SpriteBatch::USAGE_MAX_ENUM>::Entry SpriteBatch::usageHintEntries[] =
  290. {
  291. {"dynamic", SpriteBatch::USAGE_DYNAMIC},
  292. {"static", SpriteBatch::USAGE_STATIC},
  293. {"stream", SpriteBatch::USAGE_STREAM},
  294. };
  295. StringMap<SpriteBatch::UsageHint, SpriteBatch::USAGE_MAX_ENUM> SpriteBatch::usageHints(usageHintEntries, sizeof(usageHintEntries));
  296. } // opengl
  297. } // graphics
  298. } // love