UiTextArea.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #include <OgreFontManager.h>
  2. #include <OgreHardwareBufferManager.h>
  3. #include <OgreMaterialManager.h>
  4. #include "core/Logger.h"
  5. #include "core/UiManager.h"
  6. #include "core/UiTextArea.h"
  7. UiTextArea::UiTextArea(const Ogre::String& name):
  8. UiWidget(name)
  9. {
  10. Initialise();
  11. }
  12. UiTextArea::UiTextArea(const Ogre::String& name, const Ogre::String& path_name, UiWidget* parent):
  13. UiWidget(name, path_name, parent)
  14. {
  15. Initialise();
  16. }
  17. UiTextArea::~UiTextArea()
  18. {
  19. DestroyVertexBuffer();
  20. }
  21. void
  22. UiTextArea::Initialise()
  23. {
  24. m_Font = nullptr;
  25. m_MaxLetters = 0;
  26. m_TextAlign = UiTextArea::LEFT;
  27. m_Text = "";
  28. m_TextNode = nullptr;
  29. m_SceneManager = Ogre::Root::getSingleton().getSceneManager("Scene");
  30. m_RenderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem();
  31. CreateVertexBuffer();
  32. }
  33. void
  34. UiTextArea::Update()
  35. {
  36. UiWidget::Update();
  37. }
  38. void
  39. UiTextArea::Render()
  40. {
  41. if(m_Visible == true)
  42. {
  43. if(m_RenderOp.vertexData->vertexCount != 0)
  44. {
  45. m_RenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY);
  46. m_RenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY);
  47. m_RenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY);
  48. m_SceneManager->_setPass(m_Material->getTechnique(0)->getPass(0), true, false);
  49. m_RenderSystem->setScissorTest(true, m_ScissorLeft, m_ScissorTop, m_ScissorRight, m_ScissorBottom);
  50. m_RenderSystem->_render(m_RenderOp);
  51. m_RenderSystem->setScissorTest(false);
  52. }
  53. }
  54. UiWidget::Render();
  55. }
  56. void
  57. UiTextArea::UpdateTransformation()
  58. {
  59. UiWidget::UpdateTransformation();
  60. UpdateGeometry();
  61. }
  62. void
  63. UiTextArea::SetTextAlign(const TextAlign align)
  64. {
  65. m_TextAlign = align;
  66. }
  67. void
  68. UiTextArea::SetText(const Ogre::UTFString& text)
  69. {
  70. m_Text = text;
  71. }
  72. void
  73. UiTextArea::SetText(TiXmlNode* text)
  74. {
  75. m_TextNode = text;
  76. }
  77. void
  78. UiTextArea::SetFont(const Ogre::String& font)
  79. {
  80. m_Font = UiManager::getSingleton().GetFont(font);
  81. if(m_Font == nullptr)
  82. {
  83. LOG_ERROR("Could not find font \"" + font + "\" for \"" + m_PathName + "\".");
  84. return;
  85. }
  86. m_Material = Ogre::MaterialManager::getSingleton().create("UiMaterials." + m_PathName, "General");
  87. Ogre::Pass* pass = m_Material->getTechnique(0)->getPass(0);
  88. pass->setVertexColourTracking(Ogre::TVC_AMBIENT);
  89. pass->setCullingMode(Ogre::CULL_NONE);
  90. pass->setDepthCheckEnabled(false);
  91. pass->setDepthWriteEnabled(false);
  92. pass->setLightingEnabled(false);
  93. pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
  94. pass->setAlphaRejectFunction(Ogre::CMPF_GREATER);
  95. pass->setAlphaRejectValue(0);
  96. Ogre::TextureUnitState* tex = pass->createTextureUnitState();
  97. tex->setTextureName(m_Font->GetImageName());
  98. tex->setNumMipmaps(-1);
  99. tex->setTextureFiltering(Ogre::TFO_NONE);
  100. }
  101. void
  102. UiTextArea::UpdateGeometry()
  103. {
  104. if(m_Font == nullptr)
  105. {
  106. LOG_ERROR("Font for \"" + m_PathName + "\" if not set.");
  107. return;
  108. }
  109. if(m_Text.size() > m_MaxLetters)
  110. {
  111. LOG_ERROR("Max number of text reached in \"" + m_PathName + "\". Can't render text \"" + m_Text + "\". Max number of letters is " + Ogre::StringConverter::toString(m_MaxLetters) + ".");
  112. return;
  113. }
  114. float length = 0;
  115. if(m_TextAlign != LEFT)
  116. {
  117. if(m_TextNode != nullptr)
  118. {
  119. length = GetTextLengthFromNode(m_TextNode);
  120. }
  121. else
  122. {
  123. length = GetTextLength(m_Text);
  124. }
  125. if(m_TextAlign == CENTER)
  126. {
  127. length /= 2;
  128. }
  129. }
  130. TextBlockData data;
  131. data.local_x1 = -m_FinalOrigin.x - length;
  132. data.local_y1 = -m_FinalOrigin.y;
  133. data.position = 0;
  134. TextStyle style;
  135. style.colour = m_Colour1;
  136. if(m_TextNode != nullptr)
  137. {
  138. SetTextGeometryFromNode(m_TextNode, data, style);
  139. }
  140. else
  141. {
  142. SetTextGeometry(m_Text, data, style);
  143. }
  144. }
  145. float
  146. UiTextArea::GetTextLengthFromNode(TiXmlNode* node) const
  147. {
  148. float length = 0;
  149. while(node != nullptr)
  150. {
  151. switch(node->Type())
  152. {
  153. case TiXmlNode::TINYXML_TEXT:
  154. {
  155. TiXmlText* childText = node->ToText();
  156. if(childText)
  157. {
  158. length += GetTextLength(childText->Value());
  159. }
  160. }
  161. break;
  162. case TiXmlNode::TINYXML_ELEMENT:
  163. {
  164. length +=GetTextLengthFromNode(node->FirstChild());
  165. }
  166. break;
  167. }
  168. node = node->NextSibling();
  169. }
  170. return length;
  171. }
  172. float
  173. UiTextArea::GetTextLength(const Ogre::UTFString& text) const
  174. {
  175. float length = 0;
  176. for(size_t i = 0; i < text.size(); ++i)
  177. {
  178. UiCharData char_data = m_Font->GetCharData(text[i]);
  179. length += (char_data.pre + char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f;
  180. }
  181. return length;
  182. }
  183. void
  184. UiTextArea::SetTextGeometryFromNode(TiXmlNode* node, TextBlockData& data, const TextStyle& style)
  185. {
  186. while(node != nullptr)
  187. {
  188. switch(node->Type())
  189. {
  190. case TiXmlNode::TINYXML_TEXT:
  191. {
  192. TiXmlText* childText = node->ToText();
  193. if(childText)
  194. {
  195. SetTextGeometry(childText->Value(), data, style);
  196. }
  197. }
  198. break;
  199. case TiXmlNode::TINYXML_ELEMENT:
  200. {
  201. TextStyle style_child;
  202. style_child.colour = style.colour;
  203. Ogre::String name = node->ValueStr();
  204. if(name == "colour")
  205. {
  206. style_child.colour = Ogre::StringConverter::parseColourValue(node->ToElement()->Attribute("value"));
  207. }
  208. TiXmlNode* node_child = node->FirstChild();
  209. SetTextGeometryFromNode(node_child, data, style_child);
  210. }
  211. break;
  212. }
  213. node = node->NextSibling();
  214. }
  215. }
  216. void
  217. UiTextArea::SetTextGeometry(const Ogre::UTFString& text, TextBlockData& data, const TextStyle& style)
  218. {
  219. float* writeIterator = (float*) m_VertexBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
  220. writeIterator += data.position * 9 * 6;
  221. m_RenderOp.vertexData->vertexCount = data.position * 6;
  222. float local_x1 = data.local_x1;
  223. float local_y1 = data.local_y1;
  224. float x = m_FinalTranslate.x;
  225. float y = m_FinalTranslate.y;
  226. for(auto &c : text)
  227. {
  228. UiCharData char_data = m_Font->GetCharData(c);
  229. local_x1 += char_data.pre * m_FinalScale.x * m_ScreenHeight / 720.0f;
  230. float local_x2 = local_x1 + char_data.width * m_FinalScale.x * m_ScreenHeight / 720.0f;
  231. float local_y2 = local_y1 + char_data.height * m_FinalScale.y * m_ScreenHeight / 720.0f;
  232. int x1, y1, x2, y2, x3, y3, x4, y4;
  233. if(m_FinalRotation != 0)
  234. {
  235. float cos = Ogre::Math::Cos(Ogre::Radian(Ogre::Degree(m_FinalRotation)));
  236. float sin = Ogre::Math::Sin(Ogre::Radian(Ogre::Degree(m_FinalRotation)));
  237. x1 = static_cast<int>(local_x1 * cos - local_y1 * sin + x);
  238. y1 = static_cast<int>(local_x1 * sin + local_y1 * cos + y);
  239. x2 = static_cast<int>(local_x2 * cos - local_y1 * sin + x);
  240. y2 = static_cast<int>(local_x2 * sin + local_y1 * cos + y);
  241. x3 = static_cast<int>(local_x2 * cos - local_y2 * sin + x);
  242. y3 = static_cast<int>(local_x2 * sin + local_y2 * cos + y);
  243. x4 = static_cast<int>(local_x1 * cos - local_y2 * sin + x);
  244. y4 = static_cast<int>(local_x1 * sin + local_y2 * cos + y);
  245. }
  246. else
  247. {
  248. x1 = static_cast<int>(local_x1 + x);
  249. y1 = static_cast<int>(local_y1 + y);
  250. x2 = static_cast<int>(local_x2 + x);
  251. y2 = static_cast<int>(local_y1 + y);
  252. x3 = static_cast<int>(local_x2 + x);
  253. y3 = static_cast<int>(local_y2 + y);
  254. x4 = static_cast<int>(local_x1 + x);
  255. y4 = static_cast<int>(local_y2 + y);
  256. }
  257. local_x1 += (char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f;
  258. float width = static_cast<float>(m_Font->GetImageWidth());
  259. float height = static_cast<float>(m_Font->GetImageHeight());
  260. Ogre::Vector3 coords[4] = {
  261. Ogre::Vector3((x1 / m_ScreenWidth) * 2 - 1, -((y1 / m_ScreenHeight) * 2 - 1), m_FinalZ),
  262. Ogre::Vector3((x2 / m_ScreenWidth) * 2 - 1, -((y2 / m_ScreenHeight) * 2 - 1), m_FinalZ),
  263. Ogre::Vector3((x3 / m_ScreenWidth) * 2 - 1, -((y3 / m_ScreenHeight) * 2 - 1), m_FinalZ),
  264. Ogre::Vector3((x4 / m_ScreenWidth) * 2 - 1, -((y4 / m_ScreenHeight) * 2 - 1), m_FinalZ)
  265. };
  266. auto texture = Ogre::FloatRect(
  267. (float)char_data.x / width, // left
  268. (float)char_data.y / height, // top
  269. (float)(char_data.x + char_data.width) / width, // right
  270. (float)(char_data.y + char_data.height) / height // bottom
  271. );
  272. Ogre::ColourValue colour = style.colour;
  273. // draw two triangles with a colour and texture.
  274. WriteGlyph(writeIterator, coords, colour, texture);
  275. m_RenderOp.vertexData->vertexCount += 6;
  276. data.position += 1;
  277. }
  278. m_VertexBuffer->unlock();
  279. data.local_x1 = local_x1;
  280. data.local_y1 = local_y1;
  281. }
  282. void
  283. UiTextArea::CreateVertexBuffer()
  284. {
  285. m_MaxLetters = 1024;
  286. m_RenderOp.vertexData = new Ogre::VertexData;
  287. m_RenderOp.vertexData->vertexStart = 0;
  288. Ogre::VertexDeclaration* vDecl = m_RenderOp.vertexData->vertexDeclaration;
  289. size_t offset = 0;
  290. vDecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
  291. offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
  292. vDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
  293. offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
  294. vDecl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
  295. m_VertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(vDecl->getVertexSize(0), m_MaxLetters * 6, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
  296. m_RenderOp.vertexData->vertexBufferBinding->setBinding(0, m_VertexBuffer);
  297. m_RenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
  298. m_RenderOp.useIndexes = false;
  299. }
  300. void
  301. UiTextArea::DestroyVertexBuffer()
  302. {
  303. delete m_RenderOp.vertexData;
  304. m_RenderOp.vertexData = 0;
  305. m_VertexBuffer.setNull();
  306. m_MaxLetters = 0;
  307. }