#include #include #include "core/ConfigVar.h" #include "core/CameraManager.h" #include "core/DebugDraw.h" #include "core/Logger.h" #include "core/ScriptManager.h" #include "core/Timer.h" #include "core/UiWidget.h" ConfigVar cv_debug_ui("debug_ui", "Draw ui debug info", "0"); UiWidget::UiWidget(const Ogre::String& name): m_Name(name), m_PathName(name), m_Parent(nullptr) { Initialise(); } UiWidget::UiWidget(const Ogre::String& name, const Ogre::String& path_name, UiWidget* parent): m_Name(name), m_PathName(path_name), m_Parent(parent) { Initialise(); } UiWidget::~UiWidget() { for(unsigned int i = 0; i < m_Animations.size(); ++i) { delete m_Animations[i]; } ScriptManager::getSingleton().RemoveEntity(ScriptManager::UI, m_PathName); RemoveAllChildren(); } void UiWidget::Initialise() { Ogre::Viewport *viewport(CameraManager::getSingleton().getViewport()); m_ScreenWidth = static_cast(viewport->getActualWidth()); m_ScreenHeight = static_cast(viewport->getActualHeight()); m_Visible = false; m_Align = LEFT; m_VerticalAlign = TOP; m_UpdateTransformation = true; m_FinalZ = 0; m_FinalOrigin = Ogre::Vector2::ZERO; m_FinalTranslate = Ogre::Vector2::ZERO; m_FinalSize = Ogre::Vector2(m_ScreenWidth, m_ScreenHeight); m_FinalScale = Ogre::Vector2(1, 1); m_FinalRotation = 0; m_OriginXPercent = 0; m_OriginX = 0; m_OriginYPercent = 0; m_OriginY = 0; m_XPercent = 0; m_X = 0; m_YPercent = 0; m_Y = 0; m_Z = 0; m_WidthPercent = 100; m_Width = 0; m_HeightPercent = 100; m_Height = 0; m_Scale = Ogre::Vector2(1.0f, 1.0f); m_Rotation = 0.0f; m_Scissor = false; m_ScissorTop = 0; m_ScissorBottom = static_cast(m_ScreenHeight); m_ScissorLeft = 0; m_ScissorRight = static_cast(m_ScreenWidth); m_AnimationCurrent = nullptr; m_AnimationDefault = ""; m_AnimationState = UiAnimation::DEFAULT; m_Colour1 = Ogre::ColourValue(1, 1, 1, 1); m_Colour2 = Ogre::ColourValue(1, 1, 1, 1); m_Colour3 = Ogre::ColourValue(1, 1, 1, 1); m_Colour4 = Ogre::ColourValue(1, 1, 1, 1); ScriptManager::getSingleton().AddEntity(ScriptManager::UI, m_PathName, nullptr); } void UiWidget::Update() { if(m_Visible != true) { return; } if(m_AnimationCurrent != nullptr) { float delta_time = Timer::getSingleton().GetGameTimeDelta(); float time = m_AnimationCurrent->GetTime(); // if animation ended if(time + delta_time >= m_AnimationEndTime) { if(time != m_AnimationEndTime) { m_AnimationCurrent->AddTime(m_AnimationEndTime - time); } for(unsigned int i = 0; i < m_AnimationSync.size(); ++i) { ScriptManager::getSingleton().ContinueScriptExecution(m_AnimationSync[i]); } m_AnimationSync.clear(); if(m_AnimationState == UiAnimation::DEFAULT && m_AnimationDefault != "") { // in case of cycled default we need to sync with end time = time + delta_time - m_AnimationCurrent->GetLength(); PlayAnimation(m_AnimationDefault, UiAnimation::DEFAULT, time, -1); } } else { m_AnimationCurrent->AddTime(delta_time); } } else if(m_AnimationCurrent == nullptr && m_AnimationState == UiAnimation::DEFAULT && m_AnimationDefault != "") { PlayAnimation(m_AnimationDefault, UiAnimation::DEFAULT, 0, -1); } for(size_t i = 0; i < m_Children.size(); ++i) { m_Children[i]->Update(); } if(m_UpdateTransformation == true) { UpdateTransformation(); } // debug output if(cv_debug_ui.GetI() >= 1) { float local_x1 = -m_FinalOrigin.x; float local_y1 = -m_FinalOrigin.y; float local_x2 = m_FinalSize.x + local_x1; float local_y2 = m_FinalSize.y + local_y1; float x = m_FinalTranslate.x; float y = m_FinalTranslate.y; DEBUG_DRAW.SetScreenSpace(true); DEBUG_DRAW.SetColour(Ogre::ColourValue(1, 0, 0, 1)); 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); } // slightly modify to let show things that are on board of screen DEBUG_DRAW.Line(static_cast(x1), static_cast(y1 + 1), static_cast(x2), static_cast(y2 + 1)); DEBUG_DRAW.Line(static_cast(x2 - 1), static_cast(y2), static_cast(x3 - 1), static_cast(y3)); DEBUG_DRAW.Line(static_cast(x3), static_cast(y3), static_cast(x4), static_cast(y4)); DEBUG_DRAW.Line(static_cast(x4), static_cast(y4), static_cast(x1), static_cast(y1)); // draw translation DEBUG_DRAW.SetColour(Ogre::ColourValue(0, 1, 0, 1)); Ogre::Vector2 area_origin = (m_Parent != nullptr) ? m_Parent->GetFinalOrigin() : Ogre::Vector2::ZERO; Ogre::Vector2 area_translate = (m_Parent != nullptr) ? m_Parent->GetFinalTranslate() : Ogre::Vector2::ZERO; Ogre::Vector2 pos = area_translate - area_origin; DEBUG_DRAW.Line(pos.x, pos.y, x, y); DEBUG_DRAW.Quad(x - 2, y - 2, x + 2, y - 2, x + 2, y + 2, x - 2, y + 2); if(cv_debug_ui.GetI() >= 2) { DEBUG_DRAW.SetColour(Ogre::ColourValue::White); DEBUG_DRAW.SetTextAlignment(DEBUG_DRAW.LEFT); DEBUG_DRAW.Text(static_cast(x1 + 3), static_cast(y1), m_PathName); DEBUG_DRAW.Text(static_cast(x1 + 3), static_cast(y1 + 12), GetCurrentAnimationName()); } // draw origin DEBUG_DRAW.SetColour(Ogre::ColourValue(1, 0, 0, 1)); DEBUG_DRAW.Line(x, y, static_cast(x1), static_cast(y1 + 1)); } } void UiWidget::OnResize() { Ogre::Viewport *viewport(CameraManager::getSingleton().getViewport()); m_ScreenWidth = static_cast(viewport->getActualWidth()); m_ScreenHeight = static_cast(viewport->getActualHeight()); for(size_t i = 0; i < m_Children.size(); ++i) { m_Children[i]->OnResize(); } m_UpdateTransformation = true; } void UiWidget::Render() { if(m_Visible == true) { for(size_t i = 0; i < m_Children.size(); ++i) { m_Children[i]->Render(); } } } void UiWidget::SetVisible(const bool visible) { m_Visible = visible; } bool UiWidget::IsVisible() const { return m_Visible; } const Ogre::String& UiWidget::GetName() const { return m_Name; } void UiWidget::AddChild(UiWidget *widget) { m_Children.push_back(widget); } UiWidget* UiWidget::GetChild(const Ogre::String& name) { for(size_t i = 0; i < m_Children.size(); ++i) { if(m_Children[i]->GetName() == name) { return m_Children[i]; } } return nullptr; } void UiWidget::RemoveAllChildren() { for(size_t i = 0; i < m_Children.size(); ++i) { delete m_Children[i]; } m_Children.clear(); } void UiWidget::AddAnimation(UiAnimation* animation) { m_Animations.push_back(animation); } const Ogre::String& UiWidget::GetCurrentAnimationName() const { if(m_AnimationCurrent != nullptr) { return m_AnimationCurrent->GetName(); } return Ogre::StringUtil::BLANK; } void UiWidget::PlayAnimation(const Ogre::String& animation, UiAnimation::State state, const float start, const float end) { for(size_t i = 0; i < m_Animations.size(); ++i) { if(m_Animations[i]->GetName() == animation) { m_AnimationCurrent = m_Animations[i]; m_AnimationCurrent->SetTime((start == -1) ? m_AnimationCurrent->GetLength() : start); m_AnimationCurrent->AddTime(0); m_AnimationEndTime = (end == -1) ? m_AnimationCurrent->GetLength() : end; m_AnimationState = state; return; } } // stop current state and animation m_AnimationCurrent = nullptr; m_AnimationState = UiAnimation::ONCE; LOG_ERROR("Widget '" + m_Name + "' doesn't has animation '" + animation + "'."); } void UiWidget::ScriptPlayAnimation(const char* name) { PlayAnimation(Ogre::String(name), UiAnimation::DEFAULT, 0, -1); } void UiWidget::ScriptPlayAnimationStop(const char* name) { PlayAnimation(Ogre::String(name), UiAnimation::ONCE, 0, -1); } void UiWidget::ScriptPlayAnimation(const char* name, const float start, const float end) { PlayAnimation(Ogre::String(name), UiAnimation::DEFAULT, start, end); } void UiWidget::ScriptPlayAnimationStop(const char* name, const float start, const float end) { PlayAnimation(Ogre::String(name), UiAnimation::ONCE, start, end); } void UiWidget::ScriptSetDefaultAnimation(const char* animation) { m_AnimationDefault = Ogre::String(animation); m_AnimationState = UiAnimation::DEFAULT; } int UiWidget::ScriptAnimationSync() { ScriptId script = ScriptManager::getSingleton().GetCurrentScriptId(); m_AnimationSync.push_back(script); return -1; } void UiWidget::UpdateTransformation() { Ogre::Vector2 area_scale = (m_Parent != nullptr) ? m_Parent->GetFinalScale() : Ogre::Vector2(1, 1); Ogre::Vector2 area_origin = (m_Parent != nullptr) ? m_Parent->GetFinalOrigin() : Ogre::Vector2::ZERO; Ogre::Vector2 area_translate = (m_Parent != nullptr) ? m_Parent->GetFinalTranslate() : Ogre::Vector2::ZERO; Ogre::Vector2 area_size = (m_Parent != nullptr) ? m_Parent->GetFinalSize() : Ogre::Vector2(m_ScreenWidth, m_ScreenHeight); float area_rotation = (m_Parent != nullptr) ? m_Parent->GetFinalRotation() : 0; float local_x = ((area_size.x * m_XPercent) / 100.0f + (m_X * m_ScreenHeight / 720.0f) * area_scale.x) - area_origin.x; float local_y = ((area_size.y * m_YPercent) / 100.0f + (m_Y * m_ScreenHeight / 720.0f) * area_scale.y) - area_origin.y; float x = local_x; float y = local_y; if(area_rotation != 0) { float cos = Ogre::Math::Cos(Ogre::Radian(Ogre::Degree(area_rotation))); float sin = Ogre::Math::Sin(Ogre::Radian(Ogre::Degree(area_rotation))); x = local_x * cos - local_y * sin; y = local_x * sin + local_y * cos; } m_FinalTranslate.x = area_translate.x; if(m_Align == RIGHT) { m_FinalTranslate.x = area_translate.x + area_size.x; } else if(m_Align == CENTER) { m_FinalTranslate.x = area_translate.x + area_size.x / 2; } m_FinalTranslate.x += x; m_FinalTranslate.y = area_translate.y; if(m_VerticalAlign == BOTTOM) { m_FinalTranslate.y = area_translate.y + area_size.y; } else if(m_VerticalAlign == MIDDLE) { m_FinalTranslate.y = area_translate.y + area_size.y / 2; } m_FinalTranslate.y += y; m_FinalZ = (m_Parent != nullptr) ? m_Parent->GetFinalZ() + m_Z : m_Z; m_FinalScale = area_scale * m_Scale; m_FinalSize.x = (area_size.x * m_WidthPercent * m_Scale.x) / 100.0f + (m_Width * m_ScreenHeight / 720.0f) * m_FinalScale.x; m_FinalSize.y = (area_size.y * m_HeightPercent * m_Scale.y) / 100.0f + (m_Height * m_ScreenHeight / 720.0f) * m_FinalScale.y; m_FinalOrigin.x = (m_FinalSize.x * m_OriginXPercent) / 100.0f + m_OriginX * m_ScreenHeight * m_FinalScale.x / 720.0f; m_FinalOrigin.y = (m_FinalSize.y * m_OriginYPercent) / 100.0f + m_OriginY * m_ScreenHeight * m_FinalScale.y / 720.0f; m_FinalRotation = area_rotation + m_Rotation; // scissor update m_ScissorTop = (m_Parent != nullptr) ? m_Parent->GetScissorTop() : 0; m_ScissorBottom = (m_Parent != nullptr) ? m_Parent->GetScissorBottom() : static_cast(m_ScreenHeight); m_ScissorLeft = (m_Parent != nullptr) ? m_Parent->GetScissorLeft() : 0; m_ScissorRight = (m_Parent != nullptr) ? m_Parent->GetScissorRight() : static_cast(m_ScreenWidth); if(m_Scissor == true) { float local_x1 = -m_FinalOrigin.x; float local_y1 = -m_FinalOrigin.y; float local_x2 = m_FinalSize.x + local_x1; float local_y2 = m_FinalSize.y + local_y1; float x = m_FinalTranslate.x; float y = m_FinalTranslate.y; 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); } m_ScissorTop = std::max(m_ScissorTop, std::min(std::min(y1 , y2), std::min(y3 , y4))); m_ScissorBottom = std::min(m_ScissorBottom, std::max(std::max(y1 , y2), std::max(y3 , y4))); m_ScissorLeft = std::max(m_ScissorLeft, std::min(std::min(x1 , x2), std::min(x3 , x4))); m_ScissorRight = std::min(m_ScissorRight, std::max(std::max(x1 , x2), std::max(x3 , x4))); } m_UpdateTransformation = false; for(size_t i = 0; i < m_Children.size(); ++i) { m_Children[i]->UpdateTransformation(); } } void UiWidget::SetAlign(const UiWidget::Align align) { m_Align = align; } void UiWidget::SetVerticalAlign(const UiWidget::VerticalAlign valign) { m_VerticalAlign = valign; } float UiWidget::GetFinalZ() const { return m_FinalZ; } Ogre::Vector2 UiWidget::GetFinalOrigin() const { return m_FinalOrigin; } Ogre::Vector2 UiWidget::GetFinalTranslate() const { return m_FinalTranslate; } Ogre::Vector2 UiWidget::GetFinalSize() const { return m_FinalSize; } Ogre::Vector2 UiWidget::GetFinalScale() const { return m_FinalScale; } float UiWidget::GetFinalRotation() const { return m_FinalRotation; } void UiWidget::SetOriginX(const float percent, const float x) { m_OriginXPercent = percent; m_OriginX = x; m_UpdateTransformation = true; } void UiWidget::SetOriginY(const float percent, const float y) { m_OriginYPercent = percent; m_OriginY = y; m_UpdateTransformation = true; } void UiWidget::SetX(const float percent, const float x) { m_XPercent = percent; m_X = x; m_UpdateTransformation = true; } void UiWidget::SetY(const float percent, const float y) { m_YPercent = percent; m_Y = y; m_UpdateTransformation = true; } void UiWidget::SetZ(const float z) { m_Z = z; m_UpdateTransformation = true; } void UiWidget::SetWidth(const float percent, const float width) { m_WidthPercent = percent; m_Width = width; m_UpdateTransformation = true; } void UiWidget::SetHeight(const float percent, const float height) { m_HeightPercent = percent; m_Height = height; m_UpdateTransformation = true; } void UiWidget::SetScale(const Ogre::Vector2& scale) { m_Scale = scale; m_UpdateTransformation = true; } void UiWidget::SetRotation(const float degree) { m_Rotation = degree; m_UpdateTransformation = true; } void UiWidget::SetScissor(bool scissor) { m_Scissor = scissor; m_UpdateTransformation = true; } int UiWidget::GetScissorTop() const { return m_ScissorTop; } int UiWidget::GetScissorBottom() const { return m_ScissorBottom; } int UiWidget::GetScissorLeft() const { return m_ScissorLeft; } int UiWidget::GetScissorRight() const { return m_ScissorRight; } void UiWidget::SetColour(const float r, const float g, const float b) { m_Colour1.r = r; m_Colour1.g = g; m_Colour1.b = b; m_Colour2.r = r; m_Colour2.g = g; m_Colour2.b = b; m_Colour3.r = r; m_Colour3.g = g; m_Colour3.b = b; m_Colour4.r = r; m_Colour4.g = g; m_Colour4.b = b; m_UpdateTransformation = true; } void UiWidget::SetColours(const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, const float r3, const float g3, const float b3, const float r4, const float g4, const float b4) { m_Colour1.r = r1; m_Colour1.g = g1; m_Colour1.b = b1; m_Colour2.r = r2; m_Colour2.g = g2; m_Colour2.b = b2; m_Colour3.r = r3; m_Colour3.g = g3; m_Colour3.b = b3; m_Colour4.r = r4; m_Colour4.g = g4; m_Colour4.b = b4; m_UpdateTransformation = true; } void UiWidget::SetAlpha(const float a) { m_Colour1.a = a; m_Colour2.a = a; m_Colour3.a = a; m_Colour4.a = a; m_UpdateTransformation = true; }