SpriteBatch.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include "Base.h"
  2. #include "SpriteBatch.h"
  3. #include "Game.h"
  4. // Default size of a newly created sprite batch
  5. #define SPRITE_BATCH_DEFAULT_SIZE 128
  6. // Factor to grow a sprite batch by when its size is exceeded
  7. #define SPRITE_BATCH_GROW_FACTOR 2.0f
  8. // Macro for adding a sprite to the batch
  9. #define ADD_SPRITE_VERTEX(vtx, vx, vy, vz, vu, vv, vr, vg, vb, va) \
  10. vtx.x = vx; vtx.y = vy; vtx.z = vz; \
  11. vtx.u = vu; vtx.v = vv; \
  12. vtx.r = vr; vtx.g = vg; vtx.b = vb; vtx.a = va
  13. // Default sprite vertex shader
  14. #define SPRITE_VSH \
  15. "uniform mat4 u_projectionMatrix;\n" \
  16. "attribute vec3 a_position;\n" \
  17. "attribute vec2 a_texCoord;\n" \
  18. "attribute vec4 a_color;\n" \
  19. "varying vec2 v_texCoord;\n" \
  20. "varying vec4 v_color;\n" \
  21. "void main()\n" \
  22. "{\n" \
  23. "gl_Position = u_projectionMatrix * vec4(a_position, 1);\n" \
  24. "v_texCoord = a_texCoord;\n" \
  25. "v_color = a_color;\n" \
  26. "}\n"
  27. // Default sprite fragment shader
  28. #define SPRITE_FSH \
  29. "#ifdef OPENGL_ES\n" \
  30. "precision highp float;\n" \
  31. "#endif\n" \
  32. "varying vec2 v_texCoord;\n" \
  33. "varying vec4 v_color;\n" \
  34. "uniform sampler2D u_texture;\n" \
  35. "void main()\n" \
  36. "{\n" \
  37. "gl_FragColor = v_color * texture2D(u_texture, v_texCoord);\n" \
  38. "}\n"
  39. namespace gameplay
  40. {
  41. // Sprite vertex structured used for batching
  42. struct SpriteVertex
  43. {
  44. float x, y, z;
  45. float u, v;
  46. float r, g, b, a;
  47. };
  48. // Shared sprite effects
  49. static Effect* __spriteEffect = NULL;
  50. SpriteBatch::SpriteBatch()
  51. : _batch(NULL), _textureWidthRatio(0.0f), _textureHeightRatio(0.0f)
  52. {
  53. }
  54. SpriteBatch::SpriteBatch(const SpriteBatch& copy)
  55. {
  56. // hiddden
  57. }
  58. SpriteBatch::~SpriteBatch()
  59. {
  60. SAFE_DELETE(_batch);
  61. }
  62. SpriteBatch* SpriteBatch::create(const char* texturePath, Effect* effect, unsigned int initialCapacity)
  63. {
  64. Texture* texture = Texture::create(texturePath);
  65. SpriteBatch* batch = SpriteBatch::create(texture);
  66. SAFE_RELEASE(texture);
  67. return batch;
  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. }
  89. }
  90. // Search for the first sampler uniform in the effect.
  91. Uniform* samplerUniform = NULL;
  92. for (unsigned int i = 0, count = effect->getUniformCount(); i < count; ++i)
  93. {
  94. Uniform* uniform = effect->getUniform(i);
  95. if (uniform && uniform->getType() == GL_SAMPLER_2D)
  96. {
  97. samplerUniform = uniform;
  98. break;
  99. }
  100. }
  101. if (!samplerUniform)
  102. {
  103. LOG_ERROR("No uniform of type GL_SAMPLER_2D found in sprite effect.");
  104. SAFE_RELEASE(effect);
  105. return NULL;
  106. }
  107. // Wrap the effect in a material
  108. Material* material = Material::create(effect); // +ref effect
  109. // Set initial material state
  110. material->getStateBlock()->setBlend(true);
  111. material->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  112. material->getStateBlock()->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
  113. // Bind the texture to the material as a sampler
  114. Texture::Sampler* sampler = Texture::Sampler::create(texture); // +ref texture
  115. material->getParameter(samplerUniform->getName())->setValue(sampler);
  116. SAFE_RELEASE(sampler);
  117. // Define the vertex format for the batch
  118. VertexFormat::Element vertexElements[] =
  119. {
  120. VertexFormat::Element(VertexFormat::POSITION, 3),
  121. VertexFormat::Element(VertexFormat::TEXCOORD0, 2),
  122. VertexFormat::Element(VertexFormat::COLOR, 4),
  123. };
  124. VertexFormat vertexFormat(vertexElements, 3);
  125. // Create the mesh batch
  126. MeshBatch* meshBatch = MeshBatch::create(vertexFormat, Mesh::TRIANGLE_STRIP, material, true, initialCapacity > 0 ? initialCapacity : SPRITE_BATCH_DEFAULT_SIZE);
  127. material->release(); // don't call SAFE_RELEASE since material is used below
  128. // Create the batch
  129. SpriteBatch* batch = new SpriteBatch();
  130. batch->_batch = meshBatch;
  131. batch->_textureWidthRatio = 1.0f / (float)texture->getWidth();
  132. batch->_textureHeightRatio = 1.0f / (float)texture->getHeight();
  133. // Bind an ortho projection to the material by default (user can override with setProjectionMatrix)
  134. material->getParameter("u_projectionMatrix")->bindValue(batch, &SpriteBatch::getOrthoMatrix);
  135. return batch;
  136. }
  137. void SpriteBatch::begin()
  138. {
  139. _batch->begin();
  140. }
  141. void SpriteBatch::draw(const Rectangle& dst, const Rectangle& src, const Vector4& color)
  142. {
  143. // Calculate uvs.
  144. float u1 = _textureWidthRatio * src.x;
  145. float v1 = 1.0f - _textureHeightRatio * src.y;
  146. float u2 = u1 + _textureWidthRatio * src.width;
  147. float v2 = v1 - _textureHeightRatio * src.height;
  148. draw(dst.x, dst.y, dst.width, dst.height, u1, v1, u2, v2, color);
  149. }
  150. void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color)
  151. {
  152. // Calculate uvs.
  153. float u1 = _textureWidthRatio * src.x;
  154. float v1 = 1.0f - _textureHeightRatio * src.y;
  155. float u2 = u1 + _textureWidthRatio * src.width;
  156. float v2 = v1 - _textureHeightRatio * src.height;
  157. draw(dst.x, dst.y, dst.z, scale.x, scale.y, u2, v2, u1, v1, color);
  158. }
  159. void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color,
  160. const Vector2& rotationPoint, float rotationAngle)
  161. {
  162. // Calculate uvs.
  163. float u1 = _textureWidthRatio * src.x;
  164. float v1 = 1.0f - _textureHeightRatio * src.y;
  165. float u2 = u1 + _textureWidthRatio * src.width;
  166. float v2 = v1 - _textureHeightRatio * src.height;
  167. draw(dst, scale.x, scale.y, u1, v1, u2, v2, color, rotationPoint, rotationAngle);
  168. }
  169. void SpriteBatch::draw(const Vector3& dst, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color,
  170. const Vector2& rotationPoint, float rotationAngle)
  171. {
  172. // Expand dst by scale into 4 points.
  173. float x2 = dst.x + width;
  174. float y2 = dst.y + height;
  175. Vector2 upLeft(dst.x, dst.y);
  176. Vector2 upRight(x2, dst.y);
  177. Vector2 downLeft(dst.x, y2);
  178. Vector2 downRight(x2, y2);
  179. // Rotate points around rotationAxis by rotationAngle.
  180. Vector2 pivotPoint(rotationPoint);
  181. pivotPoint.x *= width;
  182. pivotPoint.y *= height;
  183. pivotPoint.x += dst.x;
  184. pivotPoint.y += dst.y;
  185. upLeft.rotate(pivotPoint, rotationAngle);
  186. upRight.rotate(pivotPoint, rotationAngle);
  187. downLeft.rotate(pivotPoint, rotationAngle);
  188. downRight.rotate(pivotPoint, rotationAngle);
  189. // Write sprite vertex data.
  190. static SpriteVertex v[4];
  191. ADD_SPRITE_VERTEX(v[0], upLeft.x, upLeft.y, dst.z, u1, v1, color.x, color.y, color.z, color.w);
  192. ADD_SPRITE_VERTEX(v[1], upRight.x, upRight.y, dst.z, u1, v2, color.x, color.y, color.z, color.w);
  193. ADD_SPRITE_VERTEX(v[2], downLeft.x, downLeft.y, dst.z, u2, v1, color.x, color.y, color.z, color.w);
  194. ADD_SPRITE_VERTEX(v[3], downRight.x, downRight.y, dst.z, u2, v2, color.x, color.y, color.z, color.w);
  195. static unsigned short indices[4] = { 0, 1, 2, 3 };
  196. _batch->add(v, 4, indices, 4);
  197. }
  198. void SpriteBatch::draw(float x, float y, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
  199. {
  200. draw(x, y, 0, width, height, u1, v1, u2, v2, color);
  201. }
  202. void SpriteBatch::draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
  203. {
  204. // Write sprite vertex data.
  205. float x2 = x + width;
  206. float y2 = y + height;
  207. static SpriteVertex v[4];
  208. ADD_SPRITE_VERTEX(v[0], x, y, z, u1, v1, color.x, color.y, color.z, color.w);
  209. ADD_SPRITE_VERTEX(v[1], x, y2, z, u1, v2, color.x, color.y, color.z, color.w);
  210. ADD_SPRITE_VERTEX(v[2], x2, y, z, u2, v1, color.x, color.y, color.z, color.w);
  211. ADD_SPRITE_VERTEX(v[3], x2, y2, z, u2, v2, color.x, color.y, color.z, color.w);
  212. static unsigned short indices[4] = { 0, 1, 2, 3 };
  213. _batch->add(v, 4, indices, 4);
  214. }
  215. void SpriteBatch::end()
  216. {
  217. // Finish and draw the batch
  218. _batch->end();
  219. _batch->draw();
  220. }
  221. RenderState::StateBlock* SpriteBatch::getStateBlock() const
  222. {
  223. return _batch->getMaterial()->getStateBlock();
  224. }
  225. Material* SpriteBatch::getMaterial()
  226. {
  227. return _batch->getMaterial();
  228. }
  229. void SpriteBatch::setProjectionMatrix(const Matrix& matrix)
  230. {
  231. // Bind the specified matrix to a parameter named 'u_projectionMatrix' (assumed to exist).
  232. _batch->getMaterial()->getParameter("u_projectionMatrix")->setValue(matrix);
  233. }
  234. const Matrix& SpriteBatch::getOrthoMatrix() const
  235. {
  236. // Update matrix with ortho projection and return it.
  237. Game* game = Game::getInstance();
  238. Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &_projectionMatrix);
  239. return _projectionMatrix;
  240. }
  241. }