#include "CGuiFrame.hpp" #include "CGuiWidget.hpp" #include "CGuiSys.hpp" #include "CGuiHeadWidget.hpp" #include "CGuiAnimController.hpp" #include "CGuiMessage.hpp" #include "CGuiLight.hpp" #include "CGuiCamera.hpp" #include "Graphics/CGraphics.hpp" #include "Input/CFinalInput.hpp" #include "zeus/CColor.hpp" namespace urde { CGuiFrame::CGuiFrame(ResId id, const std::string& name, CGuiSys& sys, int a, int b, int c) : x4_name(name), x14_id(id), x1c_transitionOpts(EFrameTransitionOptions::Zero), x3c_guiSys(sys), xb0_a(a), xb4_b(b), xb8_c(c), xbc_24_loaded(false) { xa0_lights.resize(8); x48_rootWidget.reset(new CGuiWidget( CGuiWidget::CGuiWidgetParms(this, false, 0, 0, false, false, false, zeus::CColor::skWhite, CGuiWidget::EGuiModelDrawFlags::Alpha, false, x3c_guiSys.x2c_mode != CGuiSys::EUsageMode::Zero))); } CGuiWidget* CGuiFrame::FindWidget(const std::string& name) const { s16 id = x64_idDB.FindWidgetID(name); if (id == -1) return nullptr; return FindWidget(id); } CGuiWidget* CGuiFrame::FindWidget(s16 id) const { return x48_rootWidget->FindWidget(id); } void CGuiFrame::ResetControllerStatus() { x0_controllerStatus[0] = false; x0_controllerStatus[1] = false; x0_controllerStatus[2] = false; x0_controllerStatus[3] = false; } void CGuiFrame::InterpretGUIControllerState(const CFinalInput& input, CGuiPhysicalMsg::PhysicalMap& state, char& lx, char& ly, char& rx, char& ry) { zeus::CVector2f left(std::fabs(input.ALeftX()), std::fabs(input.ALeftY())); bool leftThreshold = false; if (left.magnitude() >= 0.6f) leftThreshold = true; zeus::CVector2f right(std::fabs(input.ARightX()), std::fabs(input.ARightY())); bool rightThreshold = false; if (right.magnitude() >= 0.6f) rightThreshold = true; if (leftThreshold) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickThreshold, false); if (input.ALeftX() < 0.f) lx = input.ALeftX() * 128.f; else lx = input.ALeftX() * 127.f; if (input.ALeftY() < 0.f) ly = input.ALeftY() * 128.f; else ly = input.ALeftY() * 127.f; if (0.7f < input.ALeftY()) { if (input.PLAUp()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickUpInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftUpInst, false); } CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickUp, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftUp, false); } if (-0.7f > input.ALeftY()) { if (input.PLADown()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickDownInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftDownInst, false); } CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickDown, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftDown, false); } if (0.7f < input.ALeftX()) { if (input.PLARight()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickRightInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftRightInst, false); } CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickRight, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftRight, false); } if (-0.7f > input.ALeftX()) { if (input.PLALeft()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickLeftInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftLeftInst, false); } CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickLeft, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftLeft, false); } } else { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftStickRelease, false); lx = 0; ly = 0; } if (rightThreshold) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickThreshold, false); if (input.ARightX() < 0.f) rx = input.ARightX() * 128.f; else rx = input.ARightX() * 127.f; if (input.ARightY() < 0.f) ry = input.ARightY() * 128.f; else ry = input.ARightY() * 127.f; if (0.7f < input.ARightY()) { if (input.PRAUp()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickUpInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickUp, false); } if (-0.7f > input.ARightY()) { if (input.PRADown()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickDownInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickDown, false); } if (0.7f < input.ARightX()) { if (input.PRARight()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickRightInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickRight, false); } if (-0.7f > input.ARightX()) { if (input.PRALeft()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickLeftInst, false); CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickLeft, false); } } else { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RightStickRelease, false); rx = 0; ry = 0; } if (input.PDPUp()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadUpInst, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftUpInst, false); } else if (input.DDPUp()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadUp, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftUp, false); } if (input.PDPDown()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadDownInst, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftDownInst, false); } else if (input.DDPDown()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadDown, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftDown, false); } if (input.PDPRight()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadRightInst, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftRightInst, false); } else if (input.DDPRight()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadRight, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftRight, false); } if (input.PDPLeft()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadLeftInst, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftLeftInst, false); } else if (input.DDPLeft()) { CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::DPadLeft, false); if (leftThreshold) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LeftLeft, false); } if (input.PStart()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::StartInst, false); if (input.DStart()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::Start, false); if (input.PB()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::BInst, false); if (input.DB()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::B, false); if (input.PA()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::AInst, false); if (input.DA()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::A, false); if (input.PX()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::XInst, false); if (input.DX()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::X, false); if (input.PY()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::YInst, false); if (input.DY()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::Y, false); if (input.PZ()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::ZInst, false); if (input.DZ()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::Z, false); if (input.PLTrigger()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::LInst, false); if (input.DLTrigger()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::L, false); if (input.PRTrigger()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::RInst, false); if (input.DRTrigger()) CGuiPhysicalMsg::AddControllerID(state, EPhysicalControllerID::R, false); } CGuiFrame::WidgetToLogicalEventMap* CGuiFrame::FindWidget2LogicalEventMap(u64 events) { auto search = x7c_messageMap.find(events); if (search == x7c_messageMap.cend()) return nullptr; return search->second.get(); } CGuiFrame::LogicalEventList* CGuiFrame::FindLogicalEventList(u64 events, s16 id) { CGuiFrame::WidgetToLogicalEventMap* map = FindWidget2LogicalEventMap(events); if (!map) return nullptr; auto search = map->find(id); if (search == map->cend()) return nullptr; return search->second.get(); } bool CGuiFrame::SendWidgetMessage(s16 id, std::list>& list, CGuiPhysicalMsg::PhysicalMap& state, CGuiControllerInfo::CGuiControllerStateInfo& csInfo) { CGuiWidget* widget = FindWidget(id); for (std::unique_ptr& node : list) { CGuiMessage msg(CGuiMessage::Type(node->GetTrigger().GetTriggerId()), reinterpret_cast(&state), reinterpret_cast(&csInfo)); if (!widget->Message(msg)) return false; } return true; } void CGuiFrame::ClearAllMessageMap() { x7c_messageMap.clear(); } void CGuiFrame::ClearMessageMap(const CGuiLogicalEventTrigger* trigger, s16 id) { CGuiFrame::LogicalEventList* list = FindLogicalEventList(trigger->GetPhysicalMsg().x0_curStates, id); if (list) list->clear(); } void CGuiFrame::AddMessageMap(const CGuiLogicalEventTrigger* trigger, s16 id) { u64 events = trigger->GetPhysicalMsg().x0_curStates; int triggerId = trigger->GetTriggerId(); CGuiFrame::WidgetToLogicalEventMap* map = FindWidget2LogicalEventMap(events); if (!map) { auto it = x7c_messageMap.emplace(std::make_pair(events, std::make_unique())); map = it.first->second.get(); } CGuiFrame::LogicalEventList* list = FindLogicalEventList(events, id); if (!list) { auto it = map->emplace(std::make_pair(id, std::make_unique())); list = it.first->second.get(); } for (std::unique_ptr& node : *list) if (node->GetTrigger().GetTriggerId() == triggerId) return; list->push_back(std::make_unique(trigger->GetPhysicalMsg(), triggerId)); } void CGuiFrame::SortDrawOrder() { std::sort(x90_widgets.begin(), x90_widgets.end(), [](const CGuiWidget* a, const CGuiWidget* b) -> bool { return a->GetWorldPosition().y < b->GetWorldPosition().y; }); } void CGuiFrame::EnableLights(u32 lights) const { CGraphics::DisableAllLights(); zeus::CColor accumColor(zeus::CColor::skBlack); ERglLight lightId = ERglLight::Zero; int idx = 0; for (CGuiLight* light : xa0_lights) { if ((lights & (1 << idx)) != 0) { // accumulate color accumColor += light->GetColor(); CGraphics::LoadLight(lightId, light->BuildLight()); CGraphics::EnableLight(lightId); } ++reinterpret_cast&>(lightId); ++idx; } if (xa0_lights.empty()) CGraphics::SetAmbientColor(zeus::CColor::skWhite); else CGraphics::SetAmbientColor(accumColor); } void CGuiFrame::DisableLights() const { CGraphics::DisableAllLights(); } void CGuiFrame::RemoveLight(CGuiLight* light) { xa0_lights[light->GetLoadedIdx()] = nullptr; } void CGuiFrame::AddLight(CGuiLight* light) { xa0_lights[light->GetLoadedIdx()] = light; } bool CGuiFrame::GetIsFinishedLoading() const { if (xbc_24_loaded) return true; for (const CGuiWidget* widget : x90_widgets) { if (widget->GetIsFinishedLoading()) continue; return false; } ((CGuiFrame*)this)->xbc_24_loaded = true; return true; } void CGuiFrame::Touch() const { for (const CGuiWidget* widget : x90_widgets) widget->Touch(); } void CGuiFrame::ProcessControllerInput(const CFinalInput& input) { if (x18_ & 0x4 && input.ControllerIdx() == 0) { CGuiPhysicalMsg::PhysicalMap state; CGuiControllerInfo::CGuiControllerStateInfo stateInfo; stateInfo.cIdx = input.ControllerIdx(); InterpretGUIControllerState(input, state, stateInfo.lx, stateInfo.ly, stateInfo.rx, stateInfo.ry); float eventTime = std::chrono::duration_cast( std::chrono::steady_clock::now() - x3c_guiSys.x40_constructTime).count() / 1000000.f; for (const std::pair& newPair : state) { auto search = x3c_guiSys.GetRepeatMap().find(newPair.first); if (search != x3c_guiSys.GetRepeatMap().end()) search->second.SetActive(input.ControllerIdx(), eventTime); } for (std::pair& pair : x3c_guiSys.GetRepeatMap()) { pair.second.AddAutoEvent(input.ControllerIdx(), state, eventTime); } CGuiPhysicalMsg msg(state); SetControllerStatus(input.ControllerIdx(), true); for (std::pair>& outer : x7c_messageMap) { if (outer.second) { for (std::pair>& inner : *outer.second) { if (inner.second && inner.second->size()) { LogicalEventList& list = *inner.second; if (msg.Exists(list.back()->GetTrigger().GetPhysicalMsg())) if (!SendWidgetMessage(inner.first, list, state, stateInfo)) break; } } } } } } bool CGuiFrame::Update(float dt) { if (x34_ != EFrameStates::Four) return false; if (x18_ & 2) { EGuiAnimBehListID listId = EGuiAnimBehListID::NegOne; bool something = true; x44_headWidget->InitializeRGBAFactor(); x44_headWidget->Update(dt); x44_headWidget->RecalculateAllRGBA(); switch (x34_) { case EFrameStates::One: if (!xbd_flag2) { CGuiControllerInfo cInfo; x44_headWidget->BroadcastMessage(0, &cInfo); xbd_flag2 = true; } break; case EFrameStates::Three: listId = EGuiAnimBehListID::One; break; default: break; } if (listId != EGuiAnimBehListID::NegOne) x44_headWidget->IsAllAnimsDone(listId, something, ETraversalMode::ChildrenAndSiblings); if (something) { switch (x34_) { case EFrameStates::One: { x34_ = x38_; x44_headWidget->SetAnimUpdateState(EGuiAnimBehListID::Zero, false, ETraversalMode::Single); x44_headWidget->InitializeAnimControllers(EGuiAnimBehListID::Two, 0.f, false, EGuiAnimInitMode::Five, ETraversalMode::Single); CGuiWidget* camSib = static_cast(x4c_camera->GetNextSibling()); if (camSib) { camSib->SetAnimUpdateState(EGuiAnimBehListID::Zero, false, ETraversalMode::ChildrenAndSiblings); camSib->InitializeAnimControllers(EGuiAnimBehListID::Two, 0.f, false, EGuiAnimInitMode::Five, ETraversalMode::ChildrenAndSiblings); } xbd_flag2 = false; break; } case EFrameStates::Three: { CGuiControllerInfo cInfo; x44_headWidget->BroadcastMessage(1, &cInfo); ClearAllMessageMap(); x18_ &= ~0x3; x44_headWidget->ResetAllAnimUpdateState(); xbd_flag2 = false; break; } default: break; } } return x34_ != EFrameStates::Zero; } return false; } void CGuiFrame::Draw(const CGuiWidgetDrawParms& parms) const { if (x18_) { CGraphics::SetCullMode(ERglCullMode::None); CGraphics::SetAmbientColor(zeus::CColor::skWhite); DisableLights(); x4c_camera->Draw(parms); // Set one-stage modulate CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, ERglLogicOp::Clear); if (x50_background) x50_background->Draw(parms); for (const CGuiWidget* widget : x90_widgets) if (widget->GetIsVisible()) widget->Draw(parms); } CGraphics::SetCullMode(ERglCullMode::Front); } void CGuiFrame::Stop(const CGuiFrameTransitionOptions& transOpts, EFrameStates states, bool flag) { x18_ &= 0xFFFFFFFB; x38_ = states; if (flag) x34_ = x38_; else { x44_headWidget->InitializeAnimControllers(EGuiAnimBehListID::One, transOpts.xc_, true, EGuiAnimInitMode::Two, ETraversalMode::Single); CGuiWidget* camSib = static_cast(x4c_camera->GetNextSibling()); if (camSib) { camSib->InitializeAnimControllers(EGuiAnimBehListID::One, transOpts.xc_, true, EGuiAnimInitMode::Two, ETraversalMode::ChildrenAndSiblings); } } } void CGuiFrame::Run(CGuiFrame* frame, const CGuiFrameTransitionOptions& transOpts, EFrameStates states, bool flag) { ResetControllerStatus(); x34_ = EFrameStates::One; x38_ = EFrameStates::Two; float len = 0.f; x4c_camera->GetBranchAnimLen(EGuiAnimBehListID::Zero, len, ETraversalMode::Single); len += transOpts.xc_ + transOpts.x10_ + transOpts.x14_; x44_headWidget->InitializeAnimControllers(EGuiAnimBehListID::Zero, len, true, EGuiAnimInitMode::One, ETraversalMode::Single); CGuiWidget* camSib = static_cast(x4c_camera->GetNextSibling()); if (camSib) { camSib->InitializeAnimControllers(EGuiAnimBehListID::Zero, len, true, EGuiAnimInitMode::One, ETraversalMode::ChildrenAndSiblings); } x18_ |= 0x7; x44_headWidget->RegisterEventHandler(ETraversalMode::ChildrenAndSiblings); } void CGuiFrame::Initialize() { SortDrawOrder(); x44_headWidget->SetColor(x44_headWidget->xbc_color); x44_headWidget->InitializeRecursive(); } void CGuiFrame::LoadWidgetsInGame(CInputStream& in) { u32 count = in.readUint32Big(); x90_widgets.reserve(count); for (u32 i=0 ; iGetWidgetTypeID(); switch (type) { case SBIG('CAMR'): case SBIG('LITE'): case SBIG('BGND'): break; default: x90_widgets.push_back(widget); break; } } Initialize(); } CGuiFrame* CGuiFrame::CreateFrame(ResId frmeId, CGuiSys& sys, CInputStream& in) { std::string name = CreateFrameName(frmeId); in.readInt32Big(); int a = in.readInt32Big(); int b = in.readInt32Big(); int c = in.readInt32Big(); CGuiFrame* ret = new CGuiFrame(frmeId, name, sys, a, b, c); ret->LoadWidgetsInGame(in); return ret; } std::unique_ptr RGuiFrameFactoryInGame(const SObjectTag& tag, CInputStream& in, const CVParamTransfer&) { std::unique_ptr frame(CGuiFrame::CreateFrame(tag.id, *g_GuiSys, in)); return TToken::GetIObjObjectFor(std::move(frame)); } std::string CGuiFrame::CreateFrameName(ResId frmeId) { /* formatting token originally "frame_%x" for 32-bit ids */ return hecl::Format("frame_%016" PRIX64, frmeId); } }