From 510df58ea4d587d3aeff295b4d05708fffd52d00 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sat, 22 Mar 2025 12:34:18 +0100 Subject: [PATCH] eggLightObject good enough --- config/SOUE01/symbols.txt | 6 +- include/egg/gfx/eggLightObject.h | 23 ++- include/egg/gfx/eggLightTexture.h | 5 +- src/egg/gfx/eggLightObject.cpp | 270 ++++++++++++++++++++++++++---- 4 files changed, 256 insertions(+), 48 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 9e8abbca..b54e015c 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -26621,9 +26621,9 @@ InitGX__Q23EGG11LightObjectCFP11_GXLightObj = .text:0x804A9D40; // type:function CopyToG3D_World__Q23EGG11LightObjectCFRQ34nw4r3g3d8LightObj = .text:0x804A9F40; // type:function size:0x150 CopyToG3D_View__Q23EGG11LightObjectCFRQ34nw4r3g3d8LightObjRCQ34nw4r4math5MTX34 = .text:0x804AA090; // type:function size:0x144 CopyFromG3D__Q23EGG11LightObjectFRCQ34nw4r3g3d11ResAnmLightfPQ23EGG11LightObjectb = .text:0x804AA1E0; // type:function size:0xD8 -FUN_804aa2c0 = .text:0x804AA2C0; // type:function size:0x9C -FUN_804aa360 = .text:0x804AA360; // type:function size:0x168 -FUN_804aa4d0 = .text:0x804AA4D0; // type:function size:0xA8 +ApplyAnmResultInner__Q23EGG11LightObjectFRCQ34nw4r3g3d14LightAnmResult = .text:0x804AA2C0; // type:function size:0x9C +ApplyAnmResultA__Q23EGG11LightObjectFRCQ34nw4r3g3d14LightAnmResult = .text:0x804AA360; // type:function size:0x168 +ApplyAnmResultB__Q23EGG11LightObjectFRCQ34nw4r3g3d14LightAnmResult = .text:0x804AA4D0; // type:function size:0xA8 CalcDirDist__Q23EGG11LightObjectFv = .text:0x804AA580; // type:function size:0xD4 CalcAt__Q23EGG11LightObjectFv = .text:0x804AA660; // type:function size:0x44 SetPos__Q23EGG11LightObjectFRCQ34nw4r4math4VEC3 = .text:0x804AA6B0; // type:function size:0x1C diff --git a/include/egg/gfx/eggLightObject.h b/include/egg/gfx/eggLightObject.h index 84fbdcf3..d9ff2455 100644 --- a/include/egg/gfx/eggLightObject.h +++ b/include/egg/gfx/eggLightObject.h @@ -1,8 +1,9 @@ #ifndef EGG_LIGHT_OBJ_H #define EGG_LIGHT_OBJ_H -#include "egg/math/eggVector.h" +#include "egg/egg_types.h" #include "egg/prim/eggBinary.h" +#include "nw4r/g3d/res/g3d_resanmlight.h" #include "nw4r/math/math_types.h" #include "rvl/GX/GXLight.h" #include "rvl/GX/GXTypes.h" @@ -23,7 +24,17 @@ public: void Reset(); void Calc(); void CalcView(nw4r::math::MTX34 const &); + + void fn_804A9C30(const LightTexture *, nw4r::math::VEC3 *, GXColor *) const; + void InitGX(GXLightObj *obj) const; + void CopyToG3D_World(nw4r::g3d::LightObj &) const; + void CopyToG3D_View(nw4r::g3d::LightObj &, const nw4r::math::MTX34 &) const; + void CopyFromG3D(const nw4r::g3d::ResAnmLight &, f32, EGG::LightObject *, bool); + + void ApplyAnmResultInner(const nw4r::g3d::LightAnmResult &); + void ApplyAnmResultA(const nw4r::g3d::LightAnmResult &); + bool ApplyAnmResultB(const nw4r::g3d::LightAnmResult &); void CalcAt(); void SetPos(const nw4r::math::VEC3 &); @@ -66,12 +77,12 @@ private: /* 0x48 */ f32 field_0x48; /* 0x4C */ nw4r::math::VEC3 field_0x4C; /* 0x58 */ nw4r::math::VEC3 field_0x58; - /* 0x64 */ f32 field_0x64; - /* 0x68 */ u16 field_0x68; + /* 0x64 */ f32 mShininess; + /* 0x68 */ u16 mFlags; /* 0x6C */ nw4r::math::VEC3 field_0x6C; - /* 0x78 */ GXColor field_0x78; - /* 0x7C */ nw4r::math::VEC3 field_0x7C; - /* 0x88 */ nw4r::math::VEC3 field_0x88; + /* 0x78 */ GXColor mLightColor; + /* 0x7C */ nw4r::math::VEC3 mViewPos; + /* 0x88 */ nw4r::math::VEC3 mViewAt; /* 0x94 */ nw4r::math::VEC3 field_0x94; /* 0xA0 */ u16 field_0xA0; }; diff --git a/include/egg/gfx/eggLightTexture.h b/include/egg/gfx/eggLightTexture.h index c278e227..59bf0907 100644 --- a/include/egg/gfx/eggLightTexture.h +++ b/include/egg/gfx/eggLightTexture.h @@ -53,12 +53,13 @@ public: const char *getName() const { return mName1; } - -private: + f32 getFloat(u16 idx) const { return mpFloatData[idx]; } +private: + u8 getByte1(u16 idx) const { return mpByteData1[idx]; } diff --git a/src/egg/gfx/eggLightObject.cpp b/src/egg/gfx/eggLightObject.cpp index 9eb4db95..1c5703c7 100644 --- a/src/egg/gfx/eggLightObject.cpp +++ b/src/egg/gfx/eggLightObject.cpp @@ -1,6 +1,10 @@ #include "egg/gfx/eggLightObject.h" +#include "common.h" #include "egg/gfx/eggDrawGX.h" +#include "egg/gfx/eggLightTexture.h" +#include "nw4r/g3d/g3d_light.h" +#include "nw4r/g3d/res/g3d_resanmlight.h" #include "nw4r/math/math_arithmetic.h" #include "nw4r/math/math_types.h" #include "rvl/GX/GXLight.h" @@ -8,6 +12,12 @@ #include "rvl/MTX/mtxvec.h" #include "rvl/MTX/vec.h" +// TODO: This whole file does weird things with vectors! +// NSMBW symbol names indicate that functions use nw4r::math::VEC3 +// arguments and we have some nw4r PS inlines, but +// a fair number of vector assignments happen in a weird order +// which might indicate EGG::Vector3f? + namespace EGG { template <> @@ -35,17 +45,17 @@ LightObject::LightObject() mBlack(DrawGX::BLACK), field_0x3C(0), field_0x3D(1), - mSpotFn(0), - mDistAttnFn(0), + mSpotFn(GX_SP_OFF), + mDistAttnFn(GX_DA_OFF), field_0x40(90.0f), field_0x44(0.5f), field_0x48(0.5f), - field_0x64(16.0f), - field_0x68(0x661) {} + mShininess(16.0f), + mFlags(0x661) {} void LightObject::Reset() { SetPosAt(nw4r::math::VEC3(-10000.0f, 10000.0f, 10000.0f), zeroVec); - field_0x68 = 0x661; + mFlags = 0x661; mWhite = DrawGX::WHITE; mBlack = DrawGX::BLACK; field_0x30 = 1.0; @@ -54,24 +64,24 @@ void LightObject::Reset() { field_0x40 = 90.0; field_0x44 = 0.5; field_0x48 = 0.5; - mSpotFn = 0; - mDistAttnFn = 0; - field_0x64 = 16.0; + mSpotFn = GX_SP_OFF; + mDistAttnFn = GX_DA_OFF; + mShininess = 16.0; field_0x58.x = 1.0; field_0x4C.x = 1.0; field_0x58.z = 0.0; - field_0x4C.y = 0.0; - field_0x58.y = 0.0; field_0x4C.z = 0.0; + field_0x58.y = 0.0; + field_0x4C.y = 0.0; } void LightObject::Calc() { field_0x6C = mDir; - field_0x78 = mWhite; + mLightColor = mWhite; } void LightObject::CalcView(nw4r::math::MTX34 const &viewMtx) { - if ((field_0x68 & 1) == 0) { + if ((mFlags & 1) == 0) { return; } @@ -80,35 +90,35 @@ void LightObject::CalcView(nw4r::math::MTX34 const &viewMtx) { case 3: { // Halp f32 scale = -1.0f; - field_0x88.x = 0.0f; + mViewAt.x = 0.0f; field_0x94.x = 0.0f; - field_0x88.y = 0.0f; + mViewAt.y = 0.0f; field_0x94.y = 0.0f; field_0x94.z = -1.0f; - field_0x88.z = scale * mDist; - field_0x7C.z = 0.0f; - field_0x7C.y = 0.0f; - field_0x7C.x = 0.0f; + mViewAt.z = scale * mDist; + mViewPos.z = 0.0f; + mViewPos.y = 0.0f; + mViewPos.x = 0.0f; break; } case 4: { // Halp f32 scale = 1.0f; - field_0x7C.x = 0.0f; + mViewPos.x = 0.0f; field_0x94.x = 0.0f; - field_0x7C.y = 0.0f; + mViewPos.y = 0.0f; field_0x94.y = 0.0f; field_0x94.z = 1.0f; - field_0x7C.z = scale * mDist; - field_0x88.z = 0.0f; - field_0x88.y = 0.0f; - field_0x88.x = 0.0f; + mViewPos.z = scale * mDist; + mViewAt.z = 0.0f; + mViewAt.y = 0.0f; + mViewAt.x = 0.0f; break; } case 2: field_0x94 = mDir; - field_0x88 = mAt; - field_0x7C = mPos; + mViewAt = mAt; + mViewPos = mPos; break; } @@ -126,15 +136,30 @@ void LightObject::CalcView(nw4r::math::MTX34 const &viewMtx) { field_0x6C.z = 1.0f; } } - PSMTXMultVec(viewMtx, mPos, field_0x7C); - PSMTXMultVec(viewMtx, mAt, field_0x88); + PSMTXMultVec(viewMtx, mPos, mViewPos); + PSMTXMultVec(viewMtx, mAt, mViewAt); nw4r::math::VEC3TransformNormal(&field_0x94, &viewMtx, &field_0x6C); } } +void LightObject::fn_804A9C30(const LightTexture *tex, nw4r::math::VEC3 *pVec, GXColor *color) const { + *pVec = field_0x94; + *color = mLightColor; + f32 f = tex->getFloat(mIndex); + if (f < 1.0f) { + color->r = color->r * f; + color->g = color->g * f; + color->b = color->b * f; + color->a = color->a * f; + } else { + // Yes + *color = *color; + } +} + void LightObject::InitGX(GXLightObj *obj) const { - if ((field_0x68 & 1) != 0 && ((field_0x68 >> 6) & 1) != 0) { - GXInitLightColor(obj, field_0x78); + if ((mFlags & 1) != 0 && ((mFlags >> 6) & 1) != 0) { + GXInitLightColor(obj, mLightColor); switch (field_0x3D) { case 1: { nw4r::math::VEC3 tmp = field_0x94 * -1e10f; @@ -143,31 +168,31 @@ void LightObject::InitGX(GXLightObj *obj) const { break; } case 0: { - GXInitLightPos(obj, field_0x7C.x, field_0x7C.y, field_0x7C.z); + GXInitLightPos(obj, mViewPos.x, mViewPos.y, mViewPos.z); GXInitLightDir(obj, zeroVec[0], zeroVec[1], zeroVec[2]); break; } case 2: { - GXInitLightPos(obj, field_0x7C.x, field_0x7C.y, field_0x7C.z); + GXInitLightPos(obj, mViewPos.x, mViewPos.y, mViewPos.z); GXInitLightDir(obj, field_0x94.x, field_0x94.y, field_0x94.z); break; } } - if ((field_0x68 & 0x80) != 0) { + if ((mFlags & 0x80) != 0) { GXInitLightAttnA(obj, field_0x4C.x, field_0x4C.y, field_0x4C.z); } else { GXInitLightSpot(obj, field_0x40 > 0.0f ? field_0x40 : 0.0001f, getSpotFn()); } - if ((field_0x68 & 0x100) != 0) { + if ((mFlags & 0x100) != 0) { GXInitLightAttnK(obj, field_0x58.x, field_0x58.y, field_0x58.z); } else { GXInitLightDistAttn(obj, field_0x44 * getDistance(), field_0x48, getDistAttnFn()); } - if ((field_0x68 & 0x800) != 0) { - f32 ka = field_0x64 / 2.0f; + if ((mFlags & 0x800) != 0) { + f32 ka = mShininess / 2.0f; GXInitLightAttn(obj, 0.0f, 0.0f, 1.0f, ka, 0.0f, 1.0f - ka); } @@ -176,6 +201,178 @@ void LightObject::InitGX(GXLightObj *obj) const { } } +void LightObject::CopyToG3D_World(nw4r::g3d::LightObj &g3dObj) const { + if ((mFlags & 1) != 0 && (mFlags & 0x40) != 0) { + g3dObj.Clear(); + if ((mFlags & 0x200) == 0) { + g3dObj.DisableColor(); + } + if ((mFlags & 0x400) == 0) { + g3dObj.DisableAlpha(); + } + + g3dObj.Enable(); + g3dObj.InitLightColor(mLightColor); + + if ((mFlags & 0x80) != 0) { + g3dObj.InitLightAttnA(field_0x4C.x, field_0x4C.y, field_0x4C.z); + } else { + g3dObj.InitLightSpot(field_0x40 > 0.0f ? field_0x40 : 0.0001f, getSpotFn()); + } + + if ((mFlags & 0x100) != 0) { + g3dObj.InitLightAttnK(field_0x58.x, field_0x58.y, field_0x58.z); + } else { + g3dObj.InitLightDistAttn(field_0x44 * getDistance(), field_0x48, getDistAttnFn()); + } + + if ((mFlags & 0x800) != 0) { + g3dObj.InitLightShininess(mShininess); + } + } else { + g3dObj.Disable(); + } +} + +void LightObject::CopyToG3D_View(nw4r::g3d::LightObj &g3dObj, const nw4r::math::MTX34 &viewMtx) const { + if (!g3dObj.IsEnable()) { + return; + } + + // TODO + if (!(mFlags & 0x800)) { + nw4r::math::VEC3 dir; + nw4r::math::VEC3 pos; + switch (field_0x3D) { + case 1: { + nw4r::math::VEC3TransformNormal(&dir, &viewMtx, &field_0x94); + nw4r::math::VEC3Scale(&pos, &dir, -1e10f); + dir.z = 0.0f; + dir.y = 0.0f; + dir.x = 0.0f; + break; + } + case 0: { + PSMTXMultVec(viewMtx, mViewPos, pos); + dir.z = 0.0f; + dir.y = 0.0f; + dir.x = 0.0f; + break; + } + case 2: { + PSMTXMultVec(viewMtx, mViewPos, pos); + nw4r::math::VEC3TransformNormal(&dir, &viewMtx, &field_0x94); + break; + } + } + g3dObj.InitLightPos(pos.x, pos.y, pos.z); + g3dObj.InitLightDir(dir.x, dir.y, dir.z); + } else { + g3dObj.InitSpecularDir(mDir.x, mDir.y, mDir.z); + } +} + +void LightObject::CopyFromG3D( + const nw4r::g3d::ResAnmLight &g3dLight, f32 frame, EGG::LightObject *optObj, bool skipDoingSomething +) { + nw4r::g3d::LightAnmResult result; + g3dLight.GetAnmResult(&result, frame); + if (!skipDoingSomething || (result.flags & nw4r::g3d::LightAnmResult::FLAG_LIGHT_ENABLE) != 0) { + if ((result.flags & nw4r::g3d::LightAnmResult::FLAG_LIGHT_ENABLE) != 0) { + ApplyAnmResultA(result); + if (optObj != nullptr && optObj->ApplyAnmResultB(result)) { + optObj->field_0x06 = mIndex; + optObj->mFlags |= 2; + } + } else { + // TODO + mFlags = mFlags & 0xFFFE; + if (optObj != nullptr) { + optObj->mFlags = optObj->mFlags & 0xFFFE; + } + } + } +} + +void LightObject::ApplyAnmResultInner(const nw4r::g3d::LightAnmResult &res) { + // TODO + mFlags = mFlags & 0xF07E; + field_0x40 = 90.0f; + field_0x44 = 0.5f; + field_0x48 = 0.5f; + mSpotFn = GX_SP_OFF; + mDistAttnFn = GX_DA_OFF; + mShininess = 16.0f; + // ... + field_0x58.x = 1.0f; + field_0x4C.x = 1.0f; + field_0x58.z = 0.0f; + field_0x4C.z = 0.0f; + field_0x58.y = 0.0f; + field_0x4C.y = 0.0f; + if ((res.flags & nw4r::g3d::LightAnmResult::FLAG_COLOR_ENABLE) != 0) { + mFlags |= 0x200; + } + if ((res.flags & nw4r::g3d::LightAnmResult::FLAG_ALPHA_ENABLE) != 0) { + mFlags |= 0x400; + } + if ((res.flags & nw4r::g3d::LightAnmResult::FLAG_LIGHT_ENABLE) != 0) { + mFlags |= 1; + } +} + +void LightObject::ApplyAnmResultA(const nw4r::g3d::LightAnmResult &res) { + ApplyAnmResultInner(res); + switch ((int)(res.flags & nw4r::g3d::LightAnmResult::FLAG_LIGHT_TYPE_MASK)) { + case 0: { + field_0x3D = 0; + mWhite = res.color; + SetPosAt(res.pos, res.pos); + field_0x40 = 0.0f; + mSpotFn = GX_SP_OFF; + field_0x44 = res.refDistance; + field_0x48 = res.refBrightness; + mDistAttnFn = res.distFunc; + break; + } + case 1: { + field_0x3D = 1; + mWhite = res.color; + SetPosAt(res.pos, res.aim); + mSpotFn = GX_SP_OFF; + mDistAttnFn = GX_AF_SPEC; + break; + } + case 2: { + field_0x3D = 2; + mWhite = res.color; + SetPosAt(res.pos, res.aim); + mSpotFn = res.spotFunc; + field_0x40 = res.cutoff; + mDistAttnFn = res.distFunc; + field_0x44 = res.refDistance; + field_0x48 = res.refBrightness; + break; + } + } +} + +bool LightObject::ApplyAnmResultB(const nw4r::g3d::LightAnmResult &res) { + if ((res.flags & nw4r::g3d::LightAnmResult::FLAG_SPECULAR_ENABLE) != 0) { + ApplyAnmResultInner(res); + field_0x3D = 1; + mWhite = res.specColor; + SetPosAt(res.pos, res.aim); + mFlags |= 0x800; + mShininess = res.shininess; + return true; + } else { + // TODO + mFlags = mFlags & 0xFFFE; + return false; + } +} + void LightObject::CalcDirDist() { mDir.x = mAt.x - mPos.x; mDir.y = mAt.y - mPos.y; @@ -217,7 +414,6 @@ void LightObject::SetPosAt(nw4r::math::VEC3 const &pos, nw4r::math::VEC3 const & CalcDirDist(); } - void LightObject::SetBinaryInner(const Bin &bin) {} void LightObject::GetBinaryInner(Bin *bin) const {}