#include "m/m2d.h" #include "egg/core/eggExpHeap.h" #include "egg/core/eggHeap.h" #include "egg/gfx/eggScreen.h" #include "nw4r/lyt/lyt_init.h" #include "rvl/GX.h" // IWYU pragma: export #include "rvl/SC.h" // IWYU pragma: export namespace m2d { nw4r::ut::List l_list; mAllocator_c *l_allocator; void reset() { nw4r::ut::List_Init(&l_list, 0); } bool init(mAllocator_c *allocator) { nw4r::lyt::LytInit(); l_allocator = allocator; nw4r::lyt::Layout::mspAllocator = allocator; reset(); return true; } void create(EGG::Heap *heap, u32 size) { if (size != 0) { heap = EGG::ExpHeap::create(size, heap, 0); heap->setName("2D表示用ヒープ(m2d::create)"); } mAllocator_c *allocator = new (heap, 0x04) mAllocator_c(); allocator->attach(heap, 4); init(allocator); } // TODO This is literally the first sbss2 symbol. extern "C" GXColor lbl_8057FFA0; void defaultSet() { GXSetCullMode(GX_CULL_NONE); GXSetZMode(false, GX_ALWAYS, false); GXSetFog(GX_FOG_NONE, lbl_8057FFA0, 0.0f, 0.0f, 0.0f, 0.0f); } void draw(u8 priority) { for (Base_c *base = static_cast(nw4r::ut::List_GetFirst(&l_list)); base != nullptr; base = static_cast(nw4r::ut::List_GetNext(&l_list, base))) { if (base->getPriority() >= priority) { break; } base->draw(); } } void drawBefore(u8 priority) { for (Base_c *base = static_cast(nw4r::ut::List_GetFirst(&l_list)); base != nullptr; base = static_cast(nw4r::ut::List_GetNext(&l_list, base))) { if (base->getPriority() > priority) { base->draw(); } } } void setLytAllocator() { nw4r::lyt::Layout::mspAllocator = l_allocator; } nw4r::lyt::AnimTransform *Layout_c::CreateAnimTransform(const void *animResBuf, nw4r::lyt::ResourceAccessor *pResAcsr) { nw4r::lyt::AnimTransform *result = nw4r::lyt::Layout::CreateAnimTransform(animResBuf, pResAcsr); if (result != nullptr) { GetAnimTransformList().Erase(result); } return result; } ResAccIfBase_c::~ResAccIfBase_c() {} ResAccIf_c::~ResAccIf_c() {} nw4r::lyt::ArcResourceAccessor *ResAccIf_c::getAccessor() { return &mAccessor; } void ResAccIf_c::noop() {} bool ResAccIf_c::attach(void *data, const char *name) { return mAccessor.Attach(data, name); } void ResAccIf_c::detach() { mAccessor.Detach(); } FrameCtrl_c::~FrameCtrl_c() {} void FrameCtrl_c::play() { mPrevFrame = mCurrFrame; f32 newFrame; if (isBackwards()) { if (mCurrFrame >= mRate) { newFrame = mCurrFrame - mRate; } else { if (notLooping()) { newFrame = 0.0f; } else { newFrame = mCurrFrame + (mEndFrame - mRate); } } } else { newFrame = mCurrFrame + mRate; if (notLooping()) { f32 forwardsEnd = mEndFrame - 1.0f; if (newFrame > forwardsEnd) { newFrame = forwardsEnd; } } else { if (newFrame >= mEndFrame) { newFrame = newFrame - mEndFrame; } } } mCurrFrame = newFrame; } void FrameCtrl_c::set(f32 endFrame, u8 flags, f32 rate, f32 currFrame) { if (currFrame < 0.0f) { currFrame = 0.0f; } mEndFrame = endFrame; mCurrFrame = currFrame; setRate(rate); mFlags = flags; mPrevFrame = mCurrFrame; } void FrameCtrl_c::setFrame(f32 frame) { mCurrFrame = frame; mPrevFrame = frame; } void FrameCtrl_c::setRate(f32 rate) { mRate = rate; } bool FrameCtrl_c::isStop() const { f32 actualEnd; switch (mFlags) { case FLAG_NO_LOOP: actualEnd = mEndFrame - 1.0f; return mCurrFrame >= actualEnd; case FLAG_NO_LOOP | FLAG_BACKWARDS: return mCurrFrame <= 0.0f; default: return false; } } f32 FrameCtrl_c::getStartFrame() const { if (isBackwards()) { if (notLooping()) { return mEndFrame - 1.0f; } return mEndFrame; } return 0.0f; } f32 FrameCtrl_c::getEndFrame() const { if (isBackwards()) { return 0.0f; } if (notLooping()) { return mEndFrame - 1.0f; } return mEndFrame; } bool FrameCtrl_c::isStop2() const { if (isBackwards()) { return mCurrFrame <= 0.0f; } if (notLooping()) { f32 actualEnd = mEndFrame - 1.0f; return mCurrFrame >= actualEnd; } return mCurrFrame >= mEndFrame; } Anm_c::~Anm_c() { destroySomething(); } bool Anm_c::doSomething(const char *path, ResAccIf_c *acc) { if (mpTransform != nullptr) { destroySomething(); } static Layout_c l_layout; void *resource = acc->getAccessor()->GetResource(0, path, nullptr); nw4r::lyt::AnimTransform *transform = l_layout.CreateAnimTransform(resource, acc->getAccessor()); if (transform == nullptr) { return false; } setTransform(transform); return true; } void Anm_c::setTransform(nw4r::lyt::AnimTransform *transform) { mpTransform = transform; u8 flags = 1; if (mpTransform->IsLoopData()) { flags = 0; } set(mpTransform->GetFrameSize(), flags, 1.0f, -1.0); } void Anm_c::destroySomething() { if (mpTransform != nullptr) { mpTransform->~AnimTransform(); nw4r::lyt::Layout::FreeMemory(mpTransform); mpTransform = nullptr; } } void Anm_c::set(f32 endFrame, u8 flags, f32 rate, f32 currFrame) { mFrameCtrl.set(endFrame, flags, rate, currFrame); updateFrame(); } void Anm_c::setFrame(f32 frame) { mFrameCtrl.setFrame(frame); updateFrame(); } void Anm_c::updateFrame() { mpTransform->SetFrame(mFrameCtrl.getFrame()); } void Anm_c::play() { mFrameCtrl.play(); updateFrame(); } Base_c::~Base_c() {} void Base_c::draw() {} void Base_c::addToDrawList() { Base_c *target = static_cast(nw4r::ut::List_GetFirst(&l_list)); while (target != nullptr) { if (target->mPriority > mPriority) { nw4r::ut::List_Insert(&l_list, target, this); return; } target = static_cast(nw4r::ut::List_GetNext(&l_list, target)); } nw4r::ut::List_Append(&l_list, this); } Simple_c::~Simple_c() {} Simple_c::Simple_c() : Base_c(0x80), mLayout(), mDrawInfo(), mpResAcc(nullptr), mVec(0.0f, 0.0f, 0.0f), field_0x94(0) { if (SCGetAspectRatio() == 1) { mDrawInfo.SetLocationAdjustScale(nw4r::math::VEC2(EGG::Screen::GetAdjustScale(), 1.0f)); mDrawInfo.SetLocationAdjust(true); } } void Simple_c::calc() { calcBefore(); nw4r::math::MTX34 mtx; MTXIdentity(mtx.m); // Probably inlines mVec3_c v = mVec; MTXTransApply(mtx.m, mtx.m, v.x, v.y, v.z); mDrawInfo.SetViewMtx(mtx); calcAfter(); } void Simple_c::calcBefore() { u32 flag = 0; if ((field_0x94 & 1) != 0) { flag = 1; } mLayout.Animate(flag); } void Simple_c::calcAfter() { mDrawInfo.SetViewRect(mLayout.GetLayoutRect()); mLayout.CalculateMtx(mDrawInfo); } void Simple_c::draw() { nw4r::ut::Rect r = mLayout.GetLayoutRect(); f32 near = 0.0f; f32 far = 500.0f; EGG::Screen s; bool needsAdjust = EGG::Screen::GetTVMode() == EGG::Screen::TV_MODE_16_9; f32 f1 = EGG::Screen::GetSizeXMax(EGG::Screen::TV_MODE_16_9); f32 f2 = EGG::Screen::GetSizeXMax(EGG::Screen::TV_MODE_4_3); f32 left = needsAdjust ? f1 * r.left / f2 : r.left; f32 right = needsAdjust ? f1 * r.right / f2 : r.right; s.SetProjectionType(EGG::Frustum::PROJ_ORTHO); s.ResetOrthographic(r.top, r.bottom, left, right, near, far); if (needsAdjust) { s.SetScale(nw4r::math::VEC3(f2 / f1, 1.0f, 1.0f)); } s.SetProjectionGX(); mLayout.Draw(mDrawInfo); } bool Simple_c::build(const char *name, ResAccIf_c *acc) { if (mLayout.GetRootPane() != nullptr) { return true; } if (acc == nullptr) { acc = mpResAcc; if (acc == nullptr) { return false; } } void *resource = acc->getAccessor()->GetResource(0, name, nullptr); if (resource == nullptr) { return false; } else { bool success = mLayout.Build(resource, acc->getAccessor()); if (success) { calc(); } return success; } } void Simple_c::bind(Anm_c *anm) { anm->setBound(); mLayout.BindAnimation(anm->getTransform()); } void Simple_c::unbind(Anm_c *anm) { anm->setUnbound(); mLayout.UnbindAnimation(anm->getTransform()); } } // namespace m2d