metaforce/Runtime/GuiSys/CGuiFrame.cpp

275 lines
8.9 KiB
C++
Raw Normal View History

#include "Runtime/GuiSys/CGuiFrame.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/GuiSys/CGuiCamera.hpp"
#include "Runtime/GuiSys/CGuiHeadWidget.hpp"
#include "Runtime/GuiSys/CGuiLight.hpp"
#include "Runtime/GuiSys/CGuiSys.hpp"
#include "Runtime/GuiSys/CGuiTableGroup.hpp"
#include "Runtime/GuiSys/CGuiWidget.hpp"
#include "Runtime/GuiSys/CGuiWidgetDrawParms.hpp"
#include "Runtime/Input/CFinalInput.hpp"
#include <zeus/CColor.hpp>
2016-03-11 05:32:18 +00:00
2021-04-10 08:42:06 +00:00
namespace metaforce {
2016-03-11 05:32:18 +00:00
2017-08-13 05:26:14 +00:00
CGuiFrame::CGuiFrame(CAssetId id, CGuiSys& sys, int a, int b, int c, CSimplePool* sp)
: x0_id(id), x8_guiSys(sys), x4c_a(a), x50_b(b), x54_c(c) {
2018-12-08 05:30:43 +00:00
x3c_lights.reserve(8);
m_indexedLights.reserve(8);
x10_rootWidget = std::make_unique<CGuiWidget>(CGuiWidget::CGuiWidgetParms(
this, false, 0, 0, false, false, false, zeus::skWhite, CGuiWidget::EGuiModelDrawFlags::Alpha, false,
x8_guiSys.x8_mode != CGuiSys::EUsageMode::Zero, "<root>"s));
2018-12-08 05:30:43 +00:00
x8_guiSys.m_registeredFrames.insert(this);
}
CGuiFrame::~CGuiFrame() { x8_guiSys.m_registeredFrames.erase(this); }
CGuiWidget* CGuiFrame::FindWidget(std::string_view name) const {
s16 id = x18_idDB.FindWidgetID(name);
if (id == -1)
return nullptr;
return FindWidget(id);
}
CGuiWidget* CGuiFrame::FindWidget(s16 id) const { return x10_rootWidget->FindWidget(id); }
void CGuiFrame::SortDrawOrder() {
std::sort(x2c_widgets.begin(), x2c_widgets.end(),
[](const std::shared_ptr<CGuiWidget>& a, const std::shared_ptr<CGuiWidget>& b) -> bool {
return a->GetWorldPosition().y() > b->GetWorldPosition().y();
});
}
void CGuiFrame::EnableLights(ERglLight lights) const {
2018-12-08 05:30:43 +00:00
CGraphics::DisableAllLights();
zeus::CColor ambColor(zeus::skBlack);
ERglLight lightId = 0;
int enabledLights = 0;
2018-12-08 05:30:43 +00:00
for (CGuiLight* light : m_indexedLights) {
if (light == nullptr || !light->GetIsVisible()) {
++lightId;
2018-12-08 05:30:43 +00:00
continue;
2016-03-15 04:55:57 +00:00
}
if ((lights & (1 << lightId)) != 0) {
const auto& geomCol = light->GetGeometryColor();
if (geomCol.r() != 0.f || geomCol.g() != 0.f || geomCol.b() != 0.f) {
CGraphics::LoadLight(lightId, light->BuildLight());
CGraphics::EnableLight(lightId);
}
2018-12-08 05:30:43 +00:00
// accumulate ambient color
ambColor += light->GetAmbientLightColor();
++enabledLights;
2017-04-13 19:28:31 +00:00
}
++lightId;
2018-12-08 05:30:43 +00:00
}
if (enabledLights == 0) {
CGraphics::SetAmbientColor(zeus::skWhite);
2018-12-08 05:30:43 +00:00
} else {
CGraphics::SetAmbientColor(ambColor);
2018-12-08 05:30:43 +00:00
}
2016-03-15 04:55:57 +00:00
}
2018-12-08 05:30:43 +00:00
void CGuiFrame::DisableLights() const { CGraphics::DisableAllLights(); }
2016-03-15 04:55:57 +00:00
2018-12-08 05:30:43 +00:00
void CGuiFrame::RemoveLight(CGuiLight* light) {
if (m_indexedLights.empty())
return;
m_indexedLights[light->GetLightId()] = nullptr;
2017-03-20 05:09:53 +00:00
}
2018-12-08 05:30:43 +00:00
void CGuiFrame::AddLight(CGuiLight* light) {
if (m_indexedLights.empty())
m_indexedLights.resize(8);
m_indexedLights[light->GetLightId()] = light;
2016-03-15 04:55:57 +00:00
}
2018-12-08 05:30:43 +00:00
void CGuiFrame::RegisterLight(std::shared_ptr<CGuiLight>&& light) { x3c_lights.push_back(std::move(light)); }
2016-03-15 04:55:57 +00:00
2018-12-08 05:30:43 +00:00
bool CGuiFrame::GetIsFinishedLoading() const {
if (x58_24_loaded)
2016-03-15 04:55:57 +00:00
return true;
2018-12-08 05:30:43 +00:00
for (const auto& widget : x2c_widgets) {
if (widget->GetIsFinishedLoading())
continue;
return false;
}
x58_24_loaded = true;
2018-12-08 05:30:43 +00:00
return true;
}
void CGuiFrame::Touch() const {
for (const auto& widget : x2c_widgets)
widget->Touch();
}
void CGuiFrame::SetAspectConstraint(float c) {
m_aspectConstraint = c;
CGuiSys::ViewportResizeFrame(this);
}
void CGuiFrame::SetMaxAspect(float c) {
m_maxAspect = c;
CGuiSys::ViewportResizeFrame(this);
}
2021-06-07 19:29:18 +00:00
void CGuiFrame::Reset() { x10_rootWidget->Reset(ETraversalMode::Children); }
2018-12-08 05:30:43 +00:00
void CGuiFrame::Update(float dt) { xc_headWidget->Update(dt); }
void CGuiFrame::Draw(const CGuiWidgetDrawParms& parms) const {
2020-04-11 22:51:39 +00:00
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CGuiFrame::Draw FRME_{}"), x0_id).c_str(), zeus::skMagenta);
2018-12-08 05:30:43 +00:00
CGraphics::SetCullMode(ERglCullMode::None);
CGraphics::SetAmbientColor(zeus::skWhite);
2018-12-08 05:30:43 +00:00
DisableLights();
x14_camera->Draw(parms);
// Set one-stage modulate
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
ERglLogicOp::Clear);
for (const auto& widget : x2c_widgets)
if (widget->GetIsVisible())
widget->Draw(parms);
CGraphics::SetCullMode(ERglCullMode::Front);
}
2019-01-20 06:43:11 +00:00
CGuiWidget* CGuiFrame::BestCursorHit(const zeus::CVector2f& point, const CGuiWidgetDrawParms& parms) const {
x14_camera->Draw(parms);
zeus::CMatrix4f vp = CGraphics::GetPerspectiveProjectionMatrix() * CGraphics::g_CameraMatrix.toMatrix4f();
2019-01-20 06:43:11 +00:00
CGuiWidget* ret = nullptr;
for (const auto& widget : x2c_widgets)
if (widget->GetMouseActive() && widget->TestCursorHit(vp, point))
ret = widget.get();
return ret;
}
2018-12-08 05:30:43 +00:00
void CGuiFrame::Initialize() {
SortDrawOrder();
xc_headWidget->SetColor(xc_headWidget->xa4_color);
xc_headWidget->DispatchInitialize();
}
void CGuiFrame::LoadWidgetsInGame(CInputStream& in, CSimplePool* sp, u32 version) {
u32 count = in.ReadLong();
2018-12-08 05:30:43 +00:00
x2c_widgets.reserve(count);
for (u32 i = 0; i < count; ++i) {
FourCC type;
in.Get(reinterpret_cast<u8*>(&type), 4);
std::shared_ptr<CGuiWidget> widget = CGuiSys::CreateWidgetInGame(type.toUint32(), in, this, sp, version);
2022-02-16 05:21:24 +00:00
switch (widget->GetWidgetTypeID().toUint32()) {
2018-12-08 05:30:43 +00:00
case SBIG('CAMR'):
case SBIG('LITE'):
case SBIG('BGND'):
break;
default:
x2c_widgets.push_back(std::move(widget));
break;
2016-03-14 00:58:19 +00:00
}
2018-12-08 05:30:43 +00:00
}
Initialize();
2016-03-14 00:58:19 +00:00
}
2018-12-08 05:30:43 +00:00
void CGuiFrame::ProcessUserInput(const CFinalInput& input) const {
if (input.ControllerIdx() != 0) {
2019-01-21 04:10:34 +00:00
return;
}
for (const auto& widget : x2c_widgets) {
if (widget->GetIsActive()) {
2019-01-21 04:10:34 +00:00
widget->ProcessUserInput(input);
}
2019-01-21 04:10:34 +00:00
}
}
bool CGuiFrame::ProcessMouseInput(const CFinalInput& input, const CGuiWidgetDrawParms& parms) {
2019-01-20 06:43:11 +00:00
if (const auto& kbm = input.GetKBM()) {
2021-06-07 19:29:18 +00:00
zeus::CVector2f point(kbm->m_mouseCoord.norm[0] * 2.f - 1.f, kbm->m_mouseCoord.norm[1] * 2.f - 1.f);
2019-01-21 04:10:34 +00:00
CGuiWidget* hit = BestCursorHit(point, parms);
if (hit != m_lastMouseOverWidget) {
if (m_inMouseDown && m_mouseDownWidget != hit) {
m_inCancel = true;
if (m_mouseUpCb)
m_mouseUpCb(m_mouseDownWidget, true);
} else if (m_inCancel && m_mouseDownWidget == hit) {
m_inCancel = false;
if (m_mouseDownCb)
m_mouseDownCb(m_mouseDownWidget, true);
}
if (m_mouseOverChangeCb)
m_mouseOverChangeCb(m_lastMouseOverWidget, hit);
2019-01-22 04:23:51 +00:00
if (hit)
hit->m_lastScroll.emplace(kbm->m_accumScroll);
2019-01-21 04:10:34 +00:00
m_lastMouseOverWidget = hit;
}
2019-01-22 04:23:51 +00:00
if (hit && hit->m_lastScroll) {
SScrollDelta delta = kbm->m_accumScroll - *hit->m_lastScroll;
2019-01-22 04:23:51 +00:00
hit->m_lastScroll.emplace(kbm->m_accumScroll);
if (!delta.isZero()) {
hit->m_integerScroll += delta;
if (m_mouseScrollCb)
m_mouseScrollCb(hit, delta, int(hit->m_integerScroll.delta[0]), int(hit->m_integerScroll.delta[1]));
hit->m_integerScroll.delta[0] -= std::trunc(hit->m_integerScroll.delta[0]);
hit->m_integerScroll.delta[1] -= std::trunc(hit->m_integerScroll.delta[1]);
}
}
if (!m_inMouseDown && kbm->m_mouseButtons[size_t(EMouseButton::Primary)]) {
2019-01-20 06:43:11 +00:00
m_inMouseDown = true;
2019-01-21 04:10:34 +00:00
m_inCancel = false;
2019-01-20 06:43:11 +00:00
m_mouseDownWidget = hit;
if (m_mouseDownCb)
2019-01-21 04:10:34 +00:00
m_mouseDownCb(hit, false);
if (hit)
return true;
} else if (m_inMouseDown && !kbm->m_mouseButtons[size_t(EMouseButton::Primary)]) {
2019-01-20 06:43:11 +00:00
m_inMouseDown = false;
2019-01-21 04:10:34 +00:00
m_inCancel = false;
2019-01-22 04:23:51 +00:00
if (m_mouseDownWidget == m_lastMouseOverWidget) {
if (m_mouseDownWidget) {
if (CGuiTableGroup* p = static_cast<CGuiTableGroup*>(m_mouseDownWidget->GetParent())) {
if (p->GetWidgetTypeID() == FOURCC('TBGP')) {
s16 workerIdx = m_mouseDownWidget->GetWorkerId();
if (workerIdx >= 0)
p->DoSelectWorker(workerIdx);
}
}
}
2019-01-23 07:52:19 +00:00
if (m_mouseUpCb)
m_mouseUpCb(m_mouseDownWidget, false);
2019-01-22 04:23:51 +00:00
}
2019-01-20 06:43:11 +00:00
}
}
2019-01-21 04:10:34 +00:00
return false;
2016-12-16 04:35:49 +00:00
}
2019-01-23 07:52:19 +00:00
void CGuiFrame::ResetMouseState() {
m_inMouseDown = false;
m_inCancel = false;
m_mouseDownWidget = nullptr;
m_lastMouseOverWidget = nullptr;
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CGuiFrame> CGuiFrame::CreateFrame(CAssetId frmeId, CGuiSys& sys, CInputStream& in, CSimplePool* sp) {
u32 version = in.ReadLong();
int a = in.ReadLong();
int b = in.ReadLong();
int c = in.ReadLong();
2016-03-14 00:58:19 +00:00
2018-12-08 05:30:43 +00:00
std::unique_ptr<CGuiFrame> ret = std::make_unique<CGuiFrame>(frmeId, sys, a, b, c, sp);
ret->LoadWidgetsInGame(in, sp, version);
2018-12-08 05:30:43 +00:00
return ret;
2016-03-14 00:58:19 +00:00
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<IObj> RGuiFrameFactoryInGame(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& cvParms,
CObjectReference* selfRef) {
CSimplePool* sp = cvParms.GetOwnedObj<CSimplePool*>();
std::unique_ptr<CGuiFrame> frame(CGuiFrame::CreateFrame(tag.id, *g_GuiSys, in, sp));
return TToken<CGuiFrame>::GetIObjObjectFor(std::move(frame));
2016-03-16 20:49:35 +00:00
}
2021-04-10 08:42:06 +00:00
} // namespace metaforce