|
| 1 | +#include <types.h> |
| 2 | + |
| 3 | +#include "core/CosmeticMgr.h" |
| 4 | +#include "hooks/trampoline.h" |
| 5 | + |
| 6 | +#include <Pack/RPGraphics.h> |
| 7 | +#include <Sports2/Sp2Cmn.h> |
| 8 | +#include <nw4r/g3d.h> |
| 9 | + |
| 10 | +#include <libkiwi.h> |
| 11 | + |
| 12 | +namespace AP { |
| 13 | +namespace Bwl { |
| 14 | +namespace Cosmetic { |
| 15 | + |
| 16 | +/****************************************************************************** |
| 17 | + * |
| 18 | + * Random Bowling Ball Color |
| 19 | + * |
| 20 | + ******************************************************************************/ |
| 21 | + |
| 22 | +/** |
| 23 | + * @brief Overrides the bowling ball model color based on the randomizer |
| 24 | + * settings |
| 25 | + * |
| 26 | + * @param pModel Ball model |
| 27 | + * @param mirror Whether this model is the mirror model |
| 28 | + * @param color New ball color |
| 29 | + */ |
| 30 | +void PatchBwlBallColor(RPGrpModelG3D* pModel, bool mirror, kiwi::Color color) { |
| 31 | + ASSERT_PTR(pModel); |
| 32 | + |
| 33 | + /** |
| 34 | + * Get access to the model material |
| 35 | + */ |
| 36 | + nw4r::g3d::ScnMdl* pScnMdl = pModel->GetModelEx()->getScnMdl(); |
| 37 | + ASSERT_PTR(pScnMdl); |
| 38 | + |
| 39 | + nw4r::g3d::ResMdl resMdl = pScnMdl->GetResMdl(); |
| 40 | + ASSERT(resMdl.IsValid()); |
| 41 | + |
| 42 | + nw4r::g3d::ResMat resMat = resMdl.GetResMat("bwg_ball_mat"); |
| 43 | + ASSERT(resMat.IsValid()); |
| 44 | + |
| 45 | + RPGrpModelMaterial* pMaterial = pModel->GetMaterial(resMat.GetID()); |
| 46 | + ASSERT_PTR(pMaterial); |
| 47 | + |
| 48 | + nw4r::g3d::ScnMdl::CopiedMatAccess& rMatAccess = |
| 49 | + pMaterial->GetCopiedMatAccess(); |
| 50 | + |
| 51 | + /** |
| 52 | + * Write the required TEV colors |
| 53 | + */ |
| 54 | + // TEVREG0 holds the ball accent color |
| 55 | + // pMaterial->SetTevColor(GX_TEVREG0, color.ToS10()); |
| 56 | + // TEVKREG2 is used for greyscale conversion constants |
| 57 | + // pMaterial->SetTevKColor(GX_KCOLOR2, kiwi::Color(85, 150, 29, 0)); |
| 58 | + |
| 59 | + /** |
| 60 | + * Prepare the material for the new shader |
| 61 | + */ |
| 62 | + nw4r::g3d::ResGenMode genMode = rMatAccess.GetResGenMode(false); |
| 63 | + ASSERT(genMode.IsValid()); |
| 64 | + { |
| 65 | + // The new shader will have 7 stages |
| 66 | + genMode.GXSetNumTevStages(7); |
| 67 | + } |
| 68 | + genMode.EndEdit(); |
| 69 | + |
| 70 | + /** |
| 71 | + * Write the TEV shader fragments |
| 72 | + */ |
| 73 | + nw4r::g3d::ResTev tev = rMatAccess.GetResTev(false); |
| 74 | + ASSERT(tev.IsValid()); |
| 75 | + { |
| 76 | + /** |
| 77 | + * Ball texture color is converted to greyscale, |
| 78 | + * then blended (Addition) with the accent color in TEVREG0 |
| 79 | + */ |
| 80 | + static const u32 ballShader[] = { |
| 81 | + 0x61FE0000, 0x0F61F600, 0x000461FE, 0x00000F61, 0xF700000E, |
| 82 | + 0x61FE0000, 0x0F61F800, 0x000061FE, 0x00000F61, 0xF900000C, |
| 83 | + 0x61FE0000, 0x0F61FA00, 0x000561FE, 0x00000F61, 0xFB00000D, |
| 84 | + 0x61FE0000, 0x0F61FC00, 0x000A61FE, 0x00000F61, 0xFD00000E, |
| 85 | + 0x6127FFFF, 0xFF000000, 0x00000000, 0x00000000, 0x61FEFFFF, |
| 86 | + 0xF061F6E5, 0xB9206128, 0x3C03C061, 0xC088FE8F, 0x61C288FE, |
| 87 | + 0x8461C108, 0xFFF461C3, 0x08FFF861, 0x10000000, 0x61110000, |
| 88 | + 0x00000000, 0x61FEFFFF, 0xF061F7E0, 0x39A06129, 0x3BF3C061, |
| 89 | + 0xC408FE84, 0x61C6002C, 0x0261C508, 0xFFFC61C7, 0x08FFF061, |
| 90 | + 0x12000000, 0x61130000, 0x00000000, 0x61FEFFFF, 0xF061F8FF, |
| 91 | + 0xFFF0612A, 0x3C904061, 0xC808F0AF, 0x61CA088F, 0xE061C908, |
| 92 | + 0xF37061CB, 0x089F0061, 0x14000000, 0x61150000, 0x00000000, |
| 93 | + 0x61FEFFFF, 0xF061F900, 0x38C0612B, 0x3BF3D261, 0xCC08F80F, |
| 94 | + 0x00000000, 0x0061CD08, 0xFFE00000, 0x00000061, 0x16000000}; |
| 95 | + |
| 96 | + std::memcpy(&tev.ref().dl, ballShader, sizeof(ballShader)); |
| 97 | + tev.SetNumTevStages(7); |
| 98 | + } |
| 99 | + tev.EndEdit(); |
| 100 | +} |
| 101 | + |
| 102 | +/** |
| 103 | + * @brief Intercepts the bowling ball model after construction to apply patches |
| 104 | + * |
| 105 | + * @param pModel Bowling ball model |
| 106 | + */ |
| 107 | +void InterceptBwlBallConstruct(RPGrpModelG3D* pModel) { |
| 108 | + ASSERT_PTR(pModel); |
| 109 | + |
| 110 | + static kiwi::Color color; |
| 111 | + static int numCalls = 0; |
| 112 | + |
| 113 | + /** |
| 114 | + * Every two calls to this function will be one for the regular model and |
| 115 | + * one for the mirror model. |
| 116 | + * |
| 117 | + * We re-randomize the color after each set of two. |
| 118 | + */ |
| 119 | + if (numCalls % 2 == 0) { |
| 120 | + color = kiwi::Color::FromHsv(kiwi::RNG.NextF32(1.0f), 1.0f, 1.0f); |
| 121 | + } |
| 122 | + |
| 123 | + PatchBwlBallColor(pModel, numCalls % 2 != 0, color); |
| 124 | + numCalls++; |
| 125 | +} |
| 126 | + |
| 127 | +/** |
| 128 | + * @brief InterceptBwlBallConstruct common trampoline code |
| 129 | + */ |
| 130 | +asm void BwlBallCmnTrampoline(...) { |
| 131 | + // clang-format off |
| 132 | + TRAMPOLINE_BEGIN |
| 133 | + |
| 134 | + // Enable ScnMdl BUFFER_RESTEV buffer option |
| 135 | + ori r7, r7, (1 << 11) |
| 136 | + |
| 137 | + // RPGrpModelG3D::Construct |
| 138 | + lis r12, 0x8024E630@h |
| 139 | + ori r12, r12, 0x8024E630@l |
| 140 | + mtctr r12 |
| 141 | + bctrl |
| 142 | + mr r31, r3 |
| 143 | + |
| 144 | + // Patch the resulting model |
| 145 | + bl InterceptBwlBallConstruct |
| 146 | + |
| 147 | + mr r0, r31 |
| 148 | + TRAMPOLINE_END |
| 149 | + mr r3, r0 |
| 150 | + blr |
| 151 | + // clang-format on |
| 152 | +} |
| 153 | + |
| 154 | +/** |
| 155 | + * @brief Hook all relevant RPGrpModelG3D::Construct calls |
| 156 | + */ |
| 157 | +KM_CALL(0x804c89e0, BwlBallCmnTrampoline); |
| 158 | +KM_CALL(0x804c89fc, BwlBallCmnTrampoline); |
| 159 | +KM_CALL(0x804c8a30, BwlBallCmnTrampoline); |
| 160 | +KM_CALL(0x804c8a4c, BwlBallCmnTrampoline); |
| 161 | + |
| 162 | +KM_CALL(0x804c9cb0, BwlBallCmnTrampoline); |
| 163 | +KM_CALL(0x804c9ccc, BwlBallCmnTrampoline); |
| 164 | + |
| 165 | +KM_CALL(0x804c9f60, BwlBallCmnTrampoline); |
| 166 | +KM_CALL(0x804c9f7c, BwlBallCmnTrampoline); |
| 167 | +KM_CALL(0x804c9fb0, BwlBallCmnTrampoline); |
| 168 | +KM_CALL(0x804c9fcc, BwlBallCmnTrampoline); |
| 169 | + |
| 170 | +} // namespace Cosmetic |
| 171 | +} // namespace Bwl |
| 172 | +} // namespace AP |
0 commit comments