BsTextSprite.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include "BsTextSprite.h"
  2. #include "BsGUIMaterialManager.h"
  3. #include "CmTextUtility.h"
  4. #include "CmFont.h"
  5. #include "CmVector2.h"
  6. using namespace CamelotFramework;
  7. namespace BansheeEngine
  8. {
  9. TextSprite::TextSprite()
  10. {
  11. }
  12. void TextSprite::update(const TEXT_SPRITE_DESC& desc)
  13. {
  14. std::shared_ptr<TextUtility::TextData> textData = TextUtility::getTextData(desc.text, desc.font, desc.fontSize, desc.width, desc.height, desc.wordWrap);
  15. if(textData == nullptr)
  16. return;
  17. const CM::Vector<TextUtility::TextLine>::type& lines = textData->getLines();
  18. const CM::Vector<UINT32>::type& quadsPerPage = textData->getNumQuadsPerPage();
  19. // Resize cached mesh array to needed size
  20. if(mCachedRenderElements.size() > quadsPerPage.size())
  21. {
  22. for(UINT32 i = (UINT32)quadsPerPage.size(); i < (UINT32)mCachedRenderElements.size(); i++)
  23. {
  24. auto& renderElem = mCachedRenderElements[i];
  25. UINT32 vertexCount = renderElem.numQuads * 4;
  26. UINT32 indexCount = renderElem.numQuads * 6;
  27. if(renderElem.vertices != nullptr)
  28. cm_deleteN<ScratchAlloc>(renderElem.vertices, vertexCount);
  29. if(renderElem.uvs != nullptr)
  30. cm_deleteN<ScratchAlloc>(renderElem.uvs, vertexCount);
  31. if(renderElem.indexes != nullptr)
  32. cm_deleteN<ScratchAlloc>(renderElem.indexes, indexCount);
  33. if(renderElem.material != nullptr)
  34. {
  35. GUIMaterialManager::instance().releaseMaterial(renderElem.material);
  36. }
  37. }
  38. }
  39. if(mCachedRenderElements.size() != quadsPerPage.size())
  40. mCachedRenderElements.resize(quadsPerPage.size());
  41. // Actually generate a mesh
  42. const CM::Vector<HTexture>::type& texturePages = textData->getTexturePages();
  43. UINT32 texPage = 0;
  44. for(auto& cachedElem : mCachedRenderElements)
  45. {
  46. UINT32 newNumQuads = quadsPerPage[texPage];
  47. if(newNumQuads != cachedElem.numQuads)
  48. {
  49. UINT32 oldVertexCount = cachedElem.numQuads * 4;
  50. UINT32 oldIndexCount = cachedElem.numQuads * 6;
  51. if(cachedElem.vertices != nullptr) cm_deleteN<ScratchAlloc>(cachedElem.vertices, oldVertexCount);
  52. if(cachedElem.uvs != nullptr) cm_deleteN<ScratchAlloc>(cachedElem.uvs, oldVertexCount);
  53. if(cachedElem.indexes != nullptr) cm_deleteN<ScratchAlloc>(cachedElem.indexes, oldIndexCount);
  54. cachedElem.vertices = cm_newN<Vector2, ScratchAlloc>(newNumQuads * 4);
  55. cachedElem.uvs = cm_newN<Vector2, ScratchAlloc>(newNumQuads * 4);
  56. cachedElem.indexes = cm_newN<UINT32, ScratchAlloc>(newNumQuads * 6);
  57. cachedElem.numQuads = newNumQuads;
  58. }
  59. HMaterial newMaterial = GUIMaterialManager::instance().requestTextMaterial(texturePages[texPage]);
  60. if(cachedElem.material != nullptr)
  61. GUIMaterialManager::instance().releaseMaterial(newMaterial);
  62. cachedElem.material = newMaterial;
  63. texPage++;
  64. }
  65. // Calc alignment and anchor offsets and set final line positions
  66. UINT32 numPages = (UINT32)quadsPerPage.size();
  67. for(UINT32 j = 0; j < numPages; j++)
  68. {
  69. SpriteRenderElement& renderElem = mCachedRenderElements[j];
  70. genTextQuads(j, *textData, desc.width, desc.height, desc.horzAlign, desc.vertAlign, desc.anchor,
  71. renderElem.vertices, renderElem.uvs, renderElem.indexes, renderElem.numQuads);
  72. }
  73. updateBounds();
  74. }
  75. UINT32 TextSprite::genTextQuads(UINT32 page, const TextUtility::TextData& textData, UINT32 width, UINT32 height,
  76. TextHorzAlign horzAlign, TextVertAlign vertAlign, SpriteAnchor anchor, Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 bufferSizeQuads)
  77. {
  78. const CM::Vector<TextUtility::TextLine>::type& lines = textData.getLines();
  79. const CM::Vector<UINT32>::type& quadsPerPage = textData.getNumQuadsPerPage();
  80. UINT32 newNumQuads = quadsPerPage[page];
  81. Vector<Int2>::type alignmentOffsets = getAlignmentOffsets(lines, width, height, horzAlign, vertAlign);
  82. Int2 offset = getAnchorOffset(anchor, width, height);
  83. UINT32 quadOffset = 0;
  84. for(size_t i = 0; i < lines.size(); i++)
  85. {
  86. UINT32 writtenQuads = lines[i].fillBuffer(page, vertices, uv, indices, quadOffset, bufferSizeQuads);
  87. Int2 position = offset + alignmentOffsets[i];
  88. UINT32 numVertices = writtenQuads * 4;
  89. for(UINT32 i = 0; i < numVertices; i++)
  90. {
  91. vertices[quadOffset * 4 + i].x += (float)position.x;
  92. vertices[quadOffset * 4 + i].y += (float)position.y;
  93. }
  94. quadOffset += writtenQuads;
  95. }
  96. return newNumQuads;
  97. }
  98. UINT32 TextSprite::genTextQuads(const TextUtility::TextData& textData, UINT32 width, UINT32 height,
  99. TextHorzAlign horzAlign, TextVertAlign vertAlign, SpriteAnchor anchor, Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 bufferSizeQuads)
  100. {
  101. const CM::Vector<TextUtility::TextLine>::type& lines = textData.getLines();
  102. const CM::Vector<UINT32>::type& quadsPerPage = textData.getNumQuadsPerPage();
  103. Vector<Int2>::type alignmentOffsets = getAlignmentOffsets(lines, width, height, horzAlign, vertAlign);
  104. Int2 offset = getAnchorOffset(anchor, width, height);
  105. UINT32 quadOffset = 0;
  106. UINT32 numPages = (UINT32)quadsPerPage.size();
  107. for(size_t i = 0; i < lines.size(); i++)
  108. {
  109. for(UINT32 j = 0; j < numPages; j++)
  110. {
  111. UINT32 writtenQuads = lines[i].fillBuffer(j, vertices, uv, indices, quadOffset, bufferSizeQuads);
  112. Int2 position = offset + alignmentOffsets[i];
  113. UINT32 numVertices = writtenQuads * 4;
  114. for(UINT32 i = 0; i < numVertices; i++)
  115. {
  116. vertices[quadOffset * 4 + i].x += (float)position.x;
  117. vertices[quadOffset * 4 + i].y += (float)position.y;
  118. }
  119. quadOffset += writtenQuads;
  120. }
  121. }
  122. return quadOffset;
  123. }
  124. Vector<Int2>::type TextSprite::getAlignmentOffsets(const Vector<TextUtility::TextLine>::type& lines,
  125. UINT32 width, UINT32 height, TextHorzAlign horzAlign, TextVertAlign vertAlign)
  126. {
  127. UINT32 curHeight = 0;
  128. for(auto& line : lines)
  129. curHeight += line.getYOffset();
  130. // Calc vertical alignment offset
  131. UINT32 vertDiff = std::max(0U, height - curHeight);
  132. UINT32 vertOffset = 0;
  133. switch(vertAlign)
  134. {
  135. case TVA_Top:
  136. vertOffset = 0;
  137. break;
  138. case TVA_Bottom:
  139. vertOffset = std::max(0, (INT32)vertDiff);
  140. break;
  141. case TVA_Center:
  142. vertOffset = std::max(0, (INT32)vertDiff) / 2;
  143. break;
  144. }
  145. // Calc horizontal alignment offset
  146. UINT32 curY = 0;
  147. Vector<Int2>::type lineOffsets;
  148. for(size_t i = 0; i < lines.size(); i++)
  149. {
  150. UINT32 horzOffset = 0;
  151. switch(horzAlign)
  152. {
  153. case THA_Left:
  154. horzOffset = 0;
  155. break;
  156. case THA_Right:
  157. horzOffset = std::max(0, (INT32)(width - lines[i].getWidth()));
  158. break;
  159. case THA_Center:
  160. horzOffset = std::max(0, (INT32)(width - lines[i].getWidth())) / 2;
  161. break;
  162. }
  163. lineOffsets.push_back(Int2(horzOffset, vertOffset + curY));
  164. curY += lines[i].getYOffset();
  165. }
  166. return lineOffsets;
  167. }
  168. }