diff --git a/.vscode/settings.json b/.vscode/settings.json index dc93c0a8e..10b4bb311 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,21 +10,17 @@ "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" }, - "C_Cpp.default.defines": [ - "IEEE_LIBM", - "REVOLUTION", - "PACK_SPORTS", - ], + "C_Cpp.default.defines": ["IEEE_LIBM", "REVOLUTION", "PACK_SPORTS"], // "editor.tabSize": 4, - "files.autoSave": "onFocusChange", + // "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.associations": { "*.inc": "c", "*.pch": "c", "*.pch++": "cpp", - ".clangd": "yaml", + ".clangd": "yaml" }, // Disable C/C++ IntelliSense, use clangd instead - "C_Cpp.intelliSenseEngine": "disabled", + "C_Cpp.intelliSenseEngine": "disabled" } diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 1933f6dbc..fd3869081 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -7550,18 +7550,18 @@ fn_8019C4B4 = .text:0x8019C4B4; // type:function size:0x20 fn_8019C4D4 = .text:0x8019C4D4; // type:function size:0x24C fn_8019C720 = .text:0x8019C720; // type:function size:0x24 fn_8019C744 = .text:0x8019C744; // type:function size:0x8 -fn_8019C74C = .text:0x8019C74C; // type:function size:0x2F0 -fn_8019CA3C = .text:0x8019CA3C; // type:function size:0x1A4 -fn_8019CBE0 = .text:0x8019CBE0; // type:function size:0xB14 +Construct__16RPSysKokeshiIconFv = .text:0x8019C74C; // type:function size:0x2F0 +ModifyBgColor__16RPSysKokeshiIconFRC20RPSysKokeshiLocationUsUs9_GXTexFmt13RFLIconBGType8_GXColor = .text:0x8019CA3C; // type:function size:0x1A4 +MakeEdge__16RPSysKokeshiIconFv = .text:0x8019CBE0; // type:function size:0xB14 __dt__12RPGrpTextureFv = .text:0x8019D6F4; // type:function size:0x40 -fn_8019D734 = .text:0x8019D734; // type:function size:0x31C -fn_8019DA50 = .text:0x8019DA50; // type:function size:0x280 -fn_8019DCD0 = .text:0x8019DCD0; // type:function size:0x4 +MakeTexture__16RPSysKokeshiIconFP10RPGrpModelRC20RPSysKokeshiLocationPQ23EGG9AllocatorUsUs9_GXTexFmt13RFLIconBGType8_GXColorQ219RPSysKokeshiManager8IconView = .text:0x8019D734; // type:function size:0x31C +SetupCamera__16RPSysKokeshiIconFQ34nw4r3g3d6CameraUsUsQ219RPSysKokeshiManager8IconView = .text:0x8019DA50; // type:function size:0x280 +ApplyLightTexture__16RPSysKokeshiIconFUc = .text:0x8019DCD0; // type:function size:0x4 GetResTIMG__16RPSysKokeshiIconFv = .text:0x8019DCD4; // type:function size:0x8 -fn_8019DCDC = .text:0x8019DCDC; // type:function size:0xFC -fn_8019DDD8 = .text:0x8019DDD8; // type:function size:0x4 -fn_8019DDDC = .text:0x8019DDDC; // type:function size:0x58 -fn_8019DE34 = .text:0x8019DE34; // type:function size:0x44 +SetupModel__16RPSysKokeshiIconFP10RPGrpModel = .text:0x8019DCDC; // type:function size:0xFC +LoadResource__16RPSysKokeshiIconFPC24RPSysKokeshiOverloadInfo = .text:0x8019DDD8; // type:function size:0x4 +__dt__16RPSysKokeshiIconFv = .text:0x8019DDDC; // type:function size:0x58 +__ct__16RPSysKokeshiIconFPC19RPSysKokeshiGenInfo = .text:0x8019DE34; // type:function size:0x44 __dt__19RPSysKokeshiGenInfoFv = .text:0x8019DE78; // type:function size:0x5C __ct__19RPSysKokeshiGenInfoFv = .text:0x8019DED4; // type:function size:0xB4 __dt__20RPSysKokeshiLocationFv = .text:0x8019DF88; // type:function size:0x40 @@ -18608,7 +18608,7 @@ __vt__11RPSysAvatar = .data:0x803B9C08; // type:object size:0x14 lbl_803B9C20 = .data:0x803B9C20; // type:object size:0x10 lbl_803B9C30 = .data:0x803B9C30; // type:object size:0x18 lbl_803B9C48 = .data:0x803B9C48; // type:object size:0x38 -lbl_803B9C80 = .data:0x803B9C80; // type:object size:0x18 +__vt__16RPSysKokeshiIcon = .data:0x803B9C80; // type:object size:0x18 __vt__19RPSysKokeshiGenInfo = .data:0x803B9C98; // type:object size:0xC __vt__20RPSysKokeshiLocation = .data:0x803B9CA8; // type:object size:0xC __vt__24RPSysKokeshiOverloadInfo = .data:0x803B9CB8; // type:object size:0xC @@ -20451,7 +20451,7 @@ lbl_804BDBAC = .sdata:0x804BDBAC; // type:object size:0x4 data:4byte lbl_804BDBB0 = .sdata:0x804BDBB0; // type:object size:0x8 data:4byte lbl_804BDBB8 = .sdata:0x804BDBB8; // type:object size:0x8 lbl_804BDBC0 = .sdata:0x804BDBC0; // type:object size:0x8 align:4 data:float -lbl_804BDBC8 = .sdata:0x804BDBC8; // type:object size:0x8 +LIGHT_TEXTURE_FILE_NAMES__16RPSysKokeshiIcon = .sdata:0x804BDBC8; // type:object size:0x8 lbl_804BDBD0 = .sdata:0x804BDBD0; // type:object size:0x8 lbl_804BDBD8 = .sdata:0x804BDBD8; // type:object size:0x8 lbl_804BDBE0 = .sdata:0x804BDBE0; // type:object size:0x8 diff --git a/include/Pack/RPGraphics/RPGrpModel.h b/include/Pack/RPGraphics/RPGrpModel.h index a7200df7f..87bb930b5 100644 --- a/include/Pack/RPGraphics/RPGrpModel.h +++ b/include/Pack/RPGraphics/RPGrpModel.h @@ -66,7 +66,7 @@ class RPGrpModel { RPGrpModel* mpEntryNext; // at 0x14 RPGrpModel* mpGenNext; // at 0x18 IRPGrpModelCallback* mpCallback; // at 0x1C - nw4r::math::VEC3 mScale; // at 0x20 + nw4r::math::VEC3 mBaseScale; // at 0x20 RPGrpModelAnm* mpModelAnm; // at 0x2C RPGrpModelMaterial** mppMaterials; // at 0x30 RPGrpModelBoundingInfo* mpBoundingInfo; // at 0x34 @@ -214,8 +214,22 @@ class RPGrpModel { return mpModelEx->getScnRfl(); } - const nw4r::math::VEC3& GetScale() const { - return mScale; + const nw4r::math::VEC3& GetBaseScale() const { + return mBaseScale; + } + + void SetBaseScale(const nw4r::math::VEC3& rBaseScale) { + mBaseScale = rBaseScale; + } + + void SetBaseScale(f32 x, f32 y, f32 z) { + mBaseScale.x = x; + mBaseScale.y = y; + mBaseScale.z = z; + } + + void SetBaseScale(f32 scale) { + mBaseScale.x = mBaseScale.y = mBaseScale.z = scale; } RPGrpModelMaterial* GetMaterial(const char* pName) const { diff --git a/include/Pack/RPKernel/RPSysKokeshiGenInfo.h b/include/Pack/RPKernel/RPSysKokeshiGenInfo.h index 98b357624..e8a11536a 100644 --- a/include/Pack/RPKernel/RPSysKokeshiGenInfo.h +++ b/include/Pack/RPKernel/RPSysKokeshiGenInfo.h @@ -5,6 +5,8 @@ #include +#include + //! @addtogroup rp_kernel //! @{ @@ -17,7 +19,7 @@ class RPSysKokeshiGenInfo { RPSysKokeshiManager::GenType mGenType; // at 0x0 //! Player slot ID u8 mPlayerNo; // at 0x4 - //! Mii location (only for GenType_Info) + //! Mii storage location RPSysKokeshiLocation mLocation; // at 0x8 //! Body model to use @@ -27,15 +29,15 @@ class RPSysKokeshiGenInfo { //! Renderer view ID u8 mViewNo; // at 0x20 - - u32 mModelFlags; // at 0x24 - + //! RP model type option flags + u32 mTypeOption; // at 0x24 + //! NW4R model buffer option flags u32 mBufferOption; // at 0x28 //! Texture width for icons - u16 mTexWidth; // at 0x2C + u16 mIconWidth; // at 0x2C //! Texture height for icons - u16 mTexHeight; // at 0x2E + u16 mIconHeight; // at 0x2E //! Resolution of models and textures RFLResolution mResolution; // at 0x30 @@ -43,20 +45,21 @@ class RPSysKokeshiGenInfo { u32 mExprFlag; // at 0x34 // Use mipmapping to downscale the icon texture - BOOL mMipMap; - //! Whether to use the favorite color as the icon clear color - BOOL mUseFavoriteColor; // at 0x3C - //! Display clear color for icons - GXColor mClearColor; // at 0x40 - //! Camera setup for icons + BOOL mIconMipMap; // at 0x38 + //! Background type to use for icons + RFLIconBGType mIconBGType; // at 0x3C + //! Background color to use for icons + GXColor mIconBGColor; // at 0x40 + //! Camera viewpoint to use for icons RPSysKokeshiManager::IconView mIconView; // at 0x44 //! Facial expression to use for icons RFLExpression mIconExpression; // at 0x48 - //! Whether to outline icons - BOOL mMakeEdge; // at 0x4C - - GXColor unk50; - u16 unk54; + //! Whether to draw an outline around icons + BOOL mIconEdge; // at 0x4C + //! Edge color to use for icons + GXColor mIconEdgeColor; // at 0x50 + //! Width of the edge outline for icons + u16 mIconEdgeWidth; // at 0x54 public: /** @@ -104,11 +107,11 @@ class RPSysKokeshiGenInfo { mViewNo = viewNo; } - u32 GetModelFlags() const { - return mModelFlags; + u32 GetTypeOption() const { + return mTypeOption; } - void SetModelFlags(u32 modelFlags) { - modelFlags = modelFlags; + void SetTypeOption(u32 typeOption) { + mTypeOption = typeOption; } u32 GetBufferOption() const { @@ -118,6 +121,20 @@ class RPSysKokeshiGenInfo { mBufferOption = bufferOption; } + u16 GetIconWidth() const { + return mIconWidth; + } + void SetIconWidth(u16 width) { + mIconWidth = width; + } + + u16 GetIconHeight() const { + return mIconHeight; + } + void SetIconHeight(u16 height) { + mIconHeight = height; + } + RFLResolution GetResolution() const { return mResolution; } @@ -132,6 +149,62 @@ class RPSysKokeshiGenInfo { mExprFlag = exprFlag; } + bool GetIconMipMap() const { + return mIconMipMap; + } + void SetIconMipMap(bool mipMap) { + mIconMipMap = mipMap; + } + + RFLIconBGType GetIconBGType() const { + return mIconBGType; + } + void SetIconBGType(RFLIconBGType bgType) { + mIconBGType = bgType; + } + + const GXColor& GetIconBGColor() const { + return mIconBGColor; + } + void SetIconBGColor(const GXColor& rColor) { + mIconBGColor = rColor; + } + + RPSysKokeshiManager::IconView GetIconView() const { + return mIconView; + } + void SetIconView(RPSysKokeshiManager::IconView view) { + mIconView = view; + } + + RFLExpression GetIconExpression() const { + return mIconExpression; + } + void SetIconExpression(RFLExpression expr) { + mIconExpression = expr; + } + + bool GetIconEdge() const { + return mIconEdge; + } + void SetIconEdge(bool edge) { + mIconEdge = edge; + } + + const GXColor& GetIconEdgeColor() const { + return mIconEdgeColor; + } + void SetIconEdgeColor(const GXColor& rColor) { + mIconEdgeColor = rColor; + } + + u16 GetIconEdgeWidth() const { + return mIconEdgeWidth; + } + void SetIconEdgeWidth(u16 width) { + mIconEdgeWidth = width; + } + const RPSysKokeshiLocation& GetLocation() const { return mLocation; } diff --git a/include/Pack/RPKernel/RPSysKokeshiIcon.h b/include/Pack/RPKernel/RPSysKokeshiIcon.h index 9e942fe03..9ca548426 100644 --- a/include/Pack/RPKernel/RPSysKokeshiIcon.h +++ b/include/Pack/RPKernel/RPSysKokeshiIcon.h @@ -2,22 +2,164 @@ #define RP_KERNEL_KOKESHI_ICON_H #include +#include #include +#include + +#include #include #include -#include +#include + +#include //! @addtogroup rp_kernel //! @{ /** - * @brief Mii icon texture + * @brief Mii face icon */ class RPSysKokeshiIcon : public RPSysAvatar { public: + /** + * @brief Light map texture index + */ + enum ELightMap { + ELightMap_lm_0, //!< "lm_0.bti" texture + ELightMap_lm_1, //!< "lm_1.bti" texture + + ELightMap_Max + }; + +public: + /** + * @brief Constructor + * + * @param pGenInfo Mii generation parameters + */ + explicit RPSysKokeshiIcon(const RPSysKokeshiGenInfo* pGenInfo); + + /** + * @brief Destructor + */ + virtual ~RPSysKokeshiIcon() override; // at 0x8 + + /** + * @brief Loads the assets necessary for this avatar + * + * @param pOverloadInfo Overload parameters + */ + virtual void LoadResource(const RPSysKokeshiOverloadInfo* pOverloadInfo = + NULL) override; // at 0xC + + /** + * @brief Applies all lightmap textures to this avatar + * + * @param drawScene Draw scene index + */ + virtual void ApplyLightTexture(u8 drawScene) override; // at 0x10 + + /** + * @brief Gets the texture created for this icon + */ EGG::ResTIMG* GetResTIMG(); + + /** + * @brief Gets the Mii capture texture + */ + EGG::CapTexture* GetCapTexture() const { + return mpCapTexture; + } + +private: + /** + * @brief Configures a model for use with icon rendering + * + * @param pModel Mii model + */ + static void SetupModel(RPGrpModel* pModel); + + /** + * @brief Creates a cap texture for icon rendering + * + * @param width Texture width + * @param height Texture height + * @param format Texture format + */ + void InitCapTexture(u16 width, u16 height, GXTexFmt format); + + /** + * @brief Configures a NW4R camera to capture view this icon's model + * + * @param cam G3D camera + * @param width Texture width + * @param height Texture heigth + * @param view Icon viewpoint + */ + void SetupCamera(nw4r::g3d::Camera cam, u16 width, u16 height, + RPSysKokeshiManager::IconView view); + + /** + * @brief Prepares the GP rendering state + */ + void BeginMakeTexture() const; + + /** + * @brief Renders this icon and captures it to a texture + * + * @param pModel Mii model + * @param rLocation Mii storage location + * @param pAllocator Memory allocator + * @param width Texture width + * @param height Texture height + * @param format Texture format + * @param bgType Background color type + * @param bgColor Background color (for RFLIconBG_Direct) + * @param view Icon viewpoint + */ + void MakeTexture(RPGrpModel* pModel, const RPSysKokeshiLocation& rLocation, + EGG::Allocator* pAllocator, u16 width, u16 height, + GXTexFmt format, RFLIconBGType bgType, GXColor bgColor, + RPSysKokeshiManager::IconView view); + + /** + * @brief Finalizes the GP rendering state + */ + void EndMakeTexture() const; + + /** + * @brief Renders an outline in the icon around the Mii's face + */ + void MakeEdge(); + + /** + * @brief Applies the background color to the icon texture + * + * @param rLocation Mii storage location + * @param width Texture width + * @param height Texture height + * @param format Texture format + * @param bgType Background color type + * @param bgColor Background color (for RFLIconBG_Direct) + */ + void ModifyBgColor(const RPSysKokeshiLocation& rLocation, u16 width, + u16 height, GXTexFmt format, RFLIconBGType bgType, + GXColor bgColor); + + /** + * @brief Handles post-constructor initialization + */ + void Construct(); + +private: + //! Lightmap texture file names + static const char* LIGHT_TEXTURE_FILE_NAMES[ELightMap_Max]; + +private: + //! Mii capture texture + EGG::CapTexture* mpCapTexture; // at 0xA4 }; //! @} diff --git a/include/Pack/RPKernel/RPSysKokeshiManager.h b/include/Pack/RPKernel/RPSysKokeshiManager.h index 0327d2b9b..9831c3299 100644 --- a/include/Pack/RPKernel/RPSysKokeshiManager.h +++ b/include/Pack/RPKernel/RPSysKokeshiManager.h @@ -41,14 +41,24 @@ class RPSysKokeshiManager : public IRPSysHostIOSocket { ClothesType_Favorite, //!< Use the Mii's favorite color }; + /** + * @brief Clothing texture index + */ + enum ClothingTexture { + ClothingTexture_A, //!< "dummy_tex_a" texture + ClothingTexture_B, //!< "dummy_tex_b" texture + + ClothingTexture_Max + }; + /** * @brief Generation parameter type */ enum GenType { - GenType_Player, //!< Use the Mii associated with the info's player - GenType_Friend, //!< Pick a random friend Mii - GenType_Kokeshi, //!< Use the Mii already set in the Kokeshi object - GenType_None, //!< Use the default location values + GenType_Player, //!< Use the Mii associated with the info's player + GenType_Friend, //!< Pick a random friend Mii + GenType_Direct, //!< Use the Mii already set in the gen info + GenType_None, //!< Use the default location values }; /** @@ -60,15 +70,6 @@ class RPSysKokeshiManager : public IRPSysHostIOSocket { IconView_CloseUp, //!< Camera sees a close-up of the front of the Mii }; - /** - * @brief Official DB Mii state - */ - enum OfficialDBState { - OfficialDBState_Unused, //!< Database index is unused - OfficialDBState_Valid, //!< Database index holds a valid Mii - OfficialDBState_Registered, //!< A location has been registered here - }; - /** * @brief Light map texture index */ @@ -80,13 +81,12 @@ class RPSysKokeshiManager : public IRPSysHostIOSocket { }; /** - * @brief Clothing texture index + * @brief Official DB Mii state */ - enum ClothingTexture { - ClothingTexture_A, //!< "dummy_tex_a" texture - ClothingTexture_B, //!< "dummy_tex_b" texture - - ClothingTexture_Max + enum OfficialDBState { + OfficialDBState_Unused, //!< Database index is unused + OfficialDBState_Valid, //!< Database index holds a valid Mii + OfficialDBState_Registered, //!< A location has been registered here }; /** @@ -313,6 +313,16 @@ class RPSysKokeshiManager : public IRPSysHostIOSocket { return mpGuestNames[index]; } + /** + * @brief Gets the base scale of Mii models + */ + f32 GetBaseScale() const { + return mBaseScale; + } + + /** + * @brief Gets the output alpha of Mii models + */ u8 GetOutputAlpha() const { return mOutputAlpha; } @@ -391,9 +401,9 @@ class RPSysKokeshiManager : public IRPSysHostIOSocket { //! Names for default database ("Guest") Miis const wchar_t* mpGuestNames[RFL_DEFAULT_CHAR_MAX]; // at 0x8 //! Number of attempts before giving up on picking a random friend Mii - u16 mFriendRandomNum; // at 0x30 + u16 mFriendRandomNum; // at 0x20 //! Mii model base scale - f32 mBaseScale; // at 0x34 + f32 mBaseScale; // at 0x24 f32 unk28; f32 unk2C; diff --git a/include/Pack/RPSystem/RPSysResourceManager.h b/include/Pack/RPSystem/RPSysResourceManager.h index 46520fe64..430fc1cf8 100644 --- a/include/Pack/RPSystem/RPSysResourceManager.h +++ b/include/Pack/RPSystem/RPSysResourceManager.h @@ -223,6 +223,20 @@ class RPSysResourceManager { return mpFontArchive; } + /** + * @brief Gets the archive containing static common assets for this pack + */ + EGG::Archive* GetStaticCommonArchive() const { + return mpStaticCommonArchive; + } + + /** + * @brief Gets the archive containing static locale assets for this pack + */ + EGG::Archive* GetStaticLocalArchive() const { + return mpStaticLocalArchive; + } + /** * @brief Gets the extra handle for opening files outside the DVD */ diff --git a/include/RVLFaceLib/RFL_Types.h b/include/RVLFaceLib/RFL_Types.h index 0a6663332..2195163b0 100644 --- a/include/RVLFaceLib/RFL_Types.h +++ b/include/RVLFaceLib/RFL_Types.h @@ -108,6 +108,11 @@ typedef enum { RFLFavoriteColor_Max } RFLFavoriteColor; +typedef enum { + RFLIconBG_Favorite, + RFLIconBG_Direct, +} RFLIconBGType; + typedef enum { RFLRace_Black, RFLRace_White, diff --git a/src/Pack/RPGraphics/RPGrpModel.cpp b/src/Pack/RPGraphics/RPGrpModel.cpp index bb710893f..e05b51c4c 100644 --- a/src/Pack/RPGraphics/RPGrpModel.cpp +++ b/src/Pack/RPGraphics/RPGrpModel.cpp @@ -73,7 +73,7 @@ RPGrpModel::RPGrpModel(u8 viewNo) mpEntryNext(NULL), mpGenNext(NULL), mpCallback(NULL), - mScale(1.0f, 1.0f, 1.0f), + mBaseScale(1.0f, 1.0f, 1.0f), mpModelAnm(NULL), mppMaterials(NULL), mpBoundingInfo(NULL), diff --git a/src/Pack/RPGraphics/RPGrpModelImplement.cpp b/src/Pack/RPGraphics/RPGrpModelImplement.cpp index 8ee5a76d1..dbe2b5af3 100644 --- a/src/Pack/RPGraphics/RPGrpModelImplement.cpp +++ b/src/Pack/RPGraphics/RPGrpModelImplement.cpp @@ -110,13 +110,13 @@ RPGrpModelG3D::SetCallback(IRPGrpModelCallback* pCallback) { void RPGrpModelG3D::InternalCalc() { if (!mReverseCulling) { if (GetScnLeaf() != NULL) { - GetScnLeaf()->SetScale(mScale); + GetScnLeaf()->SetScale(mBaseScale); } } else { const nw4r::math::_VEC3& rMag = GEOMETRY_MAGNIFY[mReverseCulling - 1]; - nw4r::math::VEC3 scale(mScale.x * rMag.x, mScale.y * rMag.y, - mScale.z * rMag.z); + nw4r::math::VEC3 scale(mBaseScale.x * rMag.x, mBaseScale.y * rMag.y, + mBaseScale.z * rMag.z); if (GetScnLeaf() != NULL) { GetScnLeaf()->SetScale(scale); diff --git a/src/Pack/RPGraphics/RPGrpModelRfl.cpp b/src/Pack/RPGraphics/RPGrpModelRfl.cpp index 95905762c..7111faac3 100644 --- a/src/Pack/RPGraphics/RPGrpModelRfl.cpp +++ b/src/Pack/RPGraphics/RPGrpModelRfl.cpp @@ -110,8 +110,9 @@ u16 RPGrpModelRfl::ReplaceTexture(const char* pName, void RPGrpModelRfl::InternalCalc() { if (!mReverseCulling) { - nw4r::math::VEC3 scale(mScale.x * sBaseScale, mScale.y * sBaseScale, - mScale.z * sBaseScale); + nw4r::math::VEC3 scale(mBaseScale.x * sBaseScale, + mBaseScale.y * sBaseScale, + mBaseScale.z * sBaseScale); if (GetScnLeaf() != NULL) { GetScnLeaf()->SetScale(scale); @@ -121,9 +122,9 @@ void RPGrpModelRfl::InternalCalc() { } else { const nw4r::math::_VEC3& rMag = GEOMETRY_MAGNIFY[mReverseCulling - 1]; - nw4r::math::VEC3 scale(mScale.x * rMag.x * sBaseScale, - mScale.y * rMag.y * sBaseScale, - mScale.z * rMag.z * sBaseScale); + nw4r::math::VEC3 scale(mBaseScale.x * rMag.x * sBaseScale, + mBaseScale.y * rMag.y * sBaseScale, + mBaseScale.z * rMag.z * sBaseScale); if (GetScnLeaf() != NULL) { GetScnLeaf()->SetScale(scale); diff --git a/src/Pack/RPKernel/RPSysKokeshi.cpp b/src/Pack/RPKernel/RPSysKokeshi.cpp index 4ec307c0c..5b69b1681 100644 --- a/src/Pack/RPKernel/RPSysKokeshi.cpp +++ b/src/Pack/RPKernel/RPSysKokeshi.cpp @@ -52,7 +52,7 @@ void RPSysKokeshi::LoadResource(const RPSysKokeshiOverloadInfo* pOverloadInfo) { mAdditionalInfo.height, mAdditionalInfo.build); mpBodyModel = pKokeshiManager->CreateModel( - pBodyFile, bodyIdx, mGenInfo.GetViewNo(), mGenInfo.GetModelFlags(), + pBodyFile, bodyIdx, mGenInfo.GetViewNo(), mGenInfo.GetTypeOption(), mGenInfo.GetBufferOption()); // Open the hand archive @@ -64,11 +64,11 @@ void RPSysKokeshi::LoadResource(const RPSysKokeshiOverloadInfo* pOverloadInfo) { // Create the hand models mpLeftHandModel = pKokeshiManager->CreateModel( - pHandFile, 0, mGenInfo.GetViewNo(), mGenInfo.GetModelFlags(), + pHandFile, 0, mGenInfo.GetViewNo(), mGenInfo.GetTypeOption(), mGenInfo.GetBufferOption()); mpRightHandModel = pKokeshiManager->CreateModel( - pHandFile, 0, mGenInfo.GetViewNo(), mGenInfo.GetModelFlags(), + pHandFile, 0, mGenInfo.GetViewNo(), mGenInfo.GetTypeOption(), mGenInfo.GetBufferOption()); // Assign random clothes if requested via the overload info @@ -82,7 +82,7 @@ void RPSysKokeshi::LoadResource(const RPSysKokeshiOverloadInfo* pOverloadInfo) { } case RPSysKokeshiManager::GenType_Friend: - case RPSysKokeshiManager::GenType_Kokeshi: { + case RPSysKokeshiManager::GenType_Direct: { clothesType = static_cast( pBodyManager->GetFriendClothesStartIndex() + RPUtlRandom::getU32( @@ -227,7 +227,7 @@ void RPSysKokeshi::Construct() { break; } - case RPSysKokeshiManager::GenType_Kokeshi: { + case RPSysKokeshiManager::GenType_Direct: { location = mGenInfo.GetLocation(); break; } diff --git a/src/Pack/RPKernel/RPSysKokeshiCtrlDataMgr.cpp b/src/Pack/RPKernel/RPSysKokeshiCtrlDataMgr.cpp index 905872655..945bebe9e 100644 --- a/src/Pack/RPKernel/RPSysKokeshiCtrlDataMgr.cpp +++ b/src/Pack/RPKernel/RPSysKokeshiCtrlDataMgr.cpp @@ -1,12 +1,12 @@ #include #include +#include + #include #include -#include - /** * @brief Constructor * @@ -101,14 +101,15 @@ void RPSysKokeshiCtrlDataMgr::createResource() { // Take ownership of any graphics allocations in the callback mpHeap->becomeCurrentHeap(); RPGrpModel::SetAllocator(mpAllocator); - { - if (mpIterator->Update()) { - mpCallback->onCreateResource(mpLoader->getChannel(), - mpIterator->GetIndex()); - } else { - mState = EState_Idle; - } + + if (mpIterator->Update()) { + mpCallback->onCreateResource(mpLoader->getChannel(), + mpIterator->GetIndex()); + } else { + mState = EState_Idle; } + + // Restore original management RPGrpModel::SetAllocator(pOldAllocator); pOldHeap->becomeCurrentHeap(); } diff --git a/src/Pack/RPKernel/RPSysKokeshiGenInfo.cpp b/src/Pack/RPKernel/RPSysKokeshiGenInfo.cpp index 1308f8db5..f6b85d377 100644 --- a/src/Pack/RPKernel/RPSysKokeshiGenInfo.cpp +++ b/src/Pack/RPKernel/RPSysKokeshiGenInfo.cpp @@ -8,23 +8,29 @@ RPSysKokeshiGenInfo::RPSysKokeshiGenInfo() { mGenType = RPSysKokeshiManager::GenType_None; mPlayerNo = 0; + mBodyType = 0; mHandType = RPSysKokeshiManager::HandType_Sphere; + mViewNo = 1; - mModelFlags = 0; + mTypeOption = 0; mBufferOption = 0; - mTexWidth = 128; - mTexHeight = 128; + + mIconWidth = 128; + mIconHeight = 128; + mResolution = RFLResolution_128; mExprFlag = RFLExpFlag_Normal; - mMipMap = false; - mUseFavoriteColor = false; - mClearColor.r = mClearColor.g = mClearColor.b = mClearColor.a = 0; + + mIconMipMap = false; + mIconBGType = RFLIconBG_Favorite; + mIconBGColor.r = mIconBGColor.g = mIconBGColor.b = mIconBGColor.a = 0; mIconView = RPSysKokeshiManager::IconView_Front; mIconExpression = RFLExp_Normal; - mMakeEdge = false; - unk50.r = unk50.g = unk50.b = unk50.a = 0; - unk54 = 0; + mIconEdge = false; + mIconEdgeColor.r = mIconEdgeColor.g = mIconEdgeColor.b = mIconEdgeColor.a = + 0; + mIconEdgeWidth = 0; } /** diff --git a/src/Pack/RPKernel/RPSysKokeshiIcon.cpp b/src/Pack/RPKernel/RPSysKokeshiIcon.cpp new file mode 100644 index 000000000..ab703d688 --- /dev/null +++ b/src/Pack/RPKernel/RPSysKokeshiIcon.cpp @@ -0,0 +1,713 @@ +#include +#include +#include + +#include + +#include + +#include +#include + +/** + * @brief Lightmap texture file names + */ +const char* RPSysKokeshiIcon::LIGHT_TEXTURE_FILE_NAMES[ELightMap_Max] = { + "lm_0.bti", + "lm_1.bti", +}; + +/** + * @brief Constructor + * + * @param pGenInfo Mii generation parameters + */ +RPSysKokeshiIcon::RPSysKokeshiIcon(const RPSysKokeshiGenInfo* pGenInfo) + : RPSysAvatar(pGenInfo) { + + Construct(); +} + +/** + * @brief Destructor + */ +RPSysKokeshiIcon::~RPSysKokeshiIcon() {} + +/** + * @brief Loads the assets necessary for this avatar + * + * @param pOverloadInfo Overload parameters + */ +void RPSysKokeshiIcon::LoadResource( + const RPSysKokeshiOverloadInfo* pOverloadInfo) { + + RPSysAvatar::LoadResource(pOverloadInfo); +} + +/** + * @brief Configures a model for use with icon rendering + * + * @param pModel Mii model + */ +void RPSysKokeshiIcon::SetupModel(RPGrpModel* pModel) { + RPSysResourceManager* pResourceManager = + RP_GET_INSTANCE(RPSysResourceManager); + + EGG::Archive* pCommonArchive = pResourceManager->GetStaticCommonArchive(); + + for (u8 i = 0; i < ELightMap_Max; i++) { + void* pTexFile = RPSysResourceManager::GetFileFromArchive( + pCommonArchive, LIGHT_TEXTURE_FILE_NAMES[i]); + + RPGrpTexture tex(static_cast(pTexFile)); + + pModel->ReplaceTexture(RPSysKokeshiManager::GetLightTextureName(i), tex, + true); + } + + if (pModel->GetKind() == RPGrpModel::Kind_RFL) { + static_cast(pModel)-> // + SetMaterialType(RPGrpModelRfl::MaterialType_1); + } + + f32 scale = 1.0f / RP_GET_INSTANCE(RPSysKokeshiManager)->GetBaseScale(); + pModel->SetBaseScale(scale); + pModel->Calc(); + + if (pModel->GetKind() == RPGrpModel::Kind_RFL) { + static_cast(pModel)->SetOutputAlpha(255); + } +} + +/** + * @brief Creates a cap texture for icon rendering + * + * @param width Texture width + * @param height Texture height + * @param format Texture format + */ +void RPSysKokeshiIcon::InitCapTexture(u16 width, u16 height, GXTexFmt format) { + mpCapTexture = new EGG::CapTexture(width, height, format); + mpCapTexture->configure(); + + mpCapTexture->allocWithHeaderDebug(); + mpCapTexture->invalidate(); + + mpCapTexture->setMinFilter(GX_CLAMP); + mpCapTexture->setMagFilter(GX_CLAMP); +} + +/** + * @brief Gets the texture created for this icon + */ +EGG::ResTIMG* RPSysKokeshiIcon::GetResTIMG() { + return mpCapTexture->getResTIMG(); +} + +/** + * @brief Applies all lightmap textures to this avatar + * + * @param drawScene Draw scene index + */ +void RPSysKokeshiIcon::ApplyLightTexture(u8 /* drawScene */) {} + +/** + * @brief Configures a NW4R camera to capture view this icon's model + * + * @param cam G3D camera + * @param width Texture width + * @param height Texture heigth + * @param view Icon viewpoint + */ +void RPSysKokeshiIcon::SetupCamera(nw4r::g3d::Camera cam, u16 width, u16 height, + RPSysKokeshiManager::IconView view) { + switch (view) { + case RPSysKokeshiManager::IconView_Front: { + cam.SetPosition(32.5f, 600.0f, 0.0f); + break; + } + + case RPSysKokeshiManager::IconView_Back: { + cam.SetPosition(32.5f, -600.0f, 0.0f); + break; + } + + case RPSysKokeshiManager::IconView_CloseUp: { + cam.SetPosition(32.5f, 450.0f, 0.0f); + break; + } + + default: { + break; + } + } + + nw4r::math::VEC3 target(32.5f, 0.0f, 0.0f); + nw4r::math::VEC3 up(1.0f, 0.0f, 0.0f); + + nw4r::g3d::Camera::PostureInfo posture; + posture.tp = nw4r::g3d::Camera::POSTURE_LOOKAT; + posture.cameraUp = up; + posture.cameraTarget = target; + + cam.SetPosture(posture); + + f32 fovy; + f32 aspect = static_cast(width) / static_cast(height); + + if (width < height) { + fovy = nw4r::math::Atan2Rad(43.2f / aspect, 500.0f); + fovy = 2.0f * NW4R_MATH_RAD_TO_DEG(fovy); + } else { + fovy = nw4r::math::Atan2Rad(43.2f, 500.0f); + fovy = 2.0f * NW4R_MATH_RAD_TO_DEG(fovy); + } + + cam.SetPerspective(fovy, aspect, 1.0f, 1000.0f); + + if (mGenInfo.GetIconMipMap()) { + cam.SetScissor(0, 0, width * 2, height * 2); + } else { + cam.SetScissor(0, 0, width, height); + } + + if (mGenInfo.GetIconMipMap()) { + cam.SetViewport(0.0f, 0.0f, width * 2.0f, height * 2.0f); + cam.SetViewportZRange(0.0f, 1.0f); + } else { + cam.SetViewport(0.0f, 0.0f, width, height); + cam.SetViewportZRange(0.0f, 1.0f); + } +} + +/** + * @brief Prepares the GP rendering state + */ +void RPSysKokeshiIcon::BeginMakeTexture() const { + GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_OR, GX_NEVER, 0); + GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); + + GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GXSetZCompLoc(GX_FALSE); + + GXSetColorUpdate(GX_TRUE); + GXSetAlphaUpdate(GX_TRUE); + GXSetDither(GX_FALSE); + + GXSetDstAlpha(GX_FALSE, 0); + GXSetNumChans(0); + + nw4r::g3d::G3dReset(); +} + +/** + * @brief Renders this icon and captures it to a texture + * + * @param pModel Mii model + * @param rLocation Mii storage location + * @param pAllocator Memory allocator + * @param width Texture width + * @param height Texture height + * @param format Texture format + * @param bgType Background color type + * @param bgColor Background color (for RFLIconBG_Direct) + * @param view Icon viewpoint + */ +void RPSysKokeshiIcon::MakeTexture(RPGrpModel* pModel, + const RPSysKokeshiLocation& rLocation, + EGG::Allocator* pAllocator, u16 width, + u16 height, GXTexFmt format, + RFLIconBGType bgType, GXColor bgColor, + RPSysKokeshiManager::IconView view) { + + SetupModel(pModel); + ModifyBgColor(rLocation, width, height, format, bgType, bgColor); + + nw4r::g3d::ScnRoot* pScnRoot = + nw4r::g3d::ScnRoot::Construct(pAllocator, NULL, 32, 256); + + pScnRoot->SetCurrentCamera(0); + + nw4r::g3d::Camera cam = pScnRoot->GetCurrentCamera(); + SetupCamera(cam, width, height, view); + + BeginMakeTexture(); + { + pScnRoot->Clear(); + nw4r::g3d::ScnObj* pScnObj = NULL; + + if (pModel->GetKind() == RPGrpModel::Kind_RFL) { + pScnObj = pModel->GetScnRfl(); + } else { + pScnObj = pModel->GetScnMdlSimple(); + } + + pScnRoot->PushBack(pScnObj); + + pScnRoot->CalcWorld(); + pScnRoot->CalcMaterial(); + pScnRoot->CalcView(); + + pScnRoot->GatherDrawScnObj(); + pScnRoot->ZSort(); + pScnRoot->DrawOpa(); + pScnRoot->DrawXlu(); + } + EndMakeTexture(); + + mpCapTexture->enableColorUpdate(); + mpCapTexture->enableAlphaUpdate(); + + GXColor black = {0, 0, 0, 0}; + mpCapTexture->setClearColor(black); + + mpCapTexture->enableZBufferUpdate(); + mpCapTexture->setClearZ(GX_CLEAR_Z_MAX); + + mpCapTexture->disableVFilter(); + mpCapTexture->enablePixModeSync(); + + if (mGenInfo.GetIconMipMap()) { + mpCapTexture->capture(0, 0, true); + } else { + mpCapTexture->capture(0, 0, false); + } + + mpCapTexture->flush(); +} + +/** + * @brief Finalizes the GP rendering state + */ +void RPSysKokeshiIcon::EndMakeTexture() const { + GXDrawDone(); +} + +/** + * @brief Renders an outline in the icon around the Mii's face + */ +void RPSysKokeshiIcon::MakeEdge() { + nw4r::math::MTX34 proj; + C_MTXOrtho(proj, 0.0f, mGenInfo.GetIconWidth(), 0.0f, + mGenInfo.GetIconHeight(), -10000.0f, 10000.0f); + + GXSetProjection(proj, GX_ORTHOGRAPHIC); + + GXSetCullMode(GX_CULL_BACK); + + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, + GX_DF_CLAMP, GX_AF_SPOT); + GXSetChanCtrl(GX_COLOR1A1, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, + GX_DF_NONE, GX_AF_NONE); + + GXSetNumTexGens(1); + GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GXSetNumIndStages(0); + GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD1, GX_TEXMAP1); + GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1); + + GXSetNumTevStages(1); + GXSetTevDirect(GX_TEVSTAGE0); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); + GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); + GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + + GXSetAlphaUpdate(GX_TRUE); + GXSetColorUpdate(GX_TRUE); + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + RPGrpTexture tex(GetResTIMG()); + GXLoadTexObj(&tex.GetTexObj(), GX_TEXMAP0); + + nw4r::math::MTX34 ident; + nw4r::math::MTX34Identity(&ident); + GXLoadPosMtxImm(ident, GX_PNMTX0); + GXLoadNrmMtxImm(ident, GX_PNMTX0); + + GXSetChanMatColor(GX_COLOR0A0, mGenInfo.GetIconEdgeColor()); + + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, + GX_CC_RASC); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, + GX_TRUE, GX_TEVPREV); + + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_TEXA, GX_CA_ZERO, GX_CA_KONST, + GX_CA_ZERO); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_COMP_A8_GT, GX_TB_ZERO, GX_CS_SCALE_1, + GX_TRUE, GX_TEVPREV); + + // + // Draw edge outline + // + + f32 angle = 0.0f; + f32 step = 90.0f / static_cast(mGenInfo.GetIconEdgeWidth()); + + while (angle < 360.0f) { + // clang-format off + f32 x2 = mGenInfo.GetIconWidth() + nw4r::math::CosDeg(angle) * mGenInfo.GetIconEdgeWidth(); + f32 x1 = nw4r::math::CosDeg(angle) * mGenInfo.GetIconEdgeWidth(); + f32 y2 = mGenInfo.GetIconHeight() + nw4r::math::SinDeg(angle) * mGenInfo.GetIconEdgeWidth(); + f32 y1 = nw4r::math::SinDeg(angle) * mGenInfo.GetIconEdgeWidth(); + // clang-format on + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(x1, y1, 0.0f); + GXTexCoord2f32(0.0f, 0.0f); + + GXPosition3f32(x2, y1, 0.0f); + GXTexCoord2f32(1.0f, 0.0f); + + GXPosition3f32(x2, y2, 0.0f); + GXTexCoord2f32(1.0f, 1.0f); + + GXPosition3f32(x1, y2, 0.0f); + GXTexCoord2f32(0.0f, 1.0f); + } + GXEnd(); + + angle += step; + } + + // + // Draw icon background + // + + GXColor bgColor = mGenInfo.GetIconBGColor(); + + if (mGenInfo.GetIconBGType() == RFLIconBG_Favorite) { + RPSysKokeshiLocation location = mGenInfo.GetLocation(); + RFLAdditionalInfo info; + + RP_GET_INSTANCE(RPSysKokeshiManager) + ->GetAdditionalInfo(location, &info); + + bgColor = + RFLGetFavoriteColor(static_cast(info.color)); + } + + bgColor.a = 0; + GXSetChanMatColor(GX_COLOR0A0, bgColor); + + { + f32 w = mGenInfo.GetIconWidth(); + f32 h = mGenInfo.GetIconHeight(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(0.0f, 0.0f, 0.0f); + GXTexCoord2f32(0.0f, 0.0f); + + GXPosition3f32(w, 0.0f, 0.0f); + GXTexCoord2f32(1.0f, 0.0f); + + GXPosition3f32(w, h, 0.0f); + GXTexCoord2f32(1.0f, 1.0f); + + GXPosition3f32(0.0f, h, 0.0f); + GXTexCoord2f32(0.0f, 1.0f); + } + GXEnd(); + } + + // + // Draw icon face texture + // + + GXColor white = {255, 255, 255, 255}; + GXSetChanMatColor(GX_COLOR0A0, white); + + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, + GX_CC_ZERO); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, + GX_TRUE, GX_TEVPREV); + + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, + GX_CA_ZERO); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, + GX_TRUE, GX_TEVPREV); + + { + f32 w = mGenInfo.GetIconWidth(); + f32 h = mGenInfo.GetIconHeight(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(0.0f, 0.0f, 0.0f); + GXTexCoord2f32(0.0f, 0.0f); + + GXPosition3f32(w, 0.0f, 0.0f); + GXTexCoord2f32(1.0f, 0.0f); + + GXPosition3f32(w, h, 0.0f); + GXTexCoord2f32(1.0f, 1.0f); + + GXPosition3f32(0.0f, h, 0.0f); + GXTexCoord2f32(0.0f, 1.0f); + } + GXEnd(); + } + + // + // ??? + // + + GXSetColorUpdate(GX_FALSE); + GXSetAlphaUpdate(GX_TRUE); + GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + + GXSetChanMatColor(GX_COLOR0A0, mGenInfo.GetIconEdgeColor()); + + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, + GX_CC_RASC); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, + GX_TRUE, GX_TEVPREV); + + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, + GX_CA_RASA); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, + GX_TEVPREV); + + { + f32 w = mGenInfo.GetIconWidth(); + f32 t = mGenInfo.GetIconEdgeWidth(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(0.0f, 0.0f, 0.0f); + GXPosition3f32(w, 0.0f, 0.0f); + GXPosition3f32(w, t, 0.0f); + GXPosition3f32(0.0f, t, 0.0f); + } + GXEnd(); + } + + { + f32 w = mGenInfo.GetIconWidth(); + f32 h = mGenInfo.GetIconHeight(); + f32 b = mGenInfo.GetIconWidth() - mGenInfo.GetIconEdgeWidth(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(h, 0.0f, 0.0f); + GXPosition3f32(w, 0.0f, 0.0f); + GXPosition3f32(w, b, 0.0f); + GXPosition3f32(h, b, 0.0f); + } + GXEnd(); + } + + { + f32 w = mGenInfo.GetIconWidth(); + f32 h = mGenInfo.GetIconHeight(); + f32 l = mGenInfo.GetIconHeight() - mGenInfo.GetIconEdgeWidth(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(0.0f, l, 0.0f); + GXPosition3f32(w, l, 0.0f); + GXPosition3f32(w, h, 0.0f); + GXPosition3f32(0.0f, h, 0.0f); + } + GXEnd(); + } + + { + f32 w = mGenInfo.GetIconEdgeWidth(); + f32 r = mGenInfo.GetIconHeight(); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + { + GXPosition3f32(0.0f, 0.0f, 0.0f); + GXPosition3f32(w, 0.0f, 0.0f); + GXPosition3f32(w, r, 0.0f); + GXPosition3f32(0.0f, r, 0.0f); + } + GXEnd(); + } + + GXDrawDone(); + + mpCapTexture->disableVFilter(); + mpCapTexture->enablePixModeSync(); + + if (mGenInfo.GetIconMipMap()) { + mpCapTexture->capture(0, 0, true); + } else { + mpCapTexture->capture(0, 0, false); + } + + mpCapTexture->flush(); +} + +/** + * @brief Applies the background color to the icon texture + * + * @param rLocation Mii storage location + * @param width Texture width + * @param height Texture height + * @param format Texture format + * @param bgType Background color type + * @param bgColor Background color (for RFLIconBG_Direct) + */ +void RPSysKokeshiIcon::ModifyBgColor(const RPSysKokeshiLocation& rLocation, + u16 width, u16 height, GXTexFmt format, + RFLIconBGType bgType, GXColor bgColor) { + + EGG::ResTIMG* pResTIMG = GetResTIMG(); + + if (bgType == RFLIconBG_Favorite) { + RFLAdditionalInfo info; + + RP_GET_INSTANCE(RPSysKokeshiManager) + ->GetAdditionalInfo(rLocation, &info); + + bgColor = + RFLGetFavoriteColor(static_cast(info.color)); + } + + bgColor.a = 0; + + GXSetColorUpdate(GX_TRUE); + GXSetAlphaUpdate(GX_TRUE); + GXSetDstAlpha(GX_FALSE, 0); + + GXSetZMode(GX_TRUE, GX_ALWAYS, GX_TRUE); + GXSetPixelFmt(GX_PF_RGBA6_Z24, GX_ZC_LINEAR); + + GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); + GXSetCopyClamp(GX_CLAMP_ALL); + + if (mGenInfo.GetIconMipMap()) { + GXSetTexCopySrc(0, 0, width * 2, height * 2); + GXSetTexCopyDst(width, height, format, GX_TRUE); + } else { + GXSetTexCopySrc(0, 0, width, height); + GXSetTexCopyDst(width, height, format, GX_FALSE); + } + + GXSetCopyClear(bgColor, GX_CLEAR_Z_MAX); + + GXCopyTex(reinterpret_cast(pResTIMG) + pResTIMG->imageOffset, GX_TRUE); + GXPixModeSync(); +} + +/** + * @brief Handles post-constructor initialization + */ +void RPSysKokeshiIcon::Construct() { + RPSysAvatar::Construct(); + + // unused + RPSysSystem* pSystem = RP_GET_INSTANCE(RPSysSystem); + (void)pSystem->getFBWidth(); + (void)pSystem->getFBHeight(); + + InitCapTexture(mGenInfo.GetIconWidth(), mGenInfo.GetIconHeight(), + GX_TF_RGB5A3); + + EGG::Heap* pOldHeap = EGG::Heap::getCurrentHeap(); + EGG::Allocator* pOldAllocator = RPGrpModel::GetAllocator(); + + // TODO(kiwi) I guess 0x200 would cover the ExpHeap + Allocator? + u32 nglSize = RFLGetWorkSize(TRUE) + 0x200; + void* pNglWork = pOldHeap->alloc(nglSize, -4); + + EGG::ExpHeap* pNglHeap = EGG::ExpHeap::create(pNglWork, nglSize); + EGG::Allocator* pNglAllocator = new (pNglHeap) EGG::Allocator(pNglHeap); + + // Take ownership of any graphics allocations + pNglHeap->becomeCurrentHeap(); + RPGrpModel::SetAllocator(pNglAllocator); + + RPSysKokeshiManager* pKokeshiManager = RP_GET_INSTANCE(RPSysKokeshiManager); + RPSysKokeshiLocation location; + + switch (mGenInfo.GetGenType()) { + case RPSysKokeshiManager::GenType_Player: { + pKokeshiManager->GetLocationPlayer(mGenInfo.GetPlayerNo(), &location); + mGenInfo.SetLocation(location); + break; + } + + case RPSysKokeshiManager::GenType_Friend: { + pKokeshiManager->GetLocationFriend( + mGenInfo.GetLocation().GetDataSource(), + mGenInfo.GetLocation().GetMiddleDB(), &location); + + mGenInfo.SetLocation(location); + break; + } + + case RPSysKokeshiManager::GenType_Direct: { + location = mGenInfo.GetLocation(); + break; + } + + default: { + break; + } + } + + RFLResolution resolution = RFLResolution_64; + if (mGenInfo.GetIconWidth() > 128 || mGenInfo.GetIconHeight() > 128) { + resolution = RFLResolution_256; + } else if (mGenInfo.GetIconWidth() > 64 || mGenInfo.GetIconHeight() > 64) { + resolution = RFLResolution_128; + } + + // TODO(kiwi) View ID constants + // clang-format off + RPGrpModel* pNigaoeModel = pKokeshiManager->CreateNigaoeModel( + location, + resolution, + (1 << mGenInfo.GetIconExpression()) | RFLExpFlag_Normal, + 1); + // clang-format on + + pKokeshiManager->ChangeExpression(pNigaoeModel, + mGenInfo.GetIconExpression()); + + // clang-format off + MakeTexture( + pNigaoeModel, + mGenInfo.GetLocation(), + pNglAllocator, + mGenInfo.GetIconWidth(), + mGenInfo.GetIconHeight(), + GX_TF_RGB5A3, + mGenInfo.GetIconBGType(), + mGenInfo.GetIconBGColor(), + mGenInfo.GetIconView()); + // clang-format on + + if (mGenInfo.GetIconEdge()) { + MakeEdge(); + } + + pKokeshiManager->CreateTexture(GetResTIMG()); + pNigaoeModel->RemoveGenList(); + + // Restore original management + pNglHeap->destroy(); + RPGrpModel::SetAllocator(pOldAllocator); + pOldHeap->becomeCurrentHeap(); + + RPSysAvatar::Setup(); +} diff --git a/src/Pack/RPKernel/RPSysKokeshiManager.cpp b/src/Pack/RPKernel/RPSysKokeshiManager.cpp index f33611f05..a44414caf 100644 --- a/src/Pack/RPKernel/RPSysKokeshiManager.cpp +++ b/src/Pack/RPKernel/RPSysKokeshiManager.cpp @@ -509,7 +509,7 @@ void RPSysKokeshiManager::GetAdditionalInfo( void RPSysKokeshiManager::GetModelBaseScaleInvalidatedMtx( nw4r::math::MTX34* pOut, RPGrpModel* pModel, const nw4r::math::MTX34* pIn) { - nw4r::math::VEC3 scale = pModel->GetScale(); + nw4r::math::VEC3 scale = pModel->GetBaseScale(); nw4r::math::VEC3 scaleInv(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z); nw4r::math::MTX34Copy(pOut, pIn);