diff --git a/include/game/bases/d_SelectCursor.hpp b/include/game/bases/d_SelectCursor.hpp new file mode 100644 index 00000000..1ea95fcd --- /dev/null +++ b/include/game/bases/d_SelectCursor.hpp @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include +#include + +/// @brief A 2D layout element that adds little L-shaped rectangles around the +/// corners of a parent layout @ref nw4r::lyt::Pane. +class dSelectCursor_c : public dBase_c { + + /// @brief The null panes used in the layout. + /// @unofficial + enum N_PANE_e { + N_cursor_00, + N_LU_00, + N_RU_00, + N_LD_00, + N_RD_00, + N_COUNT + }; + + /// @brief The picture panes used in the layout. + /// @unofficial + enum P_PANE_e { + P_cursor_00, + P_cursor_01, + P_cursor_02, + P_cursor_03, + P_COUNT + }; + + /// @brief The animations used for the layout. + /// @unofficial + enum ANIM_e { + ANIM_CURSOR, + ANIM_COUNT + }; + +public: + class Layout_c { + public: + LytBase_c mBase; + nw4r::lyt::Pane *mpRootPane; ///< The root pane of the view. + nw4r::lyt::Picture *mpPicturePanes[P_COUNT]; ///< The picture panes of the view. + nw4r::lyt::Pane *mpNullPanes[N_COUNT]; ///< The null panes of the view. + bool mIsActive; ///< Whether the layout is drawn. + char mPaneName[100]; ///< The name of the parent pane. + nw4r::lyt::Size mPaneSize; ///< The size of the parent pane. + nw4r::lyt::Size mPaneOffset; ///< Always (0, 0). + mVec2_c mPaneGlbMtxScale; ///< The scale of the parent pane's global matrix. + mVec2_c mPaneGlbMtxTrans; ///< The transform of the parent pane's global matrix. + u8 mPad[4]; + mVec2_c mRootPaneOffset; ///< Always (0, 0). + float m_254; ///< Only set to 0, never read. + u8 mPaneBasePosH; + u8 mPaneBasePosV; + int mPaneAlpha; ///< The opacity of the N_cursor_00 pane. + bool mDoFade; ///< Always false. If set, it fades out the opacity of the N_cursor_00 pane then deactivates. + }; + + dSelectCursor_c(); + virtual ~dSelectCursor_c(); + + int create(); + int doDelete(); + int execute(); + int draw(); + + void PosSet(int layoutId); + void Cancel(int layoutId); + void SetPane(const nw4r::lyt::Pane *pane, int layoutId, bool dontSetAllDrawOrder); + void SetAlpha(const nw4r::lyt::Pane *pane, int layoutId); + + d2d::ResAccMultLoader_c mResLoader; + Layout_c mLayouts[5]; + bool mIsLoaded; + + static dSelectCursor_c *m_instance; +}; diff --git a/slices/wiimj2d.json b/slices/wiimj2d.json index 88e90d1b..9a92a41e 100644 --- a/slices/wiimj2d.json +++ b/slices/wiimj2d.json @@ -321,6 +321,17 @@ ".data": "0x1de58-0x1de68" } }, + { + "source": "dol/bases/d_SelectCursor.cpp", + "memoryRanges": { + ".data": "0x24348-0x24478", + ".sbss": "0x708-0x710", + ".sbss2": "0x18-0x20", + ".sdata": "0x1b88-0x1bb8", + ".sdata2": "0x2288-0x2290", + ".text": "0x1059b0-0x106360" + } + }, { "source": "dol/bases/d_SmallScoreManager.cpp", "memoryRanges": { diff --git a/source/dol/bases/d_SelectCursor.cpp b/source/dol/bases/d_SelectCursor.cpp new file mode 100644 index 00000000..91c3b212 --- /dev/null +++ b/source/dol/bases/d_SelectCursor.cpp @@ -0,0 +1,239 @@ +#include + +ACTOR_PROFILE(SELECT_CURSOR, dSelectCursor_c, 0); + +dSelectCursor_c *dSelectCursor_c::m_instance = nullptr; + +dSelectCursor_c::dSelectCursor_c() { + m_instance = this; + mIsLoaded = false; +} + +dSelectCursor_c::~dSelectCursor_c() { + dSelectCursor_c::m_instance = nullptr; +} + +int dSelectCursor_c::create() { + + static const char *AnmNameTbl[ANIM_COUNT] = { + "select_cursor_04_loopCursor.brlan" + }; + + static const char *GROUP_NAME_DT[ANIM_COUNT] = { + "A00_cursor" + }; + + static const int ANIME_INDEX_TBL[ANIM_COUNT] = { 0 }; + + static const char *PPANE_TABLE[P_COUNT] = { + "P_cursor_00", + "P_cursor_01", + "P_cursor_02", + "P_cursor_03" + }; + + static const char *NPANE_TABLE[N_COUNT] = { + "N_cursor_00", + "N_LU_00", + "N_RU_00", + "N_LD_00", + "N_RD_00" + }; + + + if (mIsLoaded) { + return SUCCEEDED; + } + + if (!mResLoader.request("Layout/select_cursor/select_cursor.arc")) { + return NOT_READY; + } + + for (int i = 0; i < ARRAY_SIZE(mLayouts); i++) { + mLayouts[i].mBase.mpResAccessor = &mResLoader; + } + + for (int i = 0; i < (int) ARRAY_SIZE(mLayouts); i++) { + mLayouts[i].mBase.build("select_cursor_04.brlyt", nullptr); + mLayouts[i].mBase.AnimeResRegister(AnmNameTbl, ANIM_COUNT); + mLayouts[i].mBase.GroupRegister(GROUP_NAME_DT, ANIME_INDEX_TBL, ANIM_COUNT); + mLayouts[i].mpRootPane = mLayouts[i].mBase.getRootPane(); + mLayouts[i].mBase.PPaneRegister(PPANE_TABLE, mLayouts[i].mpPicturePanes, P_COUNT); + mLayouts[i].mBase.NPaneRegister(NPANE_TABLE, mLayouts[i].mpNullPanes, N_COUNT); + mLayouts[i].mpRootPane->SetVisible(false); + + Cancel(i); + + if (i == 4) { + mLayouts[i].mBase.mDrawOrder = 14; + } else { + mLayouts[i].mBase.mDrawOrder = 147; + } + + mLayouts[i].mBase.LoopAnimeStartSetup(0); + } + + mIsLoaded = true; + + return SUCCEEDED; +} + + +int dSelectCursor_c::execute() { + for (int i = 0; i < (int) ARRAY_SIZE(mLayouts); i++) { + if (mLayouts[i].mIsActive) { + PosSet(i); + mLayouts[i].mBase.AnimePlay(); + mLayouts[i].mBase.calc(); + } + } + + return SUCCEEDED; +} + +int dSelectCursor_c::draw() { + for (int i = 0; i < (int) ARRAY_SIZE(mLayouts); i++) { + if (mLayouts[i].mIsActive) { + mLayouts[i].mBase.entry(); + } + } + + return SUCCEEDED; +} + +int dSelectCursor_c::doDelete() { + if (!mResLoader.remove()) { + return NOT_READY; + } + + for (int i = 0; i < (int) ARRAY_SIZE(mLayouts); i++) { + if (!mLayouts[i].mBase.doDelete()) { + return NOT_READY; + } + } + + return SUCCEEDED; +} + +void dSelectCursor_c::PosSet(int layoutId) { + mLayouts[layoutId].mpRootPane->SetVisible(true); + + mVec2_c pos; + float paneMidX, paneMidY, paneScaleX, paneScaleY; + + paneScaleX = mLayouts[layoutId].mPaneGlbMtxScale.x; + paneScaleY = mLayouts[layoutId].mPaneGlbMtxScale.y; + + paneMidX = mLayouts[layoutId].mPaneSize.width / 2.0f; + paneMidY = mLayouts[layoutId].mPaneSize.height / 2.0f; + + pos.x = mLayouts[layoutId].mPaneGlbMtxTrans.x + mLayouts[layoutId].mRootPaneOffset.x; + + if (mLayouts[layoutId].mPaneBasePosH == 0) { + pos.x += paneMidX * paneScaleX; + } else if (mLayouts[layoutId].mPaneBasePosH == 2) { + pos.x -= paneMidX * paneScaleX; + } + + pos.y = mLayouts[layoutId].mPaneGlbMtxTrans.y + mLayouts[layoutId].mRootPaneOffset.y; + if (mLayouts[layoutId].mPaneBasePosV == 0) { + pos.y -= paneMidY * paneScaleY; + } else if (mLayouts[layoutId].mPaneBasePosV == 2) { + pos.y += paneMidY * paneScaleY; + } + + mLayouts[layoutId].mpRootPane->SetTranslate(mVec3_c(pos, 0.0f)); + + float hOffset = mLayouts[layoutId].mPaneOffset.width; + float vOffset = mLayouts[layoutId].mPaneOffset.height; + for (int i = 1; i < ARRAY_SIZE(mLayouts); i++) { + mVec3_c pos2; + if ((i == 1) || (i == 3)) { + pos2.x = paneMidX * paneScaleX; + pos2.x = -pos2.x; + pos2.x -= hOffset; + } else { + pos2.x = paneMidX * paneScaleX; + pos2.x += hOffset; + } + + if ((i == 1) || (i == 2)) { + pos2.y = paneMidY * paneScaleY; + pos2.y += vOffset; + } else { + pos2.y = paneMidY * paneScaleY; + pos2.y = -pos2.y; + pos2.y -= vOffset; + } + + pos2.z = 0.0f; + mLayouts[layoutId].mpNullPanes[i]->SetTranslate(pos2); + } + + if (mLayouts[layoutId].mDoFade) { + mLayouts[layoutId].mPaneAlpha -= (255 / 10) + 1; + mLayouts[layoutId].mpNullPanes[0]->SetAlpha(mLayouts[layoutId].mPaneAlpha); + + if (mLayouts[layoutId].mPaneAlpha < 0) { + mLayouts[layoutId].mPaneAlpha = 0; + mLayouts[layoutId].mDoFade = false; + Cancel(layoutId); + } + } +} + +void dSelectCursor_c::Cancel(int layoutId) { + if (mLayouts[layoutId].mIsActive) { + mLayouts[layoutId].mIsActive = false; + strcpy(mLayouts[layoutId].mPaneName, ""); + mLayouts[layoutId].mpRootPane->SetVisible(false); + } +} + +void dSelectCursor_c::SetPane(const nw4r::lyt::Pane *pane, int layoutId, bool dontSetAllDrawOrder) { + mLayouts[layoutId].mIsActive = true; + + strcpy(mLayouts[layoutId].mPaneName, pane->GetName()); + + mLayouts[layoutId].mPaneSize.width = pane->GetSize().width; + mLayouts[layoutId].mPaneSize.height = pane->GetSize().height; + + nw4r::math::MTX34 mtx = pane->GetGlobalMtx(); + + mLayouts[layoutId].mPaneGlbMtxTrans.x = mtx._03; + mLayouts[layoutId].mPaneGlbMtxTrans.y = mtx._13; + mLayouts[layoutId].mPaneGlbMtxScale.x = mtx._00; + mLayouts[layoutId].mPaneGlbMtxScale.y = mtx._11; + + mLayouts[layoutId].mPaneBasePosH = pane->GetBasePositionH(); + mLayouts[layoutId].mPaneBasePosV = pane->GetBasePositionV(); + + mLayouts[layoutId].mPaneOffset.width = 0.0f; + mLayouts[layoutId].mPaneOffset.height = 0.0f; + mLayouts[layoutId].mRootPaneOffset.x = 0.0f; + mLayouts[layoutId].mRootPaneOffset.y = 0.0f; + mLayouts[layoutId].m_254 = 0.0f; + mLayouts[layoutId].mPaneAlpha = 0xff; + mLayouts[layoutId].mDoFade = false; + + if (dontSetAllDrawOrder) { + mLayouts[layoutId].mBase.mDrawOrder = 152; + } else { + for (int i = 0; i < ARRAY_SIZE(mLayouts); i++) { + if (i == 4) { + mLayouts[i].mBase.mDrawOrder = 14; + } else { + mLayouts[i].mBase.mDrawOrder = 147; + } + } + } +} + +void dSelectCursor_c::SetAlpha(const nw4r::lyt::Pane *pane, int layoutId) { + u8 alpha = pane->GetGlbAlpha(); + Layout_c & layout = mLayouts[layoutId]; + + for (int i = 0; i < ARRAY_SIZE(layout.mpPicturePanes); i++) { + layout.mpPicturePanes[i]->SetAlpha(alpha); + } +} diff --git a/syms.txt b/syms.txt index 8671166d..1b847e14 100644 --- a/syms.txt +++ b/syms.txt @@ -192,8 +192,6 @@ m_instance__7dInfo_c=8042a25c m_startGameInfo__7dInfo_c=80315e90 isAllAnime__9LytBase_cFv=800c9730 pauseOffGameWithReset__6dAudioFv=8006a990 -m_instance__15dSelectCursor_c=8042a5a8 -Cancel__15dSelectCursor_cFi=8010c890 strrchr=802e1f30 __ct__10sStateID_cFPCc=8015f900 __dt__10sStateID_cFv=8015f940 @@ -670,3 +668,4 @@ typeInfo__Q34nw4r3lyt7TextBox=8042b0b8 typeInfo__Q34nw4r3lyt6Window=8042b0c0 remove__Q24dDvd8loader_cFv=8008f2b0 request__Q24dDvd8loader_cFPCcUcPQ23EGG4Heap=8008f1b0 +strcpy=802E1C28