SpriteBatch.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. * SpriteBatch.cpp
  3. */
  4. #include "Base.h"
  5. #include "SpriteBatch.h"
  6. #include "Game.h"
  7. // Default size of a newly created sprite batch
  8. #define SPRITE_BATCH_DEFAULT_SIZE 128
  9. // Factor to grow a sprite batch by when its size is exceeded
  10. #define SPRITE_BATCH_GROW_FACTOR 2.0f
  11. // Macro to add a sprite vertex
  12. #define ADD_SPRITE_VERTEX(ptr, x, y, z, u, v, r, g, b, a) \
  13. ptr[0] = x; ptr[1] = y; ptr[2] = z; ptr[3] = u; ptr[4] = v; \
  14. ptr[5] = r; ptr[6] = g; ptr[7] = b; ptr[8] = a
  15. // Default sprite vertex shader
  16. #define SPRITE_VSH \
  17. "uniform mat4 u_projectionMatrix;\n" \
  18. "attribute vec3 a_position;\n" \
  19. "attribute vec2 a_texcoord;\n" \
  20. "attribute vec4 a_color;\n" \
  21. "varying vec2 v_texcoord;\n" \
  22. "varying vec4 v_color;\n" \
  23. "void main()\n" \
  24. "{\n" \
  25. "gl_Position = u_projectionMatrix * vec4(a_position, 1);\n" \
  26. "v_texcoord = a_texcoord;\n" \
  27. "v_color = a_color;\n" \
  28. "}\n"
  29. // Default sprite fragment shader
  30. #define SPRITE_FSH \
  31. "#ifdef OPENGL_ES\n" \
  32. "precision highp float;\n" \
  33. "#endif\n" \
  34. "varying vec2 v_texcoord;\n" \
  35. "varying vec4 v_color;\n" \
  36. "uniform sampler2D u_texture;\n" \
  37. "void main()\n" \
  38. "{\n" \
  39. "gl_FragColor = v_color * texture2D(u_texture, v_texcoord);\n" \
  40. "}\n"
  41. namespace gameplay
  42. {
  43. // Shared sprite effects
  44. static Effect* __spriteEffect = NULL;
  45. SpriteBatch::SpriteBatch() :
  46. _effect(NULL), _stateBlock(NULL), _sampler(NULL), _samplerUniform(NULL), _projectionUniform(NULL), _vaPosition(-1), _vaTexCoord(-1), _vaColor(-1),
  47. _textureWidthRatio(0.0f), _textureHeightRatio(0.0f), _capacity(0), _count(0),
  48. _vertices(NULL), _verticesPtr(NULL), _indices(NULL), _indicesPtr(NULL), _index(0),
  49. _drawing(false), _projectionMatrix(NULL), _customProjectionMatrix(false)
  50. {
  51. _stateBlock = RenderState::StateBlock::create();
  52. _stateBlock->setBlend(true);
  53. _stateBlock->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  54. _stateBlock->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
  55. }
  56. SpriteBatch::SpriteBatch(const SpriteBatch& copy)
  57. {
  58. // hiddden
  59. }
  60. SpriteBatch::~SpriteBatch()
  61. {
  62. SAFE_RELEASE(_stateBlock);
  63. SAFE_DELETE_ARRAY(_vertices);
  64. SAFE_DELETE_ARRAY(_indices);
  65. SAFE_DELETE(_projectionMatrix);
  66. SAFE_RELEASE(_sampler);
  67. SAFE_RELEASE(_effect);
  68. }
  69. SpriteBatch* SpriteBatch::create(Texture* texture, Effect* effect, unsigned int initialCapacity)
  70. {
  71. assert(texture != NULL);
  72. if (effect == NULL)
  73. {
  74. // Create our static sprite effect.
  75. if (__spriteEffect == NULL)
  76. {
  77. __spriteEffect = Effect::createFromSource(SPRITE_VSH, SPRITE_FSH);
  78. if (__spriteEffect == NULL)
  79. {
  80. LOG_ERROR("Unable to load sprite effect.");
  81. return NULL;
  82. }
  83. effect = __spriteEffect;
  84. }
  85. else
  86. {
  87. effect = __spriteEffect;
  88. effect->addRef();
  89. }
  90. }
  91. else
  92. {
  93. // Add a reference to the effect.
  94. effect->addRef();
  95. }
  96. // Look up vertex attributes.
  97. VertexAttribute vaPosition = effect->getVertexAttribute("a_position");
  98. VertexAttribute vaTexCoord = effect->getVertexAttribute("a_texcoord");
  99. VertexAttribute vaColor = effect->getVertexAttribute("a_color");
  100. if (vaPosition == -1 || vaTexCoord == -1 || vaColor == -1)
  101. {
  102. LOG_ERROR("Failed to load vertex attributes for sprite effect.");
  103. SAFE_RELEASE(effect);
  104. return NULL;
  105. }
  106. // Search for the first sampler uniform in the effect.
  107. Uniform* samplerUniform = NULL;
  108. for (unsigned int i = 0, count = effect->getUniformCount(); i < count; ++i)
  109. {
  110. Uniform* uniform = effect->getUniform(i);
  111. if (uniform && uniform->getType() == GL_SAMPLER_2D)
  112. {
  113. samplerUniform = uniform;
  114. break;
  115. }
  116. }
  117. if (!samplerUniform)
  118. {
  119. LOG_ERROR("No uniform of type GL_SAMPLER_2D found in sprite effect.");
  120. SAFE_RELEASE(effect);
  121. return NULL;
  122. }
  123. // Create the batch.
  124. SpriteBatch* batch = new SpriteBatch();
  125. batch->_effect = effect;
  126. batch->_sampler = Texture::Sampler::create(texture);
  127. batch->_samplerUniform = samplerUniform;
  128. batch->_vaPosition = vaPosition;
  129. batch->_vaTexCoord = vaTexCoord;
  130. batch->_vaColor = vaColor;
  131. batch->_textureWidthRatio = 1.0f / (float)texture->getWidth();
  132. batch->_textureHeightRatio = 1.0f / (float)texture->getHeight();
  133. batch->resizeBatch(initialCapacity > 0 ? initialCapacity : SPRITE_BATCH_DEFAULT_SIZE);
  134. // If there is a uniform named 'u_projectionMatrix', store it so that we can set our projection matrix to it
  135. batch->_projectionUniform = effect->getUniform("u_projectionMatrix");
  136. if (batch->_projectionUniform)
  137. {
  138. batch->_projectionMatrix = new Matrix();
  139. }
  140. return batch;
  141. }
  142. void SpriteBatch::begin()
  143. {
  144. assert(!_drawing);
  145. // Simply clear our sprite count to start writing to the beginning of the batch.
  146. _count = 0;
  147. _index = 0;
  148. _verticesPtr = _vertices;
  149. _indicesPtr = _indices;
  150. _drawing = true;
  151. }
  152. void SpriteBatch::draw(const Rectangle& dst, const Rectangle& src, const Vector4& color)
  153. {
  154. // Calculate uvs.
  155. float u1 = _textureWidthRatio * src.x;
  156. float v1 = 1.0f - _textureHeightRatio * src.y;
  157. float u2 = u1 + _textureWidthRatio * src.width;
  158. float v2 = v1 - _textureHeightRatio * src.height;
  159. draw(dst.x, dst.y, dst.width, dst.height, u1, v1, u2, v2, color);
  160. }
  161. void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color)
  162. {
  163. // Calculate uvs.
  164. float u1 = _textureWidthRatio * src.x;
  165. float v1 = 1.0f - _textureHeightRatio * src.y;
  166. float u2 = u1 + _textureWidthRatio * src.width;
  167. float v2 = v1 - _textureHeightRatio * src.height;
  168. draw(dst.x, dst.y, dst.z, scale.x, scale.y, u2, v2, u1, v1, color);
  169. }
  170. void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color,
  171. const Vector2& rotationPoint, float rotationAngle)
  172. {
  173. assert(_drawing);
  174. if (_count >= _capacity)
  175. {
  176. growBatch();
  177. }
  178. // Calculate uvs.
  179. float u1 = _textureWidthRatio * src.x;
  180. float v1 = 1.0f - _textureHeightRatio * src.y;
  181. float u2 = u1 + _textureWidthRatio * src.width;
  182. float v2 = v1 - _textureHeightRatio * src.height;
  183. draw(dst, scale.x, scale.y, u1, v1, u2, v2, color, rotationPoint, rotationAngle);
  184. }
  185. void SpriteBatch::draw(const Vector3& dst, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color,
  186. const Vector2& rotationPoint, float rotationAngle)
  187. {
  188. // Expand dst by scale into 4 points.
  189. float x2 = dst.x + width;
  190. float y2 = dst.y + height;
  191. Vector2 upLeft(dst.x, dst.y);
  192. Vector2 upRight(x2, dst.y);
  193. Vector2 downLeft(dst.x, y2);
  194. Vector2 downRight(x2, y2);
  195. // Rotate points around rotationAxis by rotationAngle.
  196. Vector2 pivotPoint(rotationPoint);
  197. pivotPoint.x *= width;
  198. pivotPoint.y *= height;
  199. pivotPoint.x += dst.x;
  200. pivotPoint.y += dst.y;
  201. upLeft.rotate(pivotPoint, rotationAngle);
  202. upRight.rotate(pivotPoint, rotationAngle);
  203. downLeft.rotate(pivotPoint, rotationAngle);
  204. downRight.rotate(pivotPoint, rotationAngle);
  205. // Write sprite vertex data.
  206. ADD_SPRITE_VERTEX(_verticesPtr, upLeft.x, upLeft.y, dst.z, u1, v1, color.x, color.y, color.z, color.w);
  207. ADD_SPRITE_VERTEX((_verticesPtr + 9), upRight.x, upRight.y, dst.z, u1, v2, color.x, color.y, color.z, color.w);
  208. ADD_SPRITE_VERTEX((_verticesPtr + 18), downLeft.x, downLeft.y, dst.z, u2, v1, color.x, color.y, color.z, color.w);
  209. ADD_SPRITE_VERTEX((_verticesPtr + 27), downRight.x, downRight.y, dst.z, u2, v2, color.x, color.y, color.z, color.w);
  210. _verticesPtr += 36; // 4 vertices per sprite, 9 elements per vertex (4*9)
  211. // Write sprite index data.
  212. if (_count > 0)
  213. {
  214. // Create a degenerate triangle to connect two triangle strips
  215. // by duplicating the previous and next vertices.
  216. _indicesPtr[0] = *(_indicesPtr-1);
  217. _indicesPtr[1] = _index;
  218. _indicesPtr += 2;
  219. }
  220. _indicesPtr[0] = _index;
  221. _indicesPtr[1] = _index + 1;
  222. _indicesPtr[2] = _index + 2;
  223. _indicesPtr[3] = _index + 3;
  224. _indicesPtr += 4;
  225. _index += 4;
  226. ++_count;
  227. }
  228. void SpriteBatch::draw(float x, float y, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
  229. {
  230. draw(x, y, 0, width, height, u1, v1, u2, v2, color);
  231. }
  232. void SpriteBatch::draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
  233. {
  234. assert(_drawing);
  235. if (_count >= _capacity)
  236. {
  237. growBatch();
  238. }
  239. // Write sprite vertex data.
  240. float x2 = x + width;
  241. float y2 = y + height;
  242. ADD_SPRITE_VERTEX(_verticesPtr, x, y, z, u1, v1, color.x, color.y, color.z, color.w);
  243. ADD_SPRITE_VERTEX((_verticesPtr + 9), x, y2, z, u1, v2, color.x, color.y, color.z, color.w);
  244. ADD_SPRITE_VERTEX((_verticesPtr + 18), x2, y, z, u2, v1, color.x, color.y, color.z, color.w);
  245. ADD_SPRITE_VERTEX((_verticesPtr + 27), x2, y2, z, u2, v2, color.x, color.y, color.z, color.w);
  246. _verticesPtr += 36; // 4 vertices per sprite, 9 elements per vertex (4*9)
  247. // Write sprite index data.
  248. if (_count > 0)
  249. {
  250. // Create a degenerate triangle to connect two triangle strips
  251. // by duplicating the previous and next vertices.
  252. _indicesPtr[0] = *(_indicesPtr-1);
  253. _indicesPtr[1] = _index;
  254. _indicesPtr += 2;
  255. }
  256. _indicesPtr[0] = _index;
  257. _indicesPtr[1] = _index + 1;
  258. _indicesPtr[2] = _index + 2;
  259. _indicesPtr[3] = _index + 3;
  260. _indicesPtr += 4;
  261. _index += 4;
  262. ++_count;
  263. }
  264. void SpriteBatch::end()
  265. {
  266. assert(_drawing);
  267. if (_count > 0)
  268. {
  269. // Flush the batch.
  270. if (_projectionMatrix && !_customProjectionMatrix)
  271. {
  272. // Update projection matrix with ortho projection.
  273. Game* game = Game::getInstance();
  274. Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, _projectionMatrix);
  275. }
  276. // Apply render state
  277. _stateBlock->bind();
  278. // Bind our effect and any required parameters
  279. _effect->bind();
  280. if (_samplerUniform && _sampler)
  281. {
  282. _effect->setValue(_samplerUniform, _sampler);
  283. }
  284. if (_projectionMatrix)
  285. {
  286. _effect->setValue(_projectionUniform, _projectionMatrix);
  287. }
  288. // Unbind any currently bound VBOs so we can use client arrays.
  289. GL_ASSERT( glBindBuffer(GL_ARRAY_BUFFER, 0 ) );
  290. GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 ) );
  291. GL_ASSERT( glEnableVertexAttribArray(_vaPosition) );
  292. GL_ASSERT( glVertexAttribPointer(_vaPosition, 3, GL_FLOAT, GL_FALSE, 36, (GLvoid*)_vertices) );
  293. GL_ASSERT( glEnableVertexAttribArray(_vaTexCoord) );
  294. GL_ASSERT( glVertexAttribPointer(_vaTexCoord, 2, GL_FLOAT, GL_FALSE, 36, (GLvoid*)(_vertices + 3)) );
  295. GL_ASSERT( glEnableVertexAttribArray(_vaColor) );
  296. GL_ASSERT( glVertexAttribPointer(_vaColor, 4, GL_FLOAT, GL_FALSE, 36, (GLvoid*)(_vertices + 5)) );
  297. GLsizei indexCount = _count * 4 + ((_count - 1) * 2);
  298. GL_ASSERT( glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_SHORT, (GLvoid*)_indices) );
  299. glDisableVertexAttribArray(_vaPosition);
  300. glDisableVertexAttribArray(_vaTexCoord);
  301. glDisableVertexAttribArray(_vaColor);
  302. }
  303. _drawing = false;
  304. }
  305. RenderState::StateBlock* SpriteBatch::getStateBlock() const
  306. {
  307. return _stateBlock;
  308. }
  309. void SpriteBatch::growBatch()
  310. {
  311. resizeBatch(_capacity == 0 ? SPRITE_BATCH_DEFAULT_SIZE : (int)((float)_capacity * SPRITE_BATCH_GROW_FACTOR));
  312. }
  313. void SpriteBatch::resizeBatch(unsigned int capacity)
  314. {
  315. // 4 verts per sprite
  316. unsigned int newVertexCapacity = capacity * 4;
  317. // 2 extra indices per sprite for degenerate vertices
  318. unsigned int newIndexCapacity = capacity * 4 + ((capacity - 1) * 2);
  319. // 9 elements per vertex (x,y,z,u,v,r,g,b,a)
  320. float* newVertices = new float[newVertexCapacity * 9];
  321. unsigned short* newIndices = new unsigned short[newIndexCapacity];
  322. // Copy and destroy old arrays.
  323. if (_vertices)
  324. {
  325. if (_count > 0)
  326. {
  327. unsigned int vertexCount = _count * 4;
  328. if (vertexCount > newVertexCapacity)
  329. {
  330. vertexCount = newVertexCapacity;
  331. }
  332. memcpy(newVertices, _vertices, vertexCount * 9 * sizeof(float));
  333. }
  334. SAFE_DELETE_ARRAY(_vertices);
  335. }
  336. if (_indices)
  337. {
  338. if (_count > 0)
  339. {
  340. unsigned int indexCount = _count * 4 + ((_count - 1) * 2);
  341. if (indexCount > newIndexCapacity)
  342. {
  343. indexCount = newIndexCapacity;
  344. }
  345. memcpy(newIndices, _indices, indexCount * sizeof(unsigned short));
  346. }
  347. SAFE_DELETE_ARRAY(_indices);
  348. }
  349. // Store new arrays.
  350. _vertices = newVertices;
  351. _indices = newIndices;
  352. _capacity = capacity;
  353. if (_count > _capacity)
  354. {
  355. _count = capacity;
  356. }
  357. // Update current pointers.
  358. if (_count > 0)
  359. {
  360. _verticesPtr = _vertices + (_count * 36);
  361. _indicesPtr = _indices + (_count * 4) + ((_count - 1) * 2);
  362. }
  363. else
  364. {
  365. _verticesPtr = _vertices;
  366. _indicesPtr = _indices;
  367. }
  368. }
  369. Effect* SpriteBatch::getEffect()
  370. {
  371. return _effect;
  372. }
  373. void SpriteBatch::setProjectionMatrix(const Matrix& matrix)
  374. {
  375. if (_projectionMatrix)
  376. {
  377. _projectionMatrix->set(matrix);
  378. _customProjectionMatrix = true;
  379. }
  380. }
  381. }