gfxFontRenderBatcher.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "gfx/gfxFontRenderBatcher.h"
  23. #include "gfx/gFont.h"
  24. FontRenderBatcher::FontRenderBatcher() : mStorage(8096)
  25. {
  26. mFont = NULL;
  27. mLength = 0;
  28. if (!mFontSB)
  29. {
  30. GFXStateBlockDesc f;
  31. f.zDefined = true;
  32. f.zEnable = false;
  33. f.zWriteEnable = false;
  34. f.cullDefined = true;
  35. f.cullMode = GFXCullNone;
  36. f.blendDefined = true;
  37. f.blendEnable = true;
  38. f.blendSrc = GFXBlendSrcAlpha;
  39. f.blendDest = GFXBlendInvSrcAlpha;
  40. f.samplersDefined = true;
  41. f.samplers[0].magFilter = GFXTextureFilterPoint;
  42. f.samplers[0].minFilter = GFXTextureFilterPoint;
  43. f.samplers[0].addressModeU = GFXAddressClamp;
  44. f.samplers[0].addressModeV = GFXAddressClamp;
  45. f.setColorWrites(true, true, true, false); // NOTE: comment this out if alpha write is needed
  46. mFontSB = GFX->createStateBlock(f);
  47. }
  48. }
  49. void FontRenderBatcher::render( F32 rot, const Point2F &offset )
  50. {
  51. if( mLength == 0 )
  52. return;
  53. GFX->setStateBlock(mFontSB);
  54. for(U32 i = 0; i < GFX->getNumSamplers(); i++)
  55. GFX->setTexture(i, NULL);
  56. MatrixF rotMatrix;
  57. bool doRotation = rot != 0.f;
  58. if(doRotation)
  59. rotMatrix.set( EulerF( 0.0, 0.0, mDegToRad( rot ) ) );
  60. // Write verts out.
  61. U32 currentPt = 0;
  62. GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile);
  63. verts.lock();
  64. for( S32 i = 0; i < mSheets.size(); i++ )
  65. {
  66. // Do some early outs...
  67. if(!mSheets[i])
  68. continue;
  69. if(!mSheets[i]->numChars)
  70. continue;
  71. mSheets[i]->startVertex = currentPt;
  72. const GFXTextureObject *tex = mFont->getTextureHandle(i);
  73. for( S32 j = 0; j < mSheets[i]->numChars; j++ )
  74. {
  75. // Get some general info to proceed with...
  76. const CharMarker &m = mSheets[i]->charIndex[j];
  77. const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c );
  78. // Where are we drawing it?
  79. F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG;
  80. F32 drawX = offset.x + m.x + ci.xOrigin;
  81. // Figure some values.
  82. const F32 texWidth = (F32)tex->getWidth();
  83. const F32 texHeight = (F32)tex->getHeight();
  84. const F32 texLeft = (F32)(ci.xOffset) / texWidth;
  85. const F32 texRight = (F32)(ci.xOffset + ci.width) / texWidth;
  86. const F32 texTop = (F32)(ci.yOffset) / texHeight;
  87. const F32 texBottom = (F32)(ci.yOffset + ci.height) / texHeight;
  88. const F32 fillConventionOffset = GFX->getFillConventionOffset();
  89. const F32 screenLeft = drawX - fillConventionOffset;
  90. const F32 screenRight = drawX - fillConventionOffset + ci.width * TEXT_MAG;
  91. const F32 screenTop = drawY - fillConventionOffset;
  92. const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG;
  93. // Build our vertices. We NEVER read back from the buffer, that's
  94. // incredibly slow, so for rotation do it into tmp. This code is
  95. // ugly as sin.
  96. Point3F tmp;
  97. tmp.set( screenLeft, screenTop, 0.f );
  98. if(doRotation)
  99. rotMatrix.mulP( tmp, &verts[currentPt].point);
  100. else
  101. verts[currentPt].point = tmp;
  102. verts[currentPt].color = m.color;
  103. verts[currentPt].texCoord.set( texLeft, texTop );
  104. currentPt++;
  105. tmp.set( screenLeft, screenBottom, 0.f );
  106. if(doRotation)
  107. rotMatrix.mulP( tmp, &verts[currentPt].point);
  108. else
  109. verts[currentPt].point = tmp;
  110. verts[currentPt].color = m.color;
  111. verts[currentPt].texCoord.set( texLeft, texBottom );
  112. currentPt++;
  113. tmp.set( screenRight, screenBottom, 0.f );
  114. if(doRotation)
  115. rotMatrix.mulP( tmp, &verts[currentPt].point);
  116. else
  117. verts[currentPt].point = tmp;
  118. verts[currentPt].color = m.color;
  119. verts[currentPt].texCoord.set( texRight, texBottom );
  120. currentPt++;
  121. tmp.set( screenRight, screenBottom, 0.f );
  122. if(doRotation)
  123. rotMatrix.mulP( tmp, &verts[currentPt].point);
  124. else
  125. verts[currentPt].point = tmp;
  126. verts[currentPt].color = m.color;
  127. verts[currentPt].texCoord.set( texRight, texBottom );
  128. currentPt++;
  129. tmp.set( screenRight, screenTop, 0.f );
  130. if(doRotation)
  131. rotMatrix.mulP( tmp, &verts[currentPt].point);
  132. else
  133. verts[currentPt].point = tmp;
  134. verts[currentPt].color = m.color;
  135. verts[currentPt].texCoord.set( texRight, texTop );
  136. currentPt++;
  137. tmp.set( screenLeft, screenTop, 0.f );
  138. if(doRotation)
  139. rotMatrix.mulP( tmp, &verts[currentPt].point);
  140. else
  141. verts[currentPt].point = tmp;
  142. verts[currentPt].color = m.color;
  143. verts[currentPt].texCoord.set( texLeft, texTop );
  144. currentPt++;
  145. }
  146. }
  147. verts->unlock();
  148. AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!");
  149. GFX->setVertexBuffer(verts);
  150. GFX->setupGenericShaders( GFXDevice::GSAddColorTexture );
  151. // Now do an optimal render!
  152. for( S32 i = 0; i < mSheets.size(); i++ )
  153. {
  154. if(!mSheets[i])
  155. continue;
  156. if(!mSheets[i]->numChars )
  157. continue;
  158. GFX->setTexture( 0, mFont->getTextureHandle(i) );
  159. GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2);
  160. }
  161. }
  162. void FontRenderBatcher::queueChar( UTF16 c, S32 &currentX, GFXVertexColor &currentColor )
  163. {
  164. const PlatformFont::CharInfo &ci = mFont->getCharInfo( c );
  165. U32 sidx = ci.bitmapIndex;
  166. if( ci.width != 0 && ci.height != 0 )
  167. {
  168. SheetMarker &sm = getSheetMarker(sidx);
  169. CharMarker &m = sm.charIndex[sm.numChars];
  170. sm.numChars++;
  171. m.c = c;
  172. m.x = (F32)currentX;
  173. m.color = currentColor;
  174. }
  175. currentX += ci.xIncrement;
  176. }
  177. FontRenderBatcher::SheetMarker & FontRenderBatcher::getSheetMarker( U32 sheetID )
  178. {
  179. // Add empty sheets up to and including the requested sheet if necessary
  180. if (mSheets.size() <= sheetID)
  181. {
  182. S32 oldSize = mSheets.size();
  183. mSheets.setSize( sheetID + 1 );
  184. for ( S32 i = oldSize; i < mSheets.size(); i++ )
  185. mSheets[i] = NULL;
  186. }
  187. // Allocate if it doesn't exist...
  188. if (!mSheets[sheetID])
  189. {
  190. S32 size = sizeof( SheetMarker) + mLength * sizeof( CharMarker );
  191. mSheets[sheetID] = (SheetMarker *)mStorage.alloc(size);
  192. mSheets[sheetID]->numChars = 0;
  193. mSheets[sheetID]->startVertex = 0; // cosmetic initialization
  194. }
  195. return *mSheets[sheetID];
  196. }
  197. void FontRenderBatcher::init( GFont *font, U32 n )
  198. {
  199. // Clear out batched results
  200. dMemset(mSheets.address(), 0, mSheets.memSize());
  201. mSheets.clear();
  202. mStorage.freeBlocks(true);
  203. mFont = font;
  204. mLength = n;
  205. }