#include #include #include #include "core/Logger.h" #include "core/UiManager.h" #include "core/UiTextArea.h" UiTextArea::UiTextArea(const Ogre::String& name): UiWidget(name) { Initialise(); } UiTextArea::UiTextArea(const Ogre::String& name, const Ogre::String& path_name, UiWidget* parent): UiWidget(name, path_name, parent) { Initialise(); } UiTextArea::~UiTextArea() { DestroyVertexBuffer(); } void UiTextArea::Initialise() { m_Font = nullptr; m_MaxLetters = 0; m_TextAlign = UiTextArea::LEFT; m_Text = ""; m_TextNode = nullptr; m_SceneManager = Ogre::Root::getSingleton().getSceneManager("Scene"); m_RenderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem(); CreateVertexBuffer(); } void UiTextArea::Update() { UiWidget::Update(); } void UiTextArea::Render() { if(m_Visible == true) { if(m_RenderOp.vertexData->vertexCount != 0) { m_RenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); m_RenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); m_RenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); m_SceneManager->_setPass(m_Material->getTechnique(0)->getPass(0), true, false); m_RenderSystem->setScissorTest(true, m_ScissorLeft, m_ScissorTop, m_ScissorRight, m_ScissorBottom); m_RenderSystem->_render(m_RenderOp); m_RenderSystem->setScissorTest(false); } } UiWidget::Render(); } void UiTextArea::UpdateTransformation() { UiWidget::UpdateTransformation(); UpdateGeometry(); } void UiTextArea::SetTextAlign(const TextAlign align) { m_TextAlign = align; } void UiTextArea::SetText(const Ogre::UTFString& text) { m_Text = text; } void UiTextArea::SetText(TiXmlNode* text) { m_TextNode = text; } void UiTextArea::SetFont(const Ogre::String& font) { m_Font = UiManager::getSingleton().GetFont(font); if(m_Font == nullptr) { LOG_ERROR("Could not find font \"" + font + "\" for \"" + m_PathName + "\"."); return; } m_Material = Ogre::MaterialManager::getSingleton().create("UiMaterials." + m_PathName, "General"); Ogre::Pass* pass = m_Material->getTechnique(0)->getPass(0); pass->setVertexColourTracking(Ogre::TVC_AMBIENT); pass->setCullingMode(Ogre::CULL_NONE); pass->setDepthCheckEnabled(false); pass->setDepthWriteEnabled(false); pass->setLightingEnabled(false); pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); pass->setAlphaRejectFunction(Ogre::CMPF_GREATER); pass->setAlphaRejectValue(0); Ogre::TextureUnitState* tex = pass->createTextureUnitState(); tex->setTextureName(m_Font->GetImageName()); tex->setNumMipmaps(-1); tex->setTextureFiltering(Ogre::TFO_NONE); } void UiTextArea::UpdateGeometry() { if(m_Font == nullptr) { LOG_ERROR("Font for \"" + m_PathName + "\" if not set."); return; } if(m_Text.size() > m_MaxLetters) { 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) + "."); return; } float length = 0; if(m_TextAlign != LEFT) { if(m_TextNode != nullptr) { length = GetTextLengthFromNode(m_TextNode); } else { length = GetTextLength(m_Text); } if(m_TextAlign == CENTER) { length /= 2; } } TextBlockData data; data.local_x1 = -m_FinalOrigin.x - length; data.local_y1 = -m_FinalOrigin.y; data.position = 0; TextStyle style; style.colour = m_Colour1; if(m_TextNode != nullptr) { SetTextGeometryFromNode(m_TextNode, data, style); } else { SetTextGeometry(m_Text, data, style); } } float UiTextArea::GetTextLengthFromNode(TiXmlNode* node) const { float length = 0; while(node != nullptr) { switch(node->Type()) { case TiXmlNode::TINYXML_TEXT: { TiXmlText* childText = node->ToText(); if(childText) { length += GetTextLength(childText->Value()); } } break; case TiXmlNode::TINYXML_ELEMENT: { length +=GetTextLengthFromNode(node->FirstChild()); } break; } node = node->NextSibling(); } return length; } float UiTextArea::GetTextLength(const Ogre::UTFString& text) const { float length = 0; for(size_t i = 0; i < text.size(); ++i) { UiCharData char_data = m_Font->GetCharData(text[i]); length += (char_data.pre + char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f; } return length; } void UiTextArea::SetTextGeometryFromNode(TiXmlNode* node, TextBlockData& data, const TextStyle& style) { while(node != nullptr) { switch(node->Type()) { case TiXmlNode::TINYXML_TEXT: { TiXmlText* childText = node->ToText(); if(childText) { SetTextGeometry(childText->Value(), data, style); } } break; case TiXmlNode::TINYXML_ELEMENT: { TextStyle style_child; style_child.colour = style.colour; Ogre::String name = node->ValueStr(); if(name == "colour") { style_child.colour = Ogre::StringConverter::parseColourValue(node->ToElement()->Attribute("value")); } TiXmlNode* node_child = node->FirstChild(); SetTextGeometryFromNode(node_child, data, style_child); } break; } node = node->NextSibling(); } } void UiTextArea::SetTextGeometry(const Ogre::UTFString& text, TextBlockData& data, const TextStyle& style) { float* writeIterator = (float*) m_VertexBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); writeIterator += data.position * 9 * 6; m_RenderOp.vertexData->vertexCount = data.position * 6; float local_x1 = data.local_x1; float local_y1 = data.local_y1; float x = m_FinalTranslate.x; float y = m_FinalTranslate.y; for(auto &c : text) { UiCharData char_data = m_Font->GetCharData(c); local_x1 += char_data.pre * m_FinalScale.x * m_ScreenHeight / 720.0f; float local_x2 = local_x1 + char_data.width * m_FinalScale.x * m_ScreenHeight / 720.0f; float local_y2 = local_y1 + char_data.height * m_FinalScale.y * m_ScreenHeight / 720.0f; int x1, y1, x2, y2, x3, y3, x4, y4; if(m_FinalRotation != 0) { float cos = Ogre::Math::Cos(Ogre::Radian(Ogre::Degree(m_FinalRotation))); float sin = Ogre::Math::Sin(Ogre::Radian(Ogre::Degree(m_FinalRotation))); x1 = static_cast(local_x1 * cos - local_y1 * sin + x); y1 = static_cast(local_x1 * sin + local_y1 * cos + y); x2 = static_cast(local_x2 * cos - local_y1 * sin + x); y2 = static_cast(local_x2 * sin + local_y1 * cos + y); x3 = static_cast(local_x2 * cos - local_y2 * sin + x); y3 = static_cast(local_x2 * sin + local_y2 * cos + y); x4 = static_cast(local_x1 * cos - local_y2 * sin + x); y4 = static_cast(local_x1 * sin + local_y2 * cos + y); } else { x1 = static_cast(local_x1 + x); y1 = static_cast(local_y1 + y); x2 = static_cast(local_x2 + x); y2 = static_cast(local_y1 + y); x3 = static_cast(local_x2 + x); y3 = static_cast(local_y2 + y); x4 = static_cast(local_x1 + x); y4 = static_cast(local_y2 + y); } local_x1 += (char_data.width + char_data.post) * m_FinalScale.x * m_ScreenHeight / 720.0f; float width = static_cast(m_Font->GetImageWidth()); float height = static_cast(m_Font->GetImageHeight()); Ogre::Vector3 coords[4] = { Ogre::Vector3((x1 / m_ScreenWidth) * 2 - 1, -((y1 / m_ScreenHeight) * 2 - 1), m_FinalZ), Ogre::Vector3((x2 / m_ScreenWidth) * 2 - 1, -((y2 / m_ScreenHeight) * 2 - 1), m_FinalZ), Ogre::Vector3((x3 / m_ScreenWidth) * 2 - 1, -((y3 / m_ScreenHeight) * 2 - 1), m_FinalZ), Ogre::Vector3((x4 / m_ScreenWidth) * 2 - 1, -((y4 / m_ScreenHeight) * 2 - 1), m_FinalZ) }; auto texture = Ogre::FloatRect( (float)char_data.x / width, // left (float)char_data.y / height, // top (float)(char_data.x + char_data.width) / width, // right (float)(char_data.y + char_data.height) / height // bottom ); Ogre::ColourValue colour = style.colour; // draw two triangles with a colour and texture. WriteGlyph(writeIterator, coords, colour, texture); m_RenderOp.vertexData->vertexCount += 6; data.position += 1; } m_VertexBuffer->unlock(); data.local_x1 = local_x1; data.local_y1 = local_y1; } void UiTextArea::CreateVertexBuffer() { m_MaxLetters = 1024; m_RenderOp.vertexData = new Ogre::VertexData; m_RenderOp.vertexData->vertexStart = 0; Ogre::VertexDeclaration* vDecl = m_RenderOp.vertexData->vertexDeclaration; size_t offset = 0; vDecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); vDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4); vDecl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); m_VertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(vDecl->getVertexSize(0), m_MaxLetters * 6, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false); m_RenderOp.vertexData->vertexBufferBinding->setBinding(0, m_VertexBuffer); m_RenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; m_RenderOp.useIndexes = false; } void UiTextArea::DestroyVertexBuffer() { delete m_RenderOp.vertexData; m_RenderOp.vertexData = 0; m_VertexBuffer.setNull(); m_MaxLetters = 0; }