SpriteBatch.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /**
  2. * Copyright (c) 2006-2011 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 "SpriteBatch.h"
  21. // STD
  22. #include <iostream>
  23. // LOVE
  24. #include "Image.h"
  25. #include "Quad.h"
  26. namespace love
  27. {
  28. namespace graphics
  29. {
  30. namespace opengl
  31. {
  32. SpriteBatch::SpriteBatch(Image * image, int size, int usage)
  33. : image(image), size(size), next(0), usage(usage), lockp(0)
  34. {
  35. if (!(GLEE_ARB_vertex_buffer_object || GLEE_VERSION_1_5))
  36. throw love::Exception("Your OpenGL version does not support SpriteBatches. Go upgrade!");
  37. image->retain();
  38. vertices = new vertex[size*4];
  39. indices = new GLushort[size*6];
  40. for(int i = 0; i<size; i++)
  41. {
  42. indices[i*6+0] = 0+(i*4);
  43. indices[i*6+1] = 1+(i*4);
  44. indices[i*6+2] = 2+(i*4);
  45. indices[i*6+3] = 0+(i*4);
  46. indices[i*6+4] = 2+(i*4);
  47. indices[i*6+5] = 3+(i*4);
  48. }
  49. loadVolatile();
  50. }
  51. SpriteBatch::~SpriteBatch()
  52. {
  53. image->release();
  54. if(vbo[0] != 0 && vbo[1] != 0)
  55. glDeleteBuffers(2, vbo);
  56. delete [] vertices;
  57. delete [] indices;
  58. }
  59. bool SpriteBatch::loadVolatile()
  60. {
  61. // Find out which OpenGL VBO usage hint to use.
  62. gl_usage = GL_STREAM_DRAW_ARB;
  63. gl_usage = (usage == USAGE_DYNAMIC) ? GL_DYNAMIC_DRAW_ARB : gl_usage;
  64. gl_usage = (usage == USAGE_STATIC) ? GL_STATIC_DRAW_ARB : gl_usage;
  65. gl_usage = (usage == USAGE_STREAM) ? GL_STREAM_DRAW_ARB : gl_usage;
  66. glGenBuffersARB(2, vbo);
  67. glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo[0]);
  68. glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertex)*size*4, vertices, gl_usage);
  69. glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  70. glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vbo[1]);
  71. glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(GLushort)*size*6, indices, GL_STATIC_DRAW_ARB);
  72. glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
  73. return true;
  74. }
  75. void SpriteBatch::unloadVolatile()
  76. {
  77. vertex * v = (vertex *)lock();
  78. // Copy to system memory.
  79. memcpy(vertices, v, sizeof(vertex)*size*4);
  80. unlock();
  81. // Delete the buffers.
  82. if(vbo[0] != 0 && vbo[1] != 0)
  83. glDeleteBuffersARB(2, vbo);
  84. }
  85. void SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
  86. {
  87. // Only do this if there's a free slot.
  88. if(next < size)
  89. {
  90. // Get a pointer to the correct insertion position.
  91. vertex * v = vertices + next*4;
  92. // Needed for texture coordinates.
  93. memcpy(v, image->getVertices(), sizeof(vertex)*4);
  94. // Transform.
  95. Matrix t;
  96. t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
  97. t.transform(v, v, 4);
  98. addv(v);
  99. // Increment counter.
  100. next++;
  101. }
  102. }
  103. void SpriteBatch::addq(Quad * quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky)
  104. {
  105. // Only do this if there's a free slot.
  106. if(next < size)
  107. {
  108. // Get a pointer to the correct insertion position.
  109. vertex * v = vertices + next*4;
  110. // Needed for colors.
  111. memcpy(v, quad->getVertices(), sizeof(vertex)*4);
  112. // Transform.
  113. Matrix t;
  114. t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
  115. t.transform(v, v, 4);
  116. addv(v);
  117. // Increment counter.
  118. next++;
  119. }
  120. }
  121. void SpriteBatch::clear()
  122. {
  123. // Reset the position of the next index.
  124. next = 0;
  125. }
  126. void * SpriteBatch::lock()
  127. {
  128. // If already locked, prevent from locking again.
  129. if(lockp != 0)
  130. return lockp;
  131. glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo[0]);
  132. lockp = (vertex *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB);
  133. glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  134. return lockp;
  135. }
  136. void SpriteBatch::unlock()
  137. {
  138. glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo[0]);
  139. glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
  140. lockp = 0;
  141. glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  142. }
  143. void SpriteBatch::setImage(Image * newimage)
  144. {
  145. image->release();
  146. image = newimage;
  147. image->retain();
  148. }
  149. void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
  150. {
  151. static Matrix t;
  152. glPushMatrix();
  153. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  154. glMultMatrixf((const GLfloat*)t.getElements());
  155. image->bind();
  156. // Enable vertex arrays.
  157. glEnableClientState(GL_VERTEX_ARRAY);
  158. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  159. // Bind the VBO buffer.
  160. glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo[0]);
  161. glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vbo[1]);
  162. glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)(sizeof(unsigned char)*4));
  163. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)(sizeof(unsigned char)*4+sizeof(float)*2));
  164. glDrawElements(GL_TRIANGLES, next*6, GL_UNSIGNED_SHORT, 0);
  165. // Disable vertex arrays.
  166. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  167. glDisableClientState(GL_VERTEX_ARRAY);
  168. glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  169. glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
  170. glPopMatrix();
  171. }
  172. void SpriteBatch::addv(const vertex * v)
  173. {
  174. if(lockp != 0)
  175. {
  176. // Copy into mapped memory if buffer is locked.
  177. memcpy(lockp + (next*4), v, sizeof(vertex)*4);
  178. }
  179. else
  180. {
  181. // ... use glBufferSubData otherwise.
  182. glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo[0]);
  183. glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, (next*4)*sizeof(vertex), sizeof(vertex)*4, v);
  184. glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  185. }
  186. }
  187. } // opengl
  188. } // graphics
  189. } // love