UiTextArea.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <string>
  16. #include <iostream>
  17. #include <OgreBlendMode.h>
  18. #include <OgreCommon.h>
  19. #include <Overlay/OgreFontManager.h>
  20. #include <Overlay/OgreUTFString.h>
  21. #include <OgreHardwareBuffer.h>
  22. #include <OgreHardwareBufferManager.h>
  23. #include <OgreMaterial.h>
  24. #include <OgreMaterialManager.h>
  25. #include "core/Logger.h"
  26. #include "core/UiManager.h"
  27. #include "core/UiTextArea.h"
  28. #include "core/Timer.h"
  29. #include "core/UiSprite.h"
  30. #include "core/Utilites.h"
  31. #include "TextHandler.h"
  32. UiTextArea::UiTextArea(const Ogre::String& name): UiWidget(name){
  33. Initialise();
  34. }
  35. UiTextArea::UiTextArea(const Ogre::String& name, const Ogre::String& path_name, UiWidget* parent):
  36. UiWidget(name, path_name, parent)
  37. {Initialise();}
  38. UiTextArea::~UiTextArea(){DestroyVertexBuffer();}
  39. void UiTextArea::Initialise(){
  40. font_ = nullptr;
  41. max_letters_ = 0;
  42. text_align_ = UiTextArea::LEFT;
  43. text_limit_ = 0;
  44. text_print_speed_ = -1; // -1 instant
  45. text_print_speed_mod_ = 1;
  46. text_state_ = TS_DONE;
  47. text_y_offset_ = 0;
  48. text_y_offset_target_ = 0;
  49. pause_time_ = 0;
  50. next_page_start_ = 0;
  51. padding_top_ = 0;
  52. padding_right_ = 0;
  53. padding_bottom_ = 0;
  54. padding_left_ = 0;
  55. next_pressed_ = false;
  56. next_repeated_ = false;
  57. timer_ = false;
  58. timer_time_ = 0;
  59. TextVariable var;
  60. var.name = "UITextAreaTimer";
  61. var.value = "00:00";
  62. text_variable_.push_back(var);
  63. scene_manager_ = Ogre::Root::getSingleton().getSceneManager("Scene");
  64. render_system_ = Ogre::Root::getSingletonPtr()->getRenderSystem();
  65. CreateVertexBuffer();
  66. }
  67. void UiTextArea::Update(){
  68. if (visible_ == true){
  69. if (timer_ == true){
  70. int time = Timer::getSingleton().GetGameTimer();
  71. if (time > 5999) time = 5999; // 99:59
  72. if (time != timer_time_){
  73. timer_time_ = time;
  74. Ogre::String time_string = "";
  75. time_string += Ogre::StringUtil::format("%2d", timer_time_ / 60);
  76. time_string += (timer_time_ & 1) ? ":" : ";";
  77. time_string += Ogre::StringUtil::format("%2d", timer_time_ % 60);
  78. SetVariable("UITextAreaTimer", time_string);
  79. }
  80. }
  81. switch(text_state_){
  82. case TS_SHOW_TEXT:
  83. if (text_print_speed_ == -1) text_limit_ = max_letters_;
  84. else{
  85. float time = Timer::getSingleton().GetGameTimeDelta() * 30;
  86. float addition;
  87. float limit;
  88. if (next_pressed_ == true || next_repeated_ == true)
  89. text_print_speed_mod_ += (text_print_speed_mod_ >= 128) ? 0 : 1.0f * time;
  90. else text_print_speed_mod_ -= (text_print_speed_mod_ <= 1) ? 0 : 1.0f * time;
  91. if (text_print_speed_ < 128){
  92. addition = ((128 - text_print_speed_) / 32) + 2;
  93. limit = 1;
  94. }
  95. else{
  96. addition = 2;
  97. limit = ((text_print_speed_ - 128) / 32) + 1;
  98. }
  99. float char_to_add = (limit * text_print_speed_mod_ / 16 + addition) / limit;
  100. text_limit_ += time * char_to_add;
  101. }
  102. update_transformation_ = true;
  103. break;
  104. case TS_SCROLL_TEXT:
  105. text_y_offset_
  106. -= font_->GetHeight()
  107. * Timer::getSingleton().GetGameTimeDelta()
  108. / text_scroll_time_;
  109. if (text_y_offset_ <= text_y_offset_target_){
  110. text_y_offset_ = text_y_offset_target_;
  111. text_print_speed_mod_ = 1;
  112. text_state_ = TS_SHOW_TEXT;
  113. }
  114. update_transformation_ = true;
  115. break;
  116. case TS_PAUSE_OK:
  117. if (next_pressed_ == true){
  118. text_print_speed_mod_ = 1;
  119. text_state_ = TS_SHOW_TEXT;
  120. }
  121. break;
  122. case TS_PAUSE_TIME:
  123. pause_time_ -= Timer::getSingleton().GetGameTimeDelta();
  124. if (pause_time_ <= 0){
  125. text_print_speed_mod_ = 1;
  126. text_state_ = TS_SHOW_TEXT;
  127. }
  128. break;
  129. case TS_OVERFLOW:
  130. if (next_pressed_ == true){
  131. text_y_offset_target_ = text_y_offset_ - font_->GetHeight();
  132. text_state_ = TS_SCROLL_TEXT;
  133. }
  134. break;
  135. case TS_NEXT_PAGE:
  136. if (next_pressed_ == true){
  137. RemoveSpritesFromText(next_page_start_);
  138. text_.erase(text_.begin(), text_.begin() + next_page_start_);
  139. text_limit_ = 0;
  140. text_print_speed_mod_ = 1;
  141. text_y_offset_ = 0;
  142. text_y_offset_target_ = 0;
  143. text_state_ = TS_SHOW_TEXT;
  144. }
  145. break;
  146. }
  147. }
  148. next_pressed_ = false;
  149. next_repeated_ = false;
  150. UiWidget::Update();
  151. }
  152. void UiTextArea::Render(){
  153. // Scripts that run after the widgets update (like the battle) can change the text or the
  154. // position of a widget in the same frame it is drawn, so the geometry is refreshed here.
  155. if (update_transformation_ == true && visible_ == true) UpdateTransformation();
  156. if (update_transformation_ == false && visible_ == true){
  157. if (render_operation_.vertexData->vertexCount != 0){
  158. auto render_parameters = render_system_->getFixedFunctionParams(
  159. Ogre::TVC_NONE, Ogre::FOG_NONE
  160. );
  161. render_parameters->setConstant(
  162. Ogre::GpuProgramParameters::ACT_WORLD_MATRIX, Ogre::Matrix4::IDENTITY
  163. );
  164. render_parameters->setConstant(
  165. Ogre::GpuProgramParameters::ACT_PROJECTION_MATRIX, Ogre::Matrix4::IDENTITY
  166. );
  167. render_parameters->setConstant(
  168. Ogre::GpuProgramParameters::ACT_VIEW_MATRIX, Ogre::Matrix4::IDENTITY
  169. );
  170. render_system_->applyFixedFunctionParams(render_parameters, Ogre::GPV_GLOBAL);
  171. scene_manager_->_setPass(material_->getTechnique(0)->getPass(0), true, false);
  172. render_system_->setScissorTest(true, Ogre::Rect(
  173. scissor_left_, scissor_top_, scissor_right_, scissor_bottom_
  174. ));
  175. render_system_->_render(render_operation_);
  176. render_system_->setScissorTest(false);
  177. }
  178. }
  179. UiWidget::Render();
  180. }
  181. void UiTextArea::UpdateTransformation(){
  182. UiWidget::UpdateTransformation();
  183. UpdateGeometry();
  184. update_transformation_ = false;
  185. }
  186. void UiTextArea::InputPressed(){next_pressed_ = true;}
  187. void UiTextArea::InputRepeated(){next_repeated_ = true;}
  188. void UiTextArea::SetTextAlign(const TextAlign align){
  189. text_align_ = align;
  190. update_transformation_ = true;
  191. }
  192. void UiTextArea::SetPadding(
  193. const float top, const float right, const float bottom, const float left
  194. ){
  195. padding_top_ = top;
  196. padding_right_ = right;
  197. padding_bottom_ = bottom;
  198. padding_left_ = left;
  199. }
  200. void UiTextArea::SetText(const char* text){
  201. // Don't call PrepareTextFromNode from here!
  202. // Use the non-recursive SetTextFromNode.
  203. Ogre::UTFString str_text = Ogre::UTFString(text);
  204. text_.clear();
  205. TiXmlDocument doc;
  206. Ogre::UTFString xml_text = "<container>" + str_text + "</container>";
  207. doc.Parse(xml_text.asUTF8_c_str(), 0, TIXML_ENCODING_UTF8);
  208. SetTextFromNode(doc.RootElement(), colour_1_);
  209. text_state_ = TS_SHOW_TEXT;
  210. update_transformation_ = true;
  211. if (text_.size() > max_letters_){
  212. text_.clear();
  213. LOG_ERROR(
  214. "Max number of text reached in '" + path_name_ + "'. Can't render text from node. "
  215. + "Max number of letters is " + Ogre::StringConverter::toString(max_letters_) + "."
  216. );
  217. }
  218. text_state_ = TS_SHOW_TEXT;
  219. update_transformation_ = true;
  220. }
  221. void UiTextArea::SetText(const Ogre::UTFString& text){
  222. TiXmlDocument doc;
  223. Ogre::UTFString xml_text = "<container>" + text + "</container>";
  224. doc.Parse(xml_text.asUTF8_c_str(), 0, TIXML_ENCODING_UTF8);
  225. if (doc.Error() == true){
  226. LOG_ERROR("Can't parse text '" + text + "'. TinyXml Error: " + doc.ErrorDesc());
  227. return;
  228. }
  229. SetText(doc.RootElement());
  230. }
  231. void UiTextArea::SetText(TiXmlNode* text){
  232. if (text == NULL){
  233. LOG_ERROR("Text pointer is NULL.");
  234. return;
  235. }
  236. // Reload font if language was changed.
  237. if (font_ != NULL){
  238. Ogre::String language = font_->GetLanguage();
  239. if (language != "")
  240. if (TextHandler::getSingleton().GetLanguage() != language) SetFont(font_->GetName());
  241. }
  242. TextClear();
  243. PrepareTextFromNode(text, colour_1_);
  244. text_state_ = TS_SHOW_TEXT;
  245. update_transformation_ = true;
  246. if (text_.size() > max_letters_){
  247. text_.clear();
  248. LOG_ERROR(
  249. "Max number of text reached in '" + path_name_ + "'. Can't render text from node. "
  250. + "Max number of letters is " + Ogre::StringConverter::toString(max_letters_) + "."
  251. );
  252. }
  253. }
  254. void UiTextArea::TextClear(){
  255. RemoveSpritesFromText(text_.size());
  256. text_.clear();
  257. text_limit_ = 0;
  258. text_print_speed_mod_ = 1;
  259. text_y_offset_ = 0;
  260. text_y_offset_target_ = 0;
  261. }
  262. void UiTextArea::RemoveSpritesFromText(const unsigned int end){
  263. for (unsigned int i = 0; i < end; ++ i){
  264. if (text_[i].sprite != NULL){
  265. for (unsigned int j = 0; j < children_.size(); ++j){
  266. if (text_[i].sprite == children_[j]){
  267. delete children_[j];
  268. children_.erase(children_.begin() + j, children_.begin() + j + 1);
  269. break;
  270. }
  271. }
  272. }
  273. }
  274. }
  275. void UiTextArea::SetFont(const Ogre::String& font){
  276. font_ = UiManager::getSingleton().GetFont(font);
  277. if (font_ == nullptr){
  278. LOG_ERROR("Could not find font '" + font + "' for '" + path_name_ + "'.");
  279. return;
  280. }
  281. material_ = Ogre::MaterialManager::getSingleton().getByName(
  282. "UiMaterials." + path_name_, "FONTS"
  283. );
  284. if (material_ == nullptr){
  285. material_ = Ogre::MaterialManager::getSingleton().create(
  286. "UiMaterials." + path_name_, "FONTS"
  287. );
  288. }
  289. Ogre::Pass* pass = material_->getTechnique(0)->getPass(0);
  290. pass->setVertexColourTracking(Ogre::TVC_AMBIENT);
  291. pass->setCullingMode(Ogre::CULL_NONE);
  292. pass->setDepthCheckEnabled(false);
  293. pass->setDepthWriteEnabled(false);
  294. pass->setLightingEnabled(false);
  295. pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
  296. pass->setAlphaRejectFunction(Ogre::CMPF_GREATER);
  297. pass->setAlphaRejectValue(0);
  298. Ogre::TextureUnitState* tex;
  299. if (pass->getTextureUnitStates().size() == 0)
  300. tex = pass->createTextureUnitState();
  301. else tex = pass->getTextureUnitState(0);//createTextureUnitState();
  302. tex->setTextureName(font_->GetImageName());
  303. tex->setNumMipmaps(-1);
  304. tex->setTextureFiltering(Ogre::TFO_NONE);
  305. update_transformation_ = true;
  306. }
  307. const UiFont* UiTextArea::GetFont() const{return font_;}
  308. void UiTextArea::SetTextPrintSpeed(const float speed){text_print_speed_ = speed;}
  309. void UiTextArea::SetTextScrollTime(const float time){text_scroll_time_ = time;}
  310. void UiTextArea::SetVariable(const Ogre::String& name, const Ogre::UTFString& value){
  311. if (name == "") return;
  312. bool update = false;
  313. for (unsigned int i = 0; i < text_variable_.size(); ++ i){
  314. if (text_variable_[i].name == name){
  315. text_variable_[i].value = value;
  316. update = true;
  317. for (unsigned int j = 0; j < text_.size(); ++ j){
  318. if (text_[j].variable == name){
  319. text_.erase(
  320. text_.begin() + j + 1, text_.begin() + j + 1 + text_[j].variable_len
  321. );
  322. }
  323. }
  324. }
  325. }
  326. if (update == false){
  327. TextVariable var;
  328. var.name = name;
  329. var.value = value;
  330. text_variable_.push_back(var);
  331. }
  332. for (unsigned int i = 0; i < text_.size(); ++ i){
  333. if (text_[i].variable == name){
  334. text_[i].variable_len = value.size();
  335. unsigned int j = 0;
  336. for (; j < text_[i].variable_len; ++ j){
  337. TextChar text_char;
  338. text_char.char_code = value[j];
  339. text_char.colour = text_[i].colour;
  340. text_.insert(text_.begin() + i + 1 + j, text_char);
  341. }
  342. i += j;
  343. }
  344. }
  345. update_transformation_ = true;
  346. }
  347. Ogre::UTFString UiTextArea::GetVariable(const Ogre::String& name) const{
  348. for (unsigned int i = 0; i < text_variable_.size(); ++ i)
  349. if (text_variable_[i].name == name) return text_variable_[i].value;
  350. return "";
  351. }
  352. TextState UiTextArea::GetTextState() const{return text_state_;}
  353. float UiTextArea::GetTextLimit() const{return text_limit_;}
  354. unsigned int UiTextArea::GetTextSize() const{return text_.size();}
  355. float UiTextArea::GetPauseTime() const{return pause_time_;}
  356. void UiTextArea::UpdateGeometry(){
  357. if (font_ == NULL){
  358. LOG_ERROR("Font for '" + path_name_ + "' if not set.");
  359. return;
  360. }
  361. float width = 0;
  362. if (text_align_ != LEFT){
  363. width = GetTextWidth();
  364. if (text_align_ == CENTER) width /= 2;
  365. }
  366. float* write_iterator
  367. = static_cast<float*>(vertex_buffer_->lock(Ogre::HardwareBuffer::HBL_NORMAL));
  368. render_operation_.vertexData->vertexCount = 0;
  369. float local_x_start
  370. = -final_origin_.x - (width - padding_left_) * final_scale_.x * screen_height_ / 720.0f;
  371. float local_x1 = local_x_start;
  372. float local_y1 = -final_origin_.y + ((text_y_offset_ + padding_top_)
  373. * final_scale_.y * screen_height_ / 720.0f);
  374. float local_x2;
  375. float local_y2;
  376. float x = final_translate_.x;
  377. float y = final_translate_.y;
  378. unsigned int i = 0;
  379. for (; (i < text_limit_) && (i < text_.size()); ++ i){
  380. if (text_[i].skip == true) continue;
  381. else if (text_[i].pause_ok == true){
  382. text_[i].skip = true;
  383. text_state_ = TS_PAUSE_OK;
  384. break;
  385. }
  386. else if (text_[i].pause_time != 0){
  387. text_[i].skip = true;
  388. pause_time_ = text_[i].pause_time;
  389. text_state_ = TS_PAUSE_TIME;
  390. break;
  391. }
  392. else if (text_[i].next_page == true){
  393. text_[i].skip = true;
  394. next_page_start_ = i + 1;
  395. text_state_ = TS_NEXT_PAGE;
  396. break;
  397. }
  398. else if (text_[i].sprite != NULL){
  399. float width_percent = 0;
  400. float img_width = 0;
  401. text_[i].sprite->GetWidth(width_percent, img_width);
  402. text_[i].sprite->SetX(0, local_x1 / (final_scale_.x * screen_height_ / 720.0f));
  403. local_x1 += img_width * final_scale_.x * screen_height_ / 720.0f;
  404. float height_percent = 0;
  405. float img_height = 0;
  406. text_[i].sprite->GetHeight(height_percent, img_height);
  407. text_[i].sprite->SetY(
  408. 0, text_[i].sprite_y + (local_y1 / (final_scale_.y * screen_height_ / 720.0f))
  409. );
  410. text_[i].sprite->SetVisible(true);
  411. text_[i].sprite->UpdateGeometry();
  412. continue;
  413. }
  414. UiCharData char_data = font_->GetCharData(text_[i].char_code);
  415. Ogre::ColourValue colour = text_[i].colour;
  416. if (char_data.char_code == 10){ // LF (line feed): \n
  417. local_x1 = local_x_start;
  418. local_y1 += font_->GetHeight() * final_scale_.y * screen_height_ / 720.0f;
  419. continue;
  420. }
  421. local_x1 += char_data.pre * final_scale_.x * screen_height_ / 720.0f;
  422. local_x2 = local_x1 + char_data.width * final_scale_.x * screen_height_ / 720.0f;
  423. local_y2 = local_y1 + char_data.height * final_scale_.y * screen_height_ / 720.0f;
  424. if (
  425. local_x2 + char_data.post * final_scale_.x * screen_height_ / 720.0f
  426. > final_size_.x - padding_right_ * final_scale_.x * screen_height_ / 720.0f
  427. ){
  428. local_x1 = local_x_start;
  429. local_x2 = local_x1 + char_data.width * final_scale_.x * screen_height_ / 720.0f;
  430. local_y1 += font_->GetHeight() * final_scale_.y * screen_height_ / 720.0f;
  431. local_y2 = local_y1 + char_data.height * final_scale_.y * screen_height_ / 720.0f;
  432. }
  433. // If the lower border of the textarea is crossed:
  434. // generate event and stop rendering
  435. if (local_y2 > final_size_.y - padding_bottom_ * final_scale_.y * screen_height_ / 720.0f){
  436. if (text_state_ != TS_SCROLL_TEXT) text_state_ = TS_OVERFLOW;
  437. break;
  438. }
  439. int x1, y1, x2, y2, x3, y3, x4, y4;
  440. if (final_rotation_ != 0){
  441. float cos = Ogre::Math::Cos(Ogre::Radian(Ogre::Degree(final_rotation_)));
  442. float sin = Ogre::Math::Sin(Ogre::Radian(Ogre::Degree(final_rotation_)));
  443. x1 = local_x1 * cos - local_y1 * sin + x;
  444. y1 = local_x1 * sin + local_y1 * cos + y;
  445. x2 = local_x2 * cos - local_y1 * sin + x;
  446. y2 = local_x2 * sin + local_y1 * cos + y;
  447. x3 = local_x2 * cos - local_y2 * sin + x;
  448. y3 = local_x2 * sin + local_y2 * cos + y;
  449. x4 = local_x1 * cos - local_y2 * sin + x;
  450. y4 = local_x1 * sin + local_y2 * cos + y;
  451. }
  452. else{
  453. x1 = local_x1 + x;
  454. y1 = local_y1 + y;
  455. x2 = local_x2 + x;
  456. y2 = local_y1 + y;
  457. x3 = local_x2 + x;
  458. y3 = local_y2 + y;
  459. x4 = local_x1 + x;
  460. y4 = local_y2 + y;
  461. }
  462. float new_x1 = (x1 / screen_width_) * 2 - 1;
  463. float new_y1 = -((y1 / screen_height_) * 2 - 1);
  464. float new_x2 = (x2 / screen_width_) * 2 - 1;
  465. float new_y2 = -((y2 / screen_height_) * 2 - 1);
  466. float new_x3 = (x3 / screen_width_) * 2 - 1;
  467. float new_y3 = -((y3 / screen_height_) * 2 - 1);
  468. float new_x4 = (x4 / screen_width_) * 2 - 1;
  469. float new_y4 = -((y4 / screen_height_) * 2 - 1);
  470. local_x1 += (char_data.width + char_data.post) * final_scale_.x * screen_height_ / 720.0f;
  471. float img_width = font_->GetImageWidth();
  472. float img_height = font_->GetImageHeight();
  473. float left = (float)char_data.x / img_width;
  474. float right = (float)(char_data.x + char_data.width) / img_width;
  475. float top = (float)char_data.y / img_height;
  476. float bottom = (float)(char_data.y + char_data.height) / img_height;
  477. *write_iterator ++ = new_x1;
  478. *write_iterator ++ = new_y1;
  479. *write_iterator ++ = final_z_;
  480. *write_iterator ++ = colour.r;
  481. *write_iterator ++ = colour.g;
  482. *write_iterator ++ = colour.b;
  483. *write_iterator ++ = colour.a;
  484. *write_iterator ++ = left;
  485. *write_iterator ++ = top;
  486. *write_iterator ++ = new_x2;
  487. *write_iterator ++ = new_y2;
  488. *write_iterator ++ = final_z_;
  489. *write_iterator ++ = colour.r;
  490. *write_iterator ++ = colour.g;
  491. *write_iterator ++ = colour.b;
  492. *write_iterator ++ = colour.a;
  493. *write_iterator ++ = right;
  494. *write_iterator ++ = top;
  495. *write_iterator ++ = new_x3;
  496. *write_iterator ++ = new_y3;
  497. *write_iterator ++ = final_z_;
  498. *write_iterator ++ = colour.r;
  499. *write_iterator ++ = colour.g;
  500. *write_iterator ++ = colour.b;
  501. *write_iterator ++ = colour.a;
  502. *write_iterator ++ = right;
  503. *write_iterator ++ = bottom;
  504. *write_iterator ++ = new_x1;
  505. *write_iterator ++ = new_y1;
  506. *write_iterator ++ = final_z_;
  507. *write_iterator ++ = colour.r;
  508. *write_iterator ++ = colour.g;
  509. *write_iterator ++ = colour.b;
  510. *write_iterator ++ = colour.a;
  511. *write_iterator ++ = left;
  512. *write_iterator ++ = top;
  513. *write_iterator ++ = new_x3;
  514. *write_iterator ++ = new_y3;
  515. *write_iterator ++ = final_z_;
  516. *write_iterator ++ = colour.r;
  517. *write_iterator ++ = colour.g;
  518. *write_iterator ++ = colour.b;
  519. *write_iterator ++ = colour.a;
  520. *write_iterator ++ = right;
  521. *write_iterator ++ = bottom;
  522. *write_iterator ++ = new_x4;
  523. *write_iterator ++ = new_y4;
  524. *write_iterator ++ = final_z_;
  525. *write_iterator ++ = colour.r;
  526. *write_iterator ++ = colour.g;
  527. *write_iterator ++ = colour.b;
  528. *write_iterator ++ = colour.a;
  529. *write_iterator ++ = left;
  530. *write_iterator ++ = bottom;
  531. render_operation_.vertexData->vertexCount += 6;
  532. }
  533. vertex_buffer_->unlock();
  534. if (i == text_.size()) text_state_ = TS_DONE;
  535. }
  536. float UiTextArea::GetTextWidth() const{
  537. float width = 0;
  538. float width_max = 0;
  539. for (unsigned int i = 0; i < text_.size(); ++ i){
  540. UiCharData char_data = font_->GetCharData(text_[i].char_code);
  541. // If newline, store previous row max width
  542. if (char_data.char_code == 10){
  543. width_max = (width > width_max) ? width : width_max;
  544. width = 0;
  545. }
  546. else width += char_data.pre + char_data.width + char_data.post;
  547. }
  548. return (width > width_max) ? width : width_max;
  549. }
  550. void UiTextArea::PrepareTextFromNode(TiXmlNode* node, const Ogre::ColourValue& colour){
  551. while (node != NULL){
  552. switch(node->Type()){
  553. case TiXmlNode::TINYXML_TEXT:
  554. {
  555. TiXmlText* childText = node->ToText();
  556. if (childText) PrepareTextFromText(childText->Value(), colour);
  557. }
  558. break;
  559. case TiXmlNode::TINYXML_ELEMENT:
  560. {
  561. Ogre::ColourValue colour_child = colour;
  562. Ogre::String name = node->ValueStr();
  563. if (name == "colour"){
  564. colour_child = Ogre::StringConverter::parseColourValue(
  565. node->ToElement()->Attribute("value")
  566. );
  567. }
  568. else if (name == "pause_ok"){
  569. TextChar new_char;
  570. new_char.pause_ok = true;
  571. text_.push_back(new_char);
  572. }
  573. else if (name == "pause"){
  574. const std::string* string
  575. = node->ToElement()->Attribute(Ogre::String("time"));
  576. if (string != NULL){
  577. TextChar new_char;
  578. new_char.pause_time = Ogre::StringConverter::parseReal(*string);
  579. text_.push_back(new_char);
  580. }
  581. }
  582. else if (name == "next_page"){
  583. TextChar new_char;
  584. new_char.next_page = true;
  585. text_.push_back(new_char);
  586. }
  587. else if (name == "timer"){
  588. timer_ = true;
  589. TextChar new_char;
  590. new_char.skip = true;
  591. new_char.variable = "UITextAreaTimer";
  592. new_char.colour = colour;
  593. Ogre::UTFString var = GetVariable("UITextAreaTimer");
  594. new_char.variable_len = var.size();
  595. text_.push_back(new_char);
  596. for (unsigned int i = 0; i < var.size(); ++ i){
  597. TextChar text_char;
  598. text_char.char_code = var[i];
  599. text_char.colour = colour;
  600. text_.push_back(text_char);
  601. }
  602. }
  603. else if (name == "variable"){
  604. const std::string* string
  605. = node->ToElement()->Attribute(Ogre::String("name"));
  606. if (string != NULL){
  607. TextChar new_char;
  608. new_char.skip = true;
  609. new_char.variable = *string;
  610. new_char.colour = colour;
  611. Ogre::UTFString var = GetVariable(*string);
  612. new_char.variable_len = var.size();
  613. text_.push_back(new_char);
  614. for (unsigned int i = 0; i < var.size(); ++ i){
  615. TextChar text_char;
  616. text_char.char_code = var[i];
  617. text_char.colour = colour;
  618. text_.push_back(text_char);
  619. }
  620. }
  621. }
  622. else if (name == "character"){
  623. const std::string* id = node->ToElement()->Attribute(Ogre::String("id"));
  624. const std::string char_name = TextHandler::getSingleton().GetCharacterName(
  625. std::stoi(*id)
  626. );
  627. for (unsigned int i = 0; i < char_name.length(); ++ i){
  628. TextChar text_char;
  629. text_char.char_code = char_name.at(i);
  630. text_char.colour = colour;
  631. text_.push_back(text_char);
  632. }
  633. }
  634. else if (name == "party"){
  635. const std::string* pos = node->ToElement()->Attribute(Ogre::String("pos"));
  636. const std::string char_name
  637. = TextHandler::getSingleton().GetPartyCharacterName(std::stoi(*pos));
  638. for (unsigned int i = 0; i < char_name.length(); ++ i){
  639. TextChar text_char;
  640. text_char.char_code = char_name.at(i);
  641. text_char.colour = colour;
  642. text_.push_back(text_char);
  643. }
  644. }
  645. else if (name == "include"){
  646. const std::string* text_name = node->ToElement()->Attribute(
  647. Ogre::String("name")
  648. );
  649. if (text_name != NULL){
  650. TiXmlNode* text = TextHandler::getSingleton().GetText(*text_name);
  651. if (text != NULL) PrepareTextFromNode(text, colour_child);
  652. }
  653. }
  654. else if (name == "image"){
  655. Ogre::String name1 = GetString(node, "sprite");
  656. if (name1 != ""){
  657. TiXmlNode* sprites = UiManager::getSingleton().GetPrototype(
  658. "TextAreaSprite"
  659. );
  660. if (sprites != NULL){
  661. sprites = sprites->FirstChild();
  662. while (sprites != NULL){
  663. if (
  664. sprites->Type() == TiXmlNode::TINYXML_ELEMENT
  665. && sprites->ValueStr() == "sprite"
  666. ){
  667. Ogre::String name2 = GetString(sprites, "name");
  668. if (name1 == name2){
  669. TextChar new_char;
  670. UiSprite* sprite = new UiSprite(
  671. name1, name_ + "." + name1, this
  672. );
  673. Ogre::String image = GetString(sprites, "image");
  674. if (image != "") sprite->SetImage(image);
  675. Ogre::String y_str = GetString(sprites, "y");
  676. if (y_str != ""){
  677. float y_percent = 0;
  678. float y = 0;
  679. ParsePercent(y_percent, y, y_str);
  680. new_char.sprite_y = y;
  681. }
  682. Ogre::String width_str = GetString(sprites, "width");
  683. if (width_str != ""){
  684. float width_percent = 0;
  685. float width = 0;
  686. ParsePercent(width_percent, width, width_str);
  687. sprite->SetWidth(0, width);
  688. }
  689. Ogre::String height_str = GetString(sprites, "height");
  690. if (height_str != ""){
  691. float height_percent = 0;
  692. float height = 0;
  693. ParsePercent(height_percent, height, height_str);
  694. sprite->SetHeight(height_percent, height);
  695. }
  696. sprite->SetVisible(false);
  697. AddChild(sprite);
  698. new_char.sprite = sprite;
  699. text_.push_back(new_char);
  700. break;
  701. }
  702. }
  703. sprites = sprites->NextSibling();
  704. }
  705. }
  706. }
  707. }
  708. TiXmlNode* node_child = node->FirstChild();
  709. if (node_child != NULL) PrepareTextFromNode(node_child, colour_child);
  710. }
  711. break;
  712. }
  713. node = node->NextSibling();
  714. }
  715. }
  716. void UiTextArea::SetTextFromNode(TiXmlNode* node, const Ogre::ColourValue& colour){
  717. switch(node->Type()){
  718. case TiXmlNode::TINYXML_TEXT:
  719. {
  720. TiXmlText* childText = node->ToText();
  721. if (childText) PrepareTextFromText(childText->Value(), colour);
  722. }
  723. break;
  724. case TiXmlNode::TINYXML_ELEMENT:
  725. {
  726. Ogre::ColourValue colour_child = colour;
  727. Ogre::String name = node->ValueStr();
  728. if (name == "colour"){
  729. colour_child = Ogre::StringConverter::parseColourValue(
  730. node->ToElement()->Attribute("value")
  731. );
  732. }
  733. else if (name == "pause_ok"){
  734. TextChar new_char;
  735. new_char.pause_ok = true;
  736. text_.push_back(new_char);
  737. }
  738. else if (name == "pause"){
  739. const std::string* string
  740. = node->ToElement()->Attribute(Ogre::String("time"));
  741. if (string != NULL){
  742. TextChar new_char;
  743. new_char.pause_time = Ogre::StringConverter::parseReal(*string);
  744. text_.push_back(new_char);
  745. }
  746. }
  747. else if (name == "next_page"){
  748. TextChar new_char;
  749. new_char.next_page = true;
  750. text_.push_back(new_char);
  751. }
  752. else if (name == "timer"){
  753. timer_ = true;
  754. TextChar new_char;
  755. new_char.skip = true;
  756. new_char.variable = "UITextAreaTimer";
  757. new_char.colour = colour;
  758. Ogre::UTFString var = GetVariable("UITextAreaTimer");
  759. new_char.variable_len = var.size();
  760. text_.push_back(new_char);
  761. for (unsigned int i = 0; i < var.size(); ++ i){
  762. TextChar text_char;
  763. text_char.char_code = var[i];
  764. text_char.colour = colour;
  765. text_.push_back(text_char);
  766. }
  767. }
  768. else if (name == "variable"){
  769. const std::string* string
  770. = node->ToElement()->Attribute(Ogre::String("name"));
  771. if (string != NULL){
  772. TextChar new_char;
  773. new_char.skip = true;
  774. new_char.variable = *string;
  775. new_char.colour = colour;
  776. Ogre::UTFString var = GetVariable(*string);
  777. new_char.variable_len = var.size();
  778. text_.push_back(new_char);
  779. for (unsigned int i = 0; i < var.size(); ++ i){
  780. TextChar text_char;
  781. text_char.char_code = var[i];
  782. text_char.colour = colour;
  783. text_.push_back(text_char);
  784. }
  785. }
  786. }
  787. else if (name == "character"){
  788. const std::string* id = node->ToElement()->Attribute(Ogre::String("id"));
  789. const std::string char_name = TextHandler::getSingleton().GetCharacterName(
  790. std::stoi(*id)
  791. );
  792. for (unsigned int i = 0; i < char_name.length(); ++ i){
  793. TextChar text_char;
  794. text_char.char_code = char_name.at(i);
  795. text_char.colour = colour;
  796. text_.push_back(text_char);
  797. }
  798. }
  799. else if (name == "party"){
  800. const std::string* pos = node->ToElement()->Attribute(Ogre::String("pos"));
  801. const std::string char_name
  802. = TextHandler::getSingleton().GetPartyCharacterName(std::stoi(*pos));
  803. for (unsigned int i = 0; i < char_name.length(); ++ i){
  804. TextChar text_char;
  805. text_char.char_code = char_name.at(i);
  806. text_char.colour = colour;
  807. text_.push_back(text_char);
  808. }
  809. }
  810. else if (name == "include"){
  811. const std::string* text_name = node->ToElement()->Attribute(
  812. Ogre::String("name")
  813. );
  814. if (text_name != NULL){
  815. TiXmlNode* text = TextHandler::getSingleton().GetText(*text_name);
  816. if (text != NULL) SetTextFromNode(text, colour_child);
  817. }
  818. }
  819. else if (name == "image"){
  820. Ogre::String name1 = GetString(node, "sprite");
  821. if (name1 != ""){
  822. TiXmlNode* sprites = UiManager::getSingleton().GetPrototype(
  823. "TextAreaSprite"
  824. );
  825. if (sprites != NULL){
  826. sprites = sprites->FirstChild();
  827. while (sprites != NULL){
  828. if (
  829. sprites->Type() == TiXmlNode::TINYXML_ELEMENT
  830. && sprites->ValueStr() == "sprite"
  831. ){
  832. Ogre::String name2 = GetString(sprites, "name");
  833. if (name1 == name2){
  834. TextChar new_char;
  835. UiSprite* sprite = new UiSprite(
  836. name1, name_ + "." + name1, this
  837. );
  838. Ogre::String image = GetString(sprites, "image");
  839. if (image != "") sprite->SetImage(image);
  840. Ogre::String y_str = GetString(sprites, "y");
  841. if (y_str != ""){
  842. float y_percent = 0;
  843. float y = 0;
  844. ParsePercent(y_percent, y, y_str);
  845. new_char.sprite_y = y;
  846. }
  847. Ogre::String width_str = GetString(sprites, "width");
  848. if (width_str != ""){
  849. float width_percent = 0;
  850. float width = 0;
  851. ParsePercent(width_percent, width, width_str);
  852. sprite->SetWidth(0, width);
  853. }
  854. Ogre::String height_str = GetString(sprites, "height");
  855. if (height_str != ""){
  856. float height_percent = 0;
  857. float height = 0;
  858. ParsePercent(height_percent, height, height_str);
  859. sprite->SetHeight(height_percent, height);
  860. }
  861. sprite->SetVisible(false);
  862. AddChild(sprite);
  863. new_char.sprite = sprite;
  864. text_.push_back(new_char);
  865. break;
  866. }
  867. }
  868. sprites = sprites->NextSibling();
  869. }
  870. }
  871. }
  872. }
  873. TiXmlNode* node_child = node->FirstChild();
  874. if (node_child != NULL) SetTextFromNode(node_child, colour_child);
  875. }
  876. break;
  877. }
  878. }
  879. void UiTextArea::PrepareTextFromText(
  880. const Ogre::UTFString& text, const Ogre::ColourValue& colour_child
  881. ){
  882. for (unsigned int i = 0; i < text.size(); ++ i){
  883. TextChar new_char;
  884. new_char.char_code = text[i];
  885. new_char.colour = colour_child;
  886. text_.push_back(new_char);
  887. };
  888. }
  889. void UiTextArea::CreateVertexBuffer(){
  890. max_letters_ = 1024;
  891. render_operation_.vertexData = new Ogre::VertexData;
  892. render_operation_.vertexData->vertexStart = 0;
  893. Ogre::VertexDeclaration* vertex_declaration = render_operation_.vertexData->vertexDeclaration;
  894. size_t offset = 0;
  895. vertex_declaration->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
  896. offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
  897. vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
  898. offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
  899. vertex_declaration->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
  900. vertex_buffer_ = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
  901. vertex_declaration->getVertexSize(0), max_letters_ * 6,
  902. Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false
  903. );
  904. render_operation_.vertexData->vertexBufferBinding->setBinding(0, vertex_buffer_);
  905. render_operation_.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
  906. render_operation_.useIndexes = false;
  907. }
  908. void UiTextArea::DestroyVertexBuffer(){
  909. delete render_operation_.vertexData;
  910. render_operation_.vertexData = 0;
  911. vertex_buffer_.reset();
  912. max_letters_ = 0;
  913. }