Text3DFont.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. //
  2. // Copyright (c) 2008-2017 the Urho3D project.
  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 deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // 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 FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../../Precompiled.h"
  23. #include "../../Core/Context.h"
  24. #include "../../Core/Profiler.h"
  25. #include "../Graphics.h"
  26. #include "../../IO/Deserializer.h"
  27. #include "../../IO/FileSystem.h"
  28. #include "Text3DFont.h"
  29. #include "Text3DBitmap.h"
  30. #include "Text3DFreeType.h"
  31. #include "../../Resource/ResourceCache.h"
  32. #include "../../Resource/XMLElement.h"
  33. #include "../../Resource/XMLFile.h"
  34. #include "../../DebugNew.h"
  35. namespace Atomic
  36. {
  37. namespace
  38. {
  39. /// Convert float to 26.6 fixed-point (as used internally by FreeType)
  40. inline int FloatToFixed(float value)
  41. {
  42. return (int)(value * 64);
  43. }
  44. }
  45. static const float MIN_POINT_SIZE = 1;
  46. static const float MAX_POINT_SIZE = 96;
  47. Text3DFont::Text3DFont(Context* context) :
  48. Resource(context),
  49. fontDataSize_(0),
  50. absoluteOffset_(IntVector2::ZERO),
  51. scaledOffset_(Vector2::ZERO),
  52. fontType_(FONT_NONE),
  53. sdfFont_(false)
  54. {
  55. }
  56. Text3DFont::~Text3DFont()
  57. {
  58. // To ensure FreeType deallocates properly, first clear all faces, then release the raw font data
  59. ReleaseFaces();
  60. fontData_.Reset();
  61. }
  62. void Text3DFont::RegisterObject(Context* context)
  63. {
  64. context->RegisterFactory<Text3DFont>();
  65. }
  66. bool Text3DFont::BeginLoad(Deserializer& source)
  67. {
  68. // In headless mode, do not actually load, just return success
  69. Graphics* graphics = GetSubsystem<Graphics>();
  70. if (!graphics)
  71. return true;
  72. fontType_ = FONT_NONE;
  73. faces_.Clear();
  74. fontDataSize_ = source.GetSize();
  75. if (fontDataSize_)
  76. {
  77. fontData_ = new unsigned char[fontDataSize_];
  78. if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_)
  79. return false;
  80. }
  81. else
  82. {
  83. fontData_.Reset();
  84. return false;
  85. }
  86. String ext = GetExtension(GetName());
  87. if (ext == ".ttf" || ext == ".otf" || ext == ".woff")
  88. {
  89. fontType_ = FONT_FREETYPE;
  90. LoadParameters();
  91. }
  92. else if (ext == ".xml" || ext == ".fnt" || ext == ".sdf")
  93. fontType_ = FONT_BITMAP;
  94. sdfFont_ = ext == ".sdf";
  95. SetMemoryUse(fontDataSize_);
  96. return true;
  97. }
  98. bool Text3DFont::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs, const String& indentation)
  99. {
  100. Text3DFontFace* fontFace = GetFace(pointSize);
  101. if (!fontFace)
  102. return false;
  103. ATOMIC_PROFILE(FontSaveXML);
  104. SharedPtr<Text3DBitmap> packedFontFace(new Text3DBitmap(this));
  105. if (!packedFontFace->Load(fontFace, usedGlyphs))
  106. return false;
  107. return packedFontFace->Save(dest, pointSize, indentation);
  108. }
  109. void Text3DFont::SetAbsoluteGlyphOffset(const IntVector2& offset)
  110. {
  111. absoluteOffset_ = offset;
  112. }
  113. void Text3DFont::SetScaledGlyphOffset(const Vector2& offset)
  114. {
  115. scaledOffset_ = offset;
  116. }
  117. Text3DFontFace* Text3DFont::GetFace(float pointSize)
  118. {
  119. // In headless mode, always return null
  120. Graphics* graphics = GetSubsystem<Graphics>();
  121. if (!graphics)
  122. return 0;
  123. // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
  124. if (fontType_ == FONT_BITMAP)
  125. pointSize = 0;
  126. else
  127. pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
  128. // For outline fonts, we return the nearest size in 1/64th increments, as that's what FreeType supports.
  129. int key = FloatToFixed(pointSize);
  130. HashMap<int, SharedPtr<Text3DFontFace> >::Iterator i = faces_.Find(key);
  131. if (i != faces_.End())
  132. {
  133. if (!i->second_->IsDataLost())
  134. return i->second_;
  135. else
  136. {
  137. // Erase and reload face if texture data lost (OpenGL mode only)
  138. faces_.Erase(i);
  139. }
  140. }
  141. ATOMIC_PROFILE(GetFontFace);
  142. switch (fontType_)
  143. {
  144. case FONT_FREETYPE:
  145. return GetFaceFreeType(pointSize);
  146. case FONT_BITMAP:
  147. return GetFaceBitmap(pointSize);
  148. default:
  149. return 0;
  150. }
  151. }
  152. IntVector2 Text3DFont::GetTotalGlyphOffset(float pointSize) const
  153. {
  154. Vector2 multipliedOffset = pointSize * scaledOffset_;
  155. return absoluteOffset_ + IntVector2((int)(multipliedOffset.x_ + 0.5f), (int)(multipliedOffset.y_ + 0.5f));
  156. }
  157. void Text3DFont::ReleaseFaces()
  158. {
  159. faces_.Clear();
  160. }
  161. void Text3DFont::LoadParameters()
  162. {
  163. ResourceCache* cache = GetSubsystem<ResourceCache>();
  164. String xmlName = ReplaceExtension(GetName(), ".xml");
  165. SharedPtr<XMLFile> xml = cache->GetTempResource<XMLFile>(xmlName, false);
  166. if (!xml)
  167. return;
  168. XMLElement rootElem = xml->GetRoot();
  169. XMLElement absoluteElem = rootElem.GetChild("absoluteoffset");
  170. if (!absoluteElem)
  171. absoluteElem = rootElem.GetChild("absolute");
  172. if (absoluteElem)
  173. {
  174. absoluteOffset_.x_ = absoluteElem.GetInt("x");
  175. absoluteOffset_.y_ = absoluteElem.GetInt("y");
  176. }
  177. XMLElement scaledElem = rootElem.GetChild("scaledoffset");
  178. if (!scaledElem)
  179. scaledElem = rootElem.GetChild("scaled");
  180. if (scaledElem)
  181. {
  182. scaledOffset_.x_ = scaledElem.GetFloat("x");
  183. scaledOffset_.y_ = scaledElem.GetFloat("y");
  184. }
  185. }
  186. Text3DFontFace* Text3DFont::GetFaceFreeType(float pointSize)
  187. {
  188. SharedPtr<Text3DFontFace> newFace(new Text3DFreeType(this));
  189. if (!newFace->Load(&fontData_[0], fontDataSize_, pointSize))
  190. return 0;
  191. int key = FloatToFixed(pointSize);
  192. faces_[key] = newFace;
  193. return newFace;
  194. }
  195. Text3DFontFace* Text3DFont::GetFaceBitmap(float pointSize)
  196. {
  197. SharedPtr<Text3DFontFace> newFace(new Text3DBitmap(this));
  198. if (!newFace->Load(&fontData_[0], fontDataSize_, pointSize))
  199. return 0;
  200. int key = FloatToFixed(pointSize);
  201. faces_[key] = newFace;
  202. return newFace;
  203. }
  204. }