BsTextData.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #pragma once
  5. #include "BsCorePrerequisites.h"
  6. #include "BsFontDesc.h"
  7. #include "BsVector2I.h"
  8. namespace BansheeEngine
  9. {
  10. /**
  11. * @brief This object takes as input a string, a font and optionally some constraints (like word wrap)
  12. * and outputs a set of character data you may use for rendering or metrics.
  13. */
  14. class TextData
  15. {
  16. private:
  17. /**
  18. * @brief Represents a single word as a set of characters, or optionally just a blank space
  19. * of a certain length.
  20. *
  21. * @note Due to the way allocation is handled, this class is not allowed to have a destructor.
  22. */
  23. class TextWord
  24. {
  25. public:
  26. /**
  27. * @brief Initializes the word and signals if it just a space (or multiple spaces), or
  28. * an actual word with letters.
  29. */
  30. void init(bool spacer);
  31. /**
  32. * @brief Appends a new character to the word.
  33. *
  34. * @param charIdx Sequential index of the character in the original string.
  35. * @param desc Character description from the font.
  36. *
  37. * @returns How many pixels did the added character expand the word by.
  38. */
  39. UINT32 addChar(UINT32 charIdx, const CHAR_DESC& desc);
  40. /**
  41. * @brief Adds a space to the word. Word must have previously have been declared as
  42. * a "spacer".
  43. */
  44. void addSpace(UINT32 spaceWidth);
  45. /**
  46. * @brief Returns the width of the word in pixels.
  47. */
  48. UINT32 getWidth() const { return mWidth; }
  49. /**
  50. * @brief Returns height of the word in pixels.
  51. */
  52. UINT32 getHeight() const { return mHeight; }
  53. /**
  54. * @brief Returns true if word is a spacer. Spacers contain just a space
  55. * of a certain length with no actual characters.
  56. */
  57. bool isSpacer() const { return mSpacer; }
  58. /**
  59. * @brief Returns the number of characters in the word.
  60. */
  61. UINT32 getNumChars() const { return mLastChar == nullptr ? 0 : (mCharsEnd - mCharsStart + 1); }
  62. /**
  63. * @brief Returns the index of the starting character in the word.
  64. */
  65. UINT32 getCharsStart() const { return mCharsStart; }
  66. /**
  67. * @brief Returns the index of the last character in the word.
  68. */
  69. UINT32 getCharsEnd() const { return mCharsEnd; }
  70. private:
  71. UINT32 mCharsStart, mCharsEnd;
  72. UINT32 mWidth;
  73. UINT32 mHeight;
  74. const CHAR_DESC* mLastChar;
  75. bool mSpacer;
  76. UINT32 mSpaceWidth;
  77. };
  78. /**
  79. * @brief Contains information about a single texture page that contains rendered
  80. * character data.
  81. *
  82. * @note Due to the way allocation is handled, this class is not allowed to have a destructor.
  83. */
  84. struct PageInfo
  85. {
  86. UINT32 numQuads;
  87. HTexture texture;
  88. };
  89. public:
  90. /**
  91. * @brief Represents a single line as a set of words.
  92. *
  93. * @note Due to the way allocation is handled, this class is not allowed to have a destructor.
  94. */
  95. class BS_CORE_EXPORT TextLine
  96. {
  97. public:
  98. /**
  99. * @brief Returns width of the line in pixels.
  100. */
  101. UINT32 getWidth() const { return mWidth; }
  102. /**
  103. * @brief Returns height of the line in pixels.
  104. */
  105. UINT32 getHeight() const { return mHeight; }
  106. /**
  107. * @brief Returns an offset used to separate two lines.
  108. */
  109. UINT32 getYOffset() const { return mTextData->getLineHeight(); }
  110. /**
  111. * @brief Fills the vertex/uv/index buffers for the specified page, with all the character data
  112. * needed for rendering.
  113. *
  114. * @param page The page.
  115. * @param [out] vertices Pre-allocated array where character vertices will be written.
  116. * @param [out] uvs Pre-allocated array where character uv coordinates will be written.
  117. * @param [out] indexes Pre-allocated array where character indices will be written.
  118. * @param offset Offsets the location at which the method writes to the buffers.
  119. * Counted as number of quads.
  120. * @param size Total number of quads that can fit into the specified buffers.
  121. *
  122. * @return Number of quads that were written.
  123. */
  124. UINT32 fillBuffer(UINT32 page, Vector2* vertices, Vector2* uvs, UINT32* indexes, UINT32 offset, UINT32 size) const;
  125. /**
  126. * @brief Returns the total number of characters on this line.
  127. */
  128. UINT32 getNumChars() const;
  129. /**
  130. * @brief Query if this line was created explicitly due to a newline character.
  131. * As opposed to a line that was created because a word couldn't fit on the previous line.
  132. */
  133. bool hasNewlineChar() const { return mHasNewline; }
  134. private:
  135. friend class TextData;
  136. /**
  137. * @brief Appends a new character to the line.
  138. *
  139. * @param charIdx Sequential index of the character in the original string.
  140. * @param desc Character description from the font.
  141. */
  142. void add(UINT32 charIdx, const CHAR_DESC& charDesc);
  143. /**
  144. * @brief Appends a space to the line.
  145. */
  146. void addSpace();
  147. /**
  148. * @brief Adds a new word to the line.
  149. *
  150. * @param wordIdx Sequential index of the word in the original string.
  151. * Spaces are counted as words as well.
  152. * @param word Description of the word.
  153. */
  154. void addWord(UINT32 wordIdx, const TextWord& word);
  155. /**
  156. * @brief Initializes the line. Must be called after construction.
  157. */
  158. void init(TextData* textData);
  159. /**
  160. * @brief Finalizes the line. Do not add new characters/words after a line has
  161. * been finalized.
  162. *
  163. * @param hasNewlineChar Set to true if line was create due to an explicit newline char.
  164. * As opposed to a line that was created because a word couldn't fit
  165. * on the previous line.
  166. */
  167. void finalize(bool hasNewlineChar);
  168. /**
  169. * @brief Returns true if the line contains no words.
  170. */
  171. bool isEmpty() const { return mIsEmpty; }
  172. /**
  173. * @brief Removes last word from the line and returns its sequential index.
  174. */
  175. UINT32 removeLastWord();
  176. /**
  177. * @brief Calculates the line width and height in pixels.
  178. */
  179. void calculateBounds();
  180. private:
  181. TextData* mTextData;
  182. UINT32 mWordsStart, mWordsEnd;
  183. UINT32 mWidth;
  184. UINT32 mHeight;
  185. bool mIsEmpty;
  186. bool mHasNewline;
  187. };
  188. public:
  189. /**
  190. * @brief Initializes a new text data using the specified string and font. Text will attempt to fit into
  191. * the provided area. It will wrap words to new line if it doesn't fit and is enabled. If word wrap
  192. * isn't possible the text will be clipped. If the specified area is zero size then the text
  193. * will not be clipped or word wrapped in any way.
  194. *
  195. * After this object is constructed you may call various getter methods to get needed information.
  196. */
  197. BS_CORE_EXPORT TextData(const WString& text, const HFont& font, UINT32 fontSize, UINT32 width = 0, UINT32 height = 0, bool wordWrap = false);
  198. BS_CORE_EXPORT ~TextData();
  199. /**
  200. * @brief Returns the number of lines that were generated.
  201. */
  202. BS_CORE_EXPORT UINT32 getNumLines() const { return mNumLines; }
  203. /**
  204. * @brief Returns the number of font pages references by the used characters.
  205. */
  206. BS_CORE_EXPORT UINT32 getNumPages() const { return mNumPageInfos; }
  207. /**
  208. * @brief Returns the height of a line in pixels.
  209. */
  210. BS_CORE_EXPORT UINT32 getLineHeight() const;
  211. /**
  212. * @brief Gets information describing a single line at the specified index.
  213. */
  214. BS_CORE_EXPORT const TextLine& getLine(UINT32 idx) const { return mLines[idx]; }
  215. /**
  216. * @brief Returns font texture for the provided page index.
  217. */
  218. BS_CORE_EXPORT const HTexture& getTextureForPage(UINT32 page) const;
  219. /**
  220. * @brief Returns the number of quads used by all the characters in the provided page.
  221. */
  222. BS_CORE_EXPORT UINT32 getNumQuadsForPage(UINT32 page) const { return mPageInfos[page].numQuads; }
  223. /**
  224. * @brief Returns the width of the actual text in pixels.
  225. */
  226. BS_CORE_EXPORT UINT32 getWidth() const;
  227. /**
  228. * @brief Returns the height of the actual text in pixels.
  229. */
  230. BS_CORE_EXPORT UINT32 getHeight() const;
  231. private:
  232. friend class TextLine;
  233. /**
  234. * @brief Returns Y offset that determines the line on which the characters are placed.
  235. * In pixels.
  236. */
  237. INT32 getBaselineOffset() const;
  238. /**
  239. * @brief Returns the width of a single space in pixels.
  240. */
  241. UINT32 getSpaceWidth() const;
  242. /**
  243. * @brief Gets a description of a single character referenced by its sequential index
  244. * based on the original string.
  245. */
  246. const CHAR_DESC& getChar(UINT32 idx) const { return *mChars[idx]; }
  247. /**
  248. * @brief Gets a description of a single word referenced by its sequential index
  249. * based on the original string.
  250. */
  251. const TextWord& getWord(UINT32 idx) const { return mWords[idx]; }
  252. private:
  253. const CHAR_DESC** mChars;
  254. UINT32 mNumChars;
  255. TextWord* mWords;
  256. UINT32 mNumWords;
  257. TextLine* mLines;
  258. UINT32 mNumLines;
  259. PageInfo* mPageInfos;
  260. UINT32 mNumPageInfos;
  261. void* mData;
  262. HFont mFont;
  263. const FontData* mFontData;
  264. // Static buffers used to reduce runtime memory allocation
  265. private:
  266. static BS_THREADLOCAL bool BuffersInitialized;
  267. static BS_THREADLOCAL TextWord* WordBuffer;
  268. static BS_THREADLOCAL UINT32 WordBufferSize;
  269. static BS_THREADLOCAL UINT32 NextFreeWord;
  270. static BS_THREADLOCAL TextLine* LineBuffer;
  271. static BS_THREADLOCAL UINT32 LineBufferSize;
  272. static BS_THREADLOCAL UINT32 NextFreeLine;
  273. static BS_THREADLOCAL PageInfo* PageBuffer;
  274. static BS_THREADLOCAL UINT32 PageBufferSize;
  275. static BS_THREADLOCAL UINT32 NextFreePageInfo;
  276. /**
  277. * @brief Allocates an initial set of buffers that will be reused while parsing
  278. * text data.
  279. */
  280. static void initAlloc();
  281. /**
  282. * @brief Allocates a new word and adds it to the buffer. Returns index of the word
  283. * in the word buffer.
  284. *
  285. * @param spacer Specify true if the word is only to contain spaces. (Spaces are considered
  286. * a special type of word).
  287. */
  288. static UINT32 allocWord(bool spacer);
  289. /**
  290. * @brief Allocates a new line and adds it to the buffer. Returns index of the line
  291. * in the line buffer.
  292. */
  293. static UINT32 allocLine(TextData* textData);
  294. /**
  295. * @brief Resets all allocation counters.
  296. */
  297. static void deallocAll();
  298. /**
  299. * @brief Increments the count of characters for the referenced page, and optionally
  300. * creates page info if it doesn't already exist.
  301. */
  302. static void addCharToPage(UINT32 page, const FontData& fontData);
  303. };
  304. }