#include "egg/gfx/eggLightManager.h" #include "common.h" #include "egg/egg_types.h" #include "egg/gfx/eggDrawGX.h" #include "egg/gfx/eggG3DUtility.h" #include "egg/gfx/eggLightObject.h" #include "egg/gfx/eggLightTextureMgr.h" #include "nw4r/g3d/g3d_light.h" #include "nw4r/g3d/g3d_scnroot.h" #include "nw4r/g3d/g3d_state.h" #include "nw4r/g3d/res/g3d_resanmamblight.h" #include "nw4r/g3d/res/g3d_resanmscn.h" #include "nw4r/g3d/res/g3d_reslightset.h" #include "nw4r/math/math_types.h" #include "rvl/GX/GXLight.h" #include "rvl/GX/GXTypes.h" #include "rvl/MTX/mtx.h" #include "rvl/OS/OSCache.h" namespace EGG { LightManager::LightManager(u32 numEggObjects, u32 numAmbientObject, u8 numGxObjsPerEggObj) { Counts c; c.mNumEggLightObjects = numEggObjects; c.mNumAmbientObjects = numAmbientObject; mCounts = c; mSavedCounts = c; mpLightData = nullptr; mpAmbientObjects = nullptr; mpTextureMgr = nullptr; mNumGxObjsPerEggObj = numGxObjsPerEggObj; mFlags = 0x40; mResAnmScn = nw4r::g3d::ResAnmScn(nullptr); mRefNumber = -1; mpTextureMgr = new LightTextureManager(this); mpLightObjs = new GXLightObj[mNumGxObjsPerEggObj * CheckedNumLightObjs(mCounts.mNumEggLightObjects)](); mpLightData = new LightData[mCounts.mNumEggLightObjects](); mpAmbientObjects = new AmbientObject[mCounts.mNumAmbientObjects](); for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { GetLightObject(i)->SetIndex(i); GetLightObject(i)->ClearField0xA0(); BecomeInvalidLight(i); } for (u16 i = 0; i < (u32)mCounts.mNumAmbientObjects; i++) { mpAmbientObjects[i].field_0x08 = 0; } Reset(); } LightManager::~LightManager() { delete mpTextureMgr; delete[] mpLightObjs; delete[] mpLightData; delete[] mpAmbientObjects; } static const char *ambientLightPlaceholderName = "--"; void LightManager::Reset() { for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { LightObject *obj = GetLightObject(i); obj->Reset(); if (i > 0) { obj->ClearFlag2(); } } for (u16 i = 0; i < (u32)mCounts.mNumAmbientObjects; i++) { mpAmbientObjects[i].mLightObj = (nw4r::g3d::AmbLightObj){0x64, 0x64, 0x64, 0xFF}; mpAmbientObjects[i].mLightName = ambientLightPlaceholderName; } mColor = DrawGX::BLACK; field_0x1D = 0; mFlags = mFlags & 0xFFE0; } void LightManager::Calc(nw4r::g3d::ScnRoot *root) { if ((mFlags & 4) == 0) { for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { LightObject *obj = GetLightObject(i); if (obj->CheckFlag2()) { u16 u = obj->GetField0x06(); if (i != u) { obj->UpdatePosAt(*GetLightObject(u)); } } obj->Calc(); } mFlags |= 4; mpTextureMgr->frameReset(); } if (root != nullptr) { CopyToG3D_World(root); } } void LightManager::CalcView(const nw4r::math::MTX34 &viewMtx, u8 lightObjOffset, nw4r::g3d::ScnRoot *root) { // NONMATCHING - regswaps field_0x1D = lightObjOffset; mFlags |= 8; GXLightObj *gxObj = mpLightObjs + lightObjOffset * CheckedNumLightObjs(mCounts.mNumEggLightObjects); for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { GetLightObject(i)->CalcView(viewMtx); if (i < CheckedNumLightObjs(mCounts.mNumEggLightObjects)) { GetLightObject(i)->InitGX(&gxObj[i]); } } DCFlushRange(gxObj, CheckedNumLightObjs(mCounts.mNumEggLightObjects) * sizeof(GXLightObj)); if (root != nullptr) { nw4r::math::MTX34 tmp; MTXInverse(viewMtx, tmp); CopyToG3D_View(root, tmp); } } void LightManager::LoadLightSet( int id, u32 *pDiffColorMask, u32 *pDiffAlphaMask, u32 *pSpecColorMask, u32 *pSpecAlphaMask, GXColor *pColor ) { nw4r::g3d::AmbLightObj o; nw4r::g3d::G3DState::LoadLightSet(id, pDiffColorMask, pDiffAlphaMask, pSpecColorMask, pSpecAlphaMask, &o); if (pColor != nullptr) { pColor->r = o.r; pColor->g = o.g; pColor->b = o.b; pColor->a = o.a; } } void LightManager::DoneDraw() { if (((mFlags & 8) != 0) && ((mFlags & 4) != 0)) { mFlags = mFlags & 0xffef; } mFlags = mFlags & 0xfffb; mFlags = mFlags & 0xfff7; } void LightManager::LoadScnLightInner(nw4r::g3d::ResAnmScn scn, f32 frame, s16 refNumber, u32 u2) { // NONMATCHING - small problems around lightSet.GetLightID if (!scn.IsValid()) { return; } if ((u2 & 2) != 0) { mFlags |= 0x10; mResAnmScn = scn; mRefNumber = refNumber; } if ((u2 & 1) == 0) { return; } for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { BecomeInvalidLight(i); } nw4r::g3d::ResLightSet lightSet = scn.GetResLightSetByRefNumber(refNumber); s32 lightId = -1; if (lightSet.IsValid()) { lightId = lightSet.GetAmbLightID(); } u32 loopMax = mCounts.mNumAmbientObjects; if (scn.GetResAnmAmbLightMaxRefNumber() < loopMax) { loopMax = scn.GetResAnmAmbLightMaxRefNumber(); } for (u32 i = 0; i < loopMax; i++) { AmbientObject *ambient = &mpAmbientObjects[i]; ambient->field_0x08 = ambient->field_0x08 & 0xFE; if (lightId == -1 || i == lightId) { nw4r::g3d::ResAnmAmbLight light = scn.GetResAnmAmbLightByRefNumber(i); AnmScnRes_GetAmbLightColor(ambient, light, frame); ambient->field_0x08 |= 1; } } u32 numObjs = mCounts.mNumEggLightObjects; u32 numAmb = scn.GetResAnmLightMaxRefNumber(); u32 numTotal = numAmb + scn.GetSpecularLightNumber(); u32 numLight = numAmb <= numObjs ? numAmb : numObjs; u32 maxIdx = numTotal <= numObjs ? numTotal : numObjs; if (lightSet.IsValid()) { numLight = lightSet.GetNumLight(); } for (u32 i = 0; i < numLight; i++) { u32 idx = lightSet.IsValid() ? lightSet.GetLightID(i) : i; GetLightObject(idx)->ClearFlag2(); } for (u32 i = 0; i < numLight; i++) { u32 idx = lightSet.IsValid() ? lightSet.GetLightID(i) : i; nw4r::g3d::ResAnmLight light = scn.GetResAnmLightByRefNumber(idx); if (light.IsValid()) { LightObject *obj = nullptr; LightData *dat = &mpLightData[idx]; if (!GetLightObject(idx)->CheckFlag1()) { if (light.HasSpecularLight() && light.GetSpecularLightIdx() < maxIdx) { obj = GetLightObject(light.GetSpecularLightIdx()); } dat->mLightObject.CopyFromG3D(light, frame, obj, false); mpLightData[idx].mLightObject.SetOtherFlag1(); } } } } void LightManager::CopyToG3D_Ambient(nw4r::g3d::ScnRoot *root) const { // NONMATCHING - word copy nw4r::g3d::LightSetting &setting = root->GetLightSetting(); for (int i = 0; i < mCounts.mNumAmbientObjects; i++) { setting.GetAmbLightObjArray()[i] = mpAmbientObjects[i].mLightObj; } } void LightManager::CopyToG3D_World(nw4r::g3d::ScnRoot *root) const { // NONMATCHING - loop registers, variables nw4r::g3d::LightSetting &setting = root->GetLightSetting(); if ((mFlags & 0x10) != 0) { G3DUtility::setUpLightSet(setting, mResAnmScn, mRefNumber); } CopyToG3D_Ambient(root); for (int i = 0; i < mCounts.mNumAmbientObjects; i++) { GetLightObject(i)->CopyToG3D_World(setting.GetLightObjArray()[i]); } } void LightManager::CopyToG3D_View(nw4r::g3d::ScnRoot *root, const nw4r::math::MTX34 &viewMtx) const { nw4r::g3d::LightSetting &setting = root->GetLightSetting(); // NONMATCHING - loop registers, variables for (int i = 0; i < mCounts.mNumEggLightObjects; i++) { GetLightObject(i)->CopyToG3D_View(setting.GetLightObjArray()[i], viewMtx); } } void LightManager::AnmScnRes_GetAmbLightColor( EGG::LightManager::AmbientObject *obj, nw4r::g3d::ResAnmAmbLight light, f32 frame ) const { nw4r::g3d::AmbLightAnmResult res; if (!light.IsValid()) { res.flags = 0; res.color = -1; } else { light.GetAnmResult(&res, frame); obj->mLightName = light.GetName(); } if ((res.flags & nw4r::g3d::AmbLightAnmResult::FLAG_COLOR_ENABLE) == 0) { res.color |= 0xFFFFFF00; } if ((res.flags & nw4r::g3d::AmbLightAnmResult::FLAG_ALPHA_ENABLE) == 0) { res.color |= 0x000000FF; } u32 color = res.color; obj->mLightObj.r = (color >> 24) & 0xFF; obj->mLightObj.g = (color >> 16) & 0xFF; obj->mLightObj.b = (color >> 8) & 0xFF; obj->mLightObj.a = (color >> 0) & 0xFF; } void LightManager::SetBinaryInner(const Bin &) { // TODO } void LightManager::GetBinaryInner(Bin *bin) const { // NONMATCHING - regswaps, loop increments u16 numObjs = mSavedCounts.mNumEggLightObjects; u16 numAmbient = mSavedCounts.mNumAmbientObjects; bin->mData.mNumLightObjects = numObjs; bin->mData.mNumAmbientObjects = mSavedCounts.mNumAmbientObjects; LightObject::Bin *pObj = reinterpret_cast(&bin->mData.mObjData); for (int i = 0; i < numObjs; i++) { GetLightObject(i)->GetBinary(&pObj[i]); } BinAmbient *pAmp = reinterpret_cast(&pObj[numObjs]); for (u16 i = 0; i < numAmbient; i++) { AmbientObject &o = mpAmbientObjects[i]; pAmp[i].field_0x00 = o.mLightObj.r; pAmp[i].field_0x01 = o.mLightObj.g; pAmp[i].field_0x02 = o.mLightObj.b; pAmp[i].field_0x03 = o.mLightObj.a; pAmp[i].field_0x07 = 0; pAmp[i].field_0x06 = 0; pAmp[i].field_0x05 = 0; pAmp[i].field_0x04 = 0; } bin->mData.mColor = mColor; } void LightManager::SetBinaryInner(const Bin &, const Bin &, f32) { // TODO } void LightManager::BecomeInvalidLight(int idx) { mpLightData[idx].mLightObject.ClearOtherFlag1(); } size_t LightManager::GetBinarySize() const { return sizeof(Bin) + sizeof(LightObject::Bin) * (mSavedCounts.mNumEggLightObjects - 1) + sizeof(BinAmbient) * mSavedCounts.mNumAmbientObjects; } } // namespace EGG