CmSprite.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "CmTextSprite.h"
  2. #include "CmVector2.h"
  3. #include "CmGUIMaterialManager.h"
  4. namespace CamelotEngine
  5. {
  6. Sprite::Sprite()
  7. {
  8. }
  9. Sprite::~Sprite()
  10. {
  11. clearMesh();
  12. }
  13. UINT32 Sprite::getNumRenderElements() const
  14. {
  15. return (UINT32)mCachedRenderElements.size();
  16. }
  17. const HMaterial& Sprite::getMaterial(UINT32 renderElementIdx) const
  18. {
  19. return mCachedRenderElements.at(renderElementIdx).material;
  20. }
  21. UINT32 Sprite::getNumQuads(UINT32 renderElementIdx) const
  22. {
  23. return mCachedRenderElements.at(renderElementIdx).numQuads;
  24. }
  25. UINT32 Sprite::fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const
  26. {
  27. auto renderElem = mCachedRenderElements.at(renderElementIdx);
  28. UINT32 startVert = startingQuad * 4;
  29. UINT32 startIndex = startingQuad * 4;
  30. UINT32 maxVertIdx = maxNumQuads * 4;
  31. UINT32 maxIndexIdx = maxNumQuads * 6;
  32. UINT32 mNumVertices = renderElem.numQuads * 4;
  33. UINT32 mNumIndices = renderElem.numQuads * 6;
  34. assert((startVert + mNumVertices) <= maxVertIdx);
  35. assert((startIndex + mNumIndices) <= maxIndexIdx);
  36. memcpy(&vertices[startVert], renderElem.vertices, mNumVertices * sizeof(Vector2));
  37. memcpy(&uv[startVert], renderElem.uvs, mNumVertices * sizeof(Vector2));
  38. memcpy(&indices[startIndex], renderElem.indexes, mNumIndices * sizeof(UINT32));
  39. return renderElem.numQuads;
  40. }
  41. Point Sprite::getAnchorOffset(SpriteAnchor anchor, UINT32 width, UINT32 height) const
  42. {
  43. switch(anchor)
  44. {
  45. case SA_TopLeft:
  46. return -Point(0, 0);
  47. case SA_TopCenter:
  48. return -Point(width / 2, 0);
  49. case SA_TopRight:
  50. return -Point(width, 0);
  51. case SA_MiddleLeft:
  52. return -Point(0, height / 2);
  53. case SA_MiddleCenter:
  54. return -Point(width / 2, height / 2);
  55. case SA_MiddleRight:
  56. return -Point(width, height / 2);
  57. case SA_BottomLeft:
  58. return -Point(0, height);
  59. case SA_BottomCenter:
  60. return -Point(width / 2, height);
  61. case SA_BottomRight:
  62. return -Point(width, height);
  63. }
  64. return Point();
  65. }
  66. void Sprite::updateBounds() const
  67. {
  68. Vector2 min;
  69. Vector2 max;
  70. // Find starting point
  71. for(auto& renderElem : mCachedRenderElements)
  72. {
  73. if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
  74. {
  75. min = renderElem.vertices[0];
  76. max = renderElem.vertices[0];
  77. break;
  78. }
  79. }
  80. // Calculate bounds
  81. for(auto& renderElem : mCachedRenderElements)
  82. {
  83. if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
  84. {
  85. UINT32 vertexCount = renderElem.numQuads * 4;
  86. for(UINT32 i = 0; i < vertexCount; i++)
  87. {
  88. min = Vector2::min(min, renderElem.vertices[i]);
  89. max = Vector2::max(max, renderElem.vertices[i]);
  90. }
  91. }
  92. }
  93. mBounds = Rect((int)min.x, (int)min.y, (int)(max.x - min.x), (int)(max.y - min.y));
  94. }
  95. void Sprite::clearMesh() const
  96. {
  97. for(auto& renderElem : mCachedRenderElements)
  98. {
  99. UINT32 vertexCount = renderElem.numQuads * 4;
  100. UINT32 indexCount = renderElem.numQuads * 6;
  101. if(renderElem.vertices != nullptr)
  102. CM_DELETE_ARRAY(renderElem.vertices, Vector2, vertexCount, ScratchAlloc);
  103. if(renderElem.uvs != nullptr)
  104. CM_DELETE_ARRAY(renderElem.uvs, Vector2, vertexCount, ScratchAlloc);
  105. if(renderElem.indexes != nullptr)
  106. CM_DELETE_ARRAY(renderElem.indexes, UINT32, indexCount, ScratchAlloc);
  107. if(renderElem.material != nullptr)
  108. {
  109. GUIMaterialManager::instance().releaseMaterial(renderElem.material);
  110. }
  111. }
  112. mCachedRenderElements.clear();
  113. updateBounds();
  114. }
  115. // This will only properly clip an array of rectangular quads
  116. // Vertices in the quad must be in a specific order: top left, top right, bottom left, bottom right
  117. // (0, 0) represents top left of the screen
  118. void Sprite::clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, const Rect& clipRect) const
  119. {
  120. float left = (float)clipRect.x;
  121. float right = (float)clipRect.x + clipRect.width;
  122. float top = (float)clipRect.y;
  123. float bottom = (float)clipRect.y - clipRect.height;
  124. for(UINT32 i = 0; i < numQuads; i++)
  125. {
  126. UINT32 vertIdx = i * 4;
  127. // Attempt to skip those that are definitely not clipped
  128. if(vertices[vertIdx + 0].x >= left && vertices[vertIdx + 1].x <= right &&
  129. vertices[vertIdx + 0].y <= top && vertices[vertIdx + 2].y >= bottom)
  130. {
  131. continue;
  132. }
  133. float du = (uv[vertIdx + 1].x - uv[vertIdx + 0].x) / (vertices[vertIdx + 1].x - vertices[vertIdx + 0].x);
  134. float dv = (uv[vertIdx + 0].y - uv[vertIdx + 2].y) / (vertices[vertIdx + 0].y - vertices[vertIdx + 2].y);
  135. // Clip left
  136. float newLeft = Math::Clamp(vertices[vertIdx + 0].x, left, right);
  137. float uvLeftOffset = (newLeft - vertices[vertIdx + 0].x) * du;
  138. vertices[vertIdx + 0].x = newLeft;
  139. vertices[vertIdx + 2].x = newLeft;
  140. uv[vertIdx + 0].x += uvLeftOffset;
  141. uv[vertIdx + 2].x += uvLeftOffset;
  142. // Clip right
  143. float newRight = Math::Clamp(vertices[vertIdx + 1].x, left, right);
  144. float uvRightOffset = (vertices[vertIdx + 1].x - newRight) * du;
  145. vertices[vertIdx + 1].x = newRight;
  146. vertices[vertIdx + 3].x = newRight;
  147. uv[vertIdx + 1].x -= uvRightOffset;
  148. uv[vertIdx + 3].x -= uvRightOffset;
  149. // Clip top
  150. float newTop = Math::Clamp(vertices[vertIdx + 0].y, bottom, top);
  151. float uvTopOffset = (vertices[vertIdx + 0].y - newTop) * dv;
  152. vertices[vertIdx + 0].y = newTop;
  153. vertices[vertIdx + 1].y = newTop;
  154. uv[vertIdx + 0].y -= uvTopOffset;
  155. uv[vertIdx + 1].y -= uvTopOffset;
  156. // Clip bottom
  157. float newBottom = Math::Clamp(vertices[vertIdx + 2].y, bottom, top);
  158. float uvBottomOffset = (newBottom - vertices[vertIdx + 2].y) * dv;
  159. vertices[vertIdx + 2].y = newBottom;
  160. vertices[vertIdx + 3].y = newBottom;
  161. uv[vertIdx + 2].y += uvBottomOffset;
  162. uv[vertIdx + 3].y += uvBottomOffset;
  163. }
  164. }
  165. }