From 35523a5ac2dcbfbc31380243eeed146da19efb9b Mon Sep 17 00:00:00 2001 From: robojumper Date: Sun, 4 May 2025 21:38:47 +0200 Subject: More cleanups --- src/REL/d/a/d_a_t_wood_area.cpp | 2 +- src/REL/d/a/obj/d_a_obj_tubo.cpp | 2 +- src/REL/d/a/obj/d_a_obj_tumble_weed.cpp | 2 +- src/d/a/d_a_insect.cpp | 2 +- src/d/a/obj/d_a_obj_switch.cpp | 2 +- src/d/a/obj/d_a_obj_water_spout.cpp | 2 +- src/d/lyt/meter/d_lyt_meter_dowsing.cpp | 2 +- src/d/lyt/meter/d_lyt_meter_heart.cpp | 2 +- src/d/lyt/meter/d_lyt_meter_item_select.cpp | 2 +- src/d/lyt/meter/d_lyt_meter_timer.cpp | 2 +- src/toBeSorted/d_effects_1.cpp | 1107 ------------------------ src/toBeSorted/d_emitter.cpp | 1229 +++++++++++++++++++++++++++ 12 files changed, 1239 insertions(+), 1117 deletions(-) delete mode 100644 src/toBeSorted/d_effects_1.cpp create mode 100644 src/toBeSorted/d_emitter.cpp (limited to 'src') diff --git a/src/REL/d/a/d_a_t_wood_area.cpp b/src/REL/d/a/d_a_t_wood_area.cpp index 88ef72d8..044826bf 100644 --- a/src/REL/d/a/d_a_t_wood_area.cpp +++ b/src/REL/d/a/d_a_t_wood_area.cpp @@ -2,7 +2,7 @@ #include "common.h" #include "d/a/d_a_player.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" const f32 dAcTWoodArea_c::scaleX = 100.0f; const f32 dAcTWoodArea_c::scaleY = 100.0f; diff --git a/src/REL/d/a/obj/d_a_obj_tubo.cpp b/src/REL/d/a/obj/d_a_obj_tubo.cpp index 16361da0..a21885eb 100644 --- a/src/REL/d/a/obj/d_a_obj_tubo.cpp +++ b/src/REL/d/a/obj/d_a_obj_tubo.cpp @@ -31,7 +31,7 @@ #include "s/s_Math.h" #include "toBeSorted/attention.h" #include "toBeSorted/blur_and_palette_manager.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/event_manager.h" #include "toBeSorted/small_sound_mgr.h" #include "toBeSorted/special_item_drop_mgr.h" diff --git a/src/REL/d/a/obj/d_a_obj_tumble_weed.cpp b/src/REL/d/a/obj/d_a_obj_tumble_weed.cpp index 110ef752..367f48e2 100644 --- a/src/REL/d/a/obj/d_a_obj_tumble_weed.cpp +++ b/src/REL/d/a/obj/d_a_obj_tumble_weed.cpp @@ -19,7 +19,7 @@ #include "s/s_Math.h" #include "toBeSorted/blur_and_palette_manager.h" #include "toBeSorted/dowsing_target.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/small_sound_mgr.h" void float_ordering() { diff --git a/src/d/a/d_a_insect.cpp b/src/d/a/d_a_insect.cpp index b7dc69da..56c29de0 100644 --- a/src/d/a/d_a_insect.cpp +++ b/src/d/a/d_a_insect.cpp @@ -14,7 +14,7 @@ #include "m/m_mtx.h" #include "m/m_vec.h" #include "toBeSorted/attention.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/small_sound_mgr.h" extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_394_; diff --git a/src/d/a/obj/d_a_obj_switch.cpp b/src/d/a/obj/d_a_obj_switch.cpp index 8103d7a7..3bedebf6 100644 --- a/src/d/a/obj/d_a_obj_switch.cpp +++ b/src/d/a/obj/d_a_obj_switch.cpp @@ -6,7 +6,7 @@ #include "d/flag/sceneflag_manager.h" #include "nw4r/g3d/res/g3d_resfile.h" #include "s/s_Math.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/small_sound_mgr.h" SPECIAL_ACTOR_PROFILE(OBJ_SW, dAcOsw_c, fProfile::OBJ_SW, 0x12B, 0, 0x1002); diff --git a/src/d/a/obj/d_a_obj_water_spout.cpp b/src/d/a/obj/d_a_obj_water_spout.cpp index 32f2f4ac..b86b6f09 100644 --- a/src/d/a/obj/d_a_obj_water_spout.cpp +++ b/src/d/a/obj/d_a_obj_water_spout.cpp @@ -9,7 +9,7 @@ #include "nw4r/g3d/res/g3d_resfile.h" #include "nw4r/g3d/res/g3d_resmdl.h" #include "s/s_State.hpp" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" SPECIAL_ACTOR_PROFILE(OBJ_WATER_SPOUT, dAcOwaterSpout_c, fProfile::OBJ_WATER_SPOUT, 0x1DA, 0, 6); diff --git a/src/d/lyt/meter/d_lyt_meter_dowsing.cpp b/src/d/lyt/meter/d_lyt_meter_dowsing.cpp index 736cdc1b..f7850755 100644 --- a/src/d/lyt/meter/d_lyt_meter_dowsing.cpp +++ b/src/d/lyt/meter/d_lyt_meter_dowsing.cpp @@ -15,7 +15,7 @@ #include "nw4r/math/math_types.h" #include "sized_string.h" #include "toBeSorted/dowsing_target.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/file_manager.h" #include "toBeSorted/small_sound_mgr.h" diff --git a/src/d/lyt/meter/d_lyt_meter_heart.cpp b/src/d/lyt/meter/d_lyt_meter_heart.cpp index 6b11a4c0..7ee24c48 100644 --- a/src/d/lyt/meter/d_lyt_meter_heart.cpp +++ b/src/d/lyt/meter/d_lyt_meter_heart.cpp @@ -6,7 +6,7 @@ #include "d/lyt/d2d.h" #include "d/lyt/d_lyt_game_over.h" #include "nw4r/math/math_types.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/event_manager.h" #include "toBeSorted/file_manager.h" #include "toBeSorted/small_sound_mgr.h" diff --git a/src/d/lyt/meter/d_lyt_meter_item_select.cpp b/src/d/lyt/meter/d_lyt_meter_item_select.cpp index 1eaae5ee..7055a566 100644 --- a/src/d/lyt/meter/d_lyt_meter_item_select.cpp +++ b/src/d/lyt/meter/d_lyt_meter_item_select.cpp @@ -18,7 +18,7 @@ #include "nw4r/math/math_types.h" #include "s/s_Math.h" #include "sized_string.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/event_manager.h" #include "toBeSorted/minigame_mgr.h" #include "toBeSorted/small_sound_mgr.h" diff --git a/src/d/lyt/meter/d_lyt_meter_timer.cpp b/src/d/lyt/meter/d_lyt_meter_timer.cpp index a67f92b9..085479cf 100644 --- a/src/d/lyt/meter/d_lyt_meter_timer.cpp +++ b/src/d/lyt/meter/d_lyt_meter_timer.cpp @@ -14,7 +14,7 @@ #include "m/m_vec.h" #include "nw4r/lyt/lyt_pane.h" #include "nw4r/math/math_types.h" -#include "toBeSorted/effects_struct.h" +#include "toBeSorted/d_emitter.h" #include "toBeSorted/event_manager.h" #include "toBeSorted/small_sound_mgr.h" diff --git a/src/toBeSorted/d_effects_1.cpp b/src/toBeSorted/d_effects_1.cpp deleted file mode 100644 index c4d37d08..00000000 --- a/src/toBeSorted/d_effects_1.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -// clang-format off -// vtable order -#include "JSystem/JParticle/JPAEmitter.h" -#include "JSystem/JParticle/JPAParticle.h" -#include "toBeSorted/d_d3d.h" -// clang-format on - -#include "JSystem/JParticle/JPADrawInfo.h" -#include "JSystem/JParticle/JPAEmitter.h" -#include "c/c_math.h" -#include "common.h" -#include "d/a/d_a_base.h" -#include "d/a/obj/d_a_obj_base.h" -#include "d/d_base.h" -#include "d/d_heap.h" -#include "d/d_stage.h" -#include "d/d_stage_mgr.h" -#include "egg/core/eggHeap.h" -#include "f/f_base.h" -#include "f/f_profile_name.h" -#include "m/m3d/m3d.h" -#include "m/m_allocator.h" -#include "m/m_angle.h" -#include "m/m_color.h" -#include "m/m_mtx.h" -#include "m/m_vec.h" -#include "nw4r/g3d/g3d_camera.h" -#include "nw4r/g3d/g3d_state.h" -#include "nw4r/g3d/res/g3d_resfile.h" -#include "nw4r/g3d/res/g3d_resmat.h" -#include "nw4r/g3d/res/g3d_resmdl.h" -#include "nw4r/g3d/res/g3d_resshp.h" -#include "nw4r/math/math_arithmetic.h" -#include "sized_string.h" -#include "toBeSorted/arc_managers/oarc_manager.h" -#include "toBeSorted/blur_and_palette_manager.h" -#include "toBeSorted/d_d3d.h" -#include "toBeSorted/d_particle.h" -#include "toBeSorted/effects_struct.h" -#include "toBeSorted/event_manager.h" -#include "toBeSorted/lyt_related_floats.h" - -#include "rvl/GX.h" -#include "rvl/MTX.h" - -// There's a data gap at 0x805013b4 (right after dParticleFogProc_c's vtable) -// so maybe that's a data split. Unsure how to get all those vtables to appear -// there though... - -void float_ordering_1(s32 a) { - (f32) a; -} - -void float_ordering_2() { - 255.0f; -} - -void float_ordering_3(u32 a) { - (f32) a; -} - -void float_ordering_4() { - 0.0f; -} - -dJEffManager_c::EffectsList dJEffManager_c::sPlayingEffectsList; -CommonEmitterCallback dJEffManager_c::sCommonEmitterCallbacks[2]; -dShpEmitter_c dJEffManager_c::sShpEmitters[47]; -dEmitterBase_c dJEffManager_c::sEmitter; -dParticleFogProc_c dJEffManager_c::sFogProcs[12]; -dEffect2D_c dJEffManager_c::s2DEffects[3]; - -// broken by -ipa file - reconsider splits? -dEmitterCallback_c::~dEmitterCallback_c() { - for (EmitterCallbackList::Iterator it = mEmitterList.GetBeginIter(); it != mEmitterList.GetEndIter();) { - EmitterCallbackList::Iterator itCopy = it; - ++itCopy; - it->setEmitterCallback(nullptr); - it = itCopy; - } -} - -void dEmitterCallback_c::remove(dEmitterBase_c *emitter) { - if (mEmitterList.GetPosition(emitter) == mEmitterList.GetEndIter()) { - return; - } - mEmitterList.remove(emitter); -} - -// broken by -ipa file - reconsider splits? -dParticleCallback_c::~dParticleCallback_c() { - for (ParticleCallbackList::Iterator it = mEmitterList.GetBeginIter(); it != mEmitterList.GetEndIter();) { - ParticleCallbackList::Iterator itCopy = it; - ++itCopy; - it->setParticleCallback(nullptr); - it = itCopy; - } -} - -void dParticleCallback_c::remove(dEmitterBase_c *emitter) { - if (mEmitterList.GetPosition(emitter) == mEmitterList.GetEndIter()) { - return; - } - mEmitterList.remove(emitter); -} - -dEmitterBase_c::~dEmitterBase_c() { - deactivateEmitters(); - if (mpEmitterCallback != nullptr) { - mpEmitterCallback->remove(this); - mpEmitterCallback = nullptr; - } - - if (mpParticleCallback != nullptr) { - mpParticleCallback->remove(this); - mpParticleCallback = nullptr; - } -} - -JPABaseEmitter *dEmitterBase_c::GetNextEmitter(JPABaseEmitter *head) { - return reinterpret_cast(head->getUserWork()); -} - -bool dEmitterBase_c::createEmitters( - u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, - const GXColor *c2, s32 idx1, s32 idx2 -) { - u16 iter = effectResourceId; - JPABaseEmitter *head = nullptr; - JPABaseEmitter *last; - for (; iter != 0xFFFF; iter = dParticle::mgr_c::GetInstance()->getJpnData(iter)) { - last = dParticle::mgr_c::GetInstance()->createEmitter(iter, getGroupId(iter), position, rot, scale); - if (last != nullptr) { - if (head != nullptr) { - head->setUserWork(reinterpret_cast(last)); - } else { - mpEmitterHead = last; - } - head = last; - last->setEmitterCallBackPtr(mpEmitterCallback); - last->setParticleCallBackPtr(mpParticleCallback); - loadColors(last, c1, c2, idx1, idx2); - } - } - - if (mpEmitterHead != nullptr) { - if (mpEmitterCallback != nullptr) { - // why last and not head? - mpEmitterCallback->create(last); - } - if (mpParticleCallback != nullptr) { - // why last and not head? - mpParticleCallback->create(last); - } - } - return mpEmitterHead != nullptr; -} - -void dEmitterBase_c::setEmitterCallback(dEmitterCallback_c *cb) { - if (mpEmitterCallback != cb) { - if (mpEmitterCallback != nullptr) { - mpEmitterCallback->remove(this); - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setEmitterCallBackPtr(nullptr); - } - } - mpEmitterCallback = cb; - if (cb != nullptr) { - cb->mEmitterList.append(this); - } - } -} - -void dEmitterBase_c::setParticleCallback(dParticleCallback_c *cb) { - if (mpParticleCallback != cb) { - if (mpParticleCallback != nullptr) { - mpParticleCallback->remove(this); - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setParticleCallBackPtr(nullptr); - } - } - mpParticleCallback = cb; - if (cb != nullptr) { - cb->mEmitterList.append(this); - } - } -} - -void dEmitterBase_c::setImmortal() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->becomeImmortalEmitter(); - } -} - -void dEmitterBase_c::deactivateEmitters() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setEmitterCallBackPtr(nullptr); - emitter->setParticleCallBackPtr(nullptr); - emitter->quitImmortalEmitter(); - if (emitter->mMaxFrame == 0) { - emitter->becomeInvalidEmitter(); - } - emitter->playCalcEmitter(); - } - mpEmitterHead = nullptr; -} - -void dEmitterBase_c::stopCalcEmitters() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->stopCalcEmitter(); - } -} - -void dEmitterBase_c::playCalcEmitters() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->playCalcEmitter(); - } -} - -void dEmitterBase_c::stopDrawParticles() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->stopDrawParticle(); - } -} - -void dEmitterBase_c::playDrawParticles() { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->playDrawParticle(); - } -} - -void dEmitterBase_c::setPosRotScale(const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setGlobalTranslation(position); - if (rot != nullptr) { - emitter->setGlobalRotation(*rot); - } - if (scale != nullptr) { - emitter->setGlobalScale(*scale); - } - } -} - -extern "C" f32 lbl_80571C50; -inline f32 getlbl_80571C50() { - return lbl_80571C50; -} -void dEmitterBase_c::setPosRotScaleWithScreenScale(const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale) { - mVec3_c adjustedPosition(position.x * getlbl_80571C50(), position.y, position.z); - setPosRotScale(adjustedPosition, rot, scale); -} - -void dEmitterBase_c::setTransform(const mMtx_c &mtx) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setGlobalSRTMatrix(mtx); - } -} - -void dEmitterBase_c::loadColors(const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - loadColors(emitter, c1, c2, idx1, idx2); - } -} - -void dEmitterBase_c::setGlobalAlpha(u8 alpha) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setGlobalAlpha(alpha); - } -} - -void dEmitterBase_c::setRate(f32 rate) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setRate(rate); - } -} - -void dEmitterBase_c::setDynamicsScale(const mVec3_c &scale) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setGlobalDynamicsScale(scale); - } -} - -void dEmitterBase_c::setParticleScale(const mVec3_c &scale) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setGlobalParticleScale(scale); - } -} - -void dEmitterBase_c::setAwayFromCenterSpeed(f32 speed) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setAwayFromCenterSpeed(speed); - } -} - -void dEmitterBase_c::setVolumeSize(u16 size) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setVolumeSize(size); - } -} - -void dEmitterBase_c::setLifeTime(s16 lifetime) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setLifeTime(lifetime); - } -} - -void dEmitterBase_c::attachEmitterCallbackId(s32 id) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setEmitterCallBackPtr(&dJEffManager_c::sCommonEmitterCallbacks[id]); - } -} - -void dEmitterBase_c::bindShpEmitter(s32 id, bool unused) { - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - emitter->setParticleCallBackPtr(&dJEffManager_c::sShpEmitters[id]); - emitter->setGlobalAlpha(0); - } -} - -EffectsStruct::EffectsStruct() : mpOwner(nullptr), mFlags(0), mEffect(0) {} - -EffectsStruct::EffectsStruct(dBase_c *base) : mpOwner(base), mFlags(0), mEffect(0) {} - -EffectsStruct::~EffectsStruct() { - mpOwner = nullptr; - remove(false); -} - -void EffectsStruct::remove(bool bForceDeleteEmitters) { - offFlag(EMITTER_0x1); - JPABaseEmitter *emitter = bForceDeleteEmitters ? mpEmitterHead : nullptr; - deactivateEmitters(); - for (; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - dParticle::mgr_c::GetInstance()->forceDeleteEmitter(emitter); - } - removeFromActiveEmittersList(); -} - -void EffectsStruct::addToActiveEmittersList(u16 resourceId, bool bFlags) { - mEffect = resourceId; - mFlags = 0; - setImmortal(); - dJEffManager_c::sPlayingEffectsList.append(this); - onFlag(EMITTER_0x1); - if (bFlags) { - onFlag(EMITTER_0x4); - } - if (dParticle::mgr_c::GetInstance()->getResUserWork(resourceId) & 0x4000) { - onFlag(EMITTER_0x10); - } -} - -bool EffectsStruct::areAllEmittersDone() { - bool allDone = true; - - if (mpEmitterHead != nullptr) { - if (checkFlag(EMITTER_Fading) && mFadeTimer != 0) { - return false; - } - for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { - bool canDelete = emitter->isEnableDeleteEmitter(); - if (!canDelete) { - if (emitter->mMaxFrame == 0) { - emitter->becomeInvalidEmitter(); - } - allDone = false; - } - } - } - - return allDone; -} - -void EffectsStruct::execute() { - if (mpOwner != nullptr && (mpOwner->delete_request || mpOwner->lifecycle_state == fBase_c::TO_BE_DELETED)) { - mpOwner = nullptr; - } - if (shouldBePaused(mpOwner)) { - if (!checkFlag(EMITTER_0x10)) { - stopCalcEmitters(); - if (mpOwner != nullptr && !mpOwner->isBasePropertyFlag(0x100)) { - if (!mpEmitterHead->checkStatus(JPAEmtrStts_StopDraw)) { - onFlag(EMITTER_0x20); - stopDrawParticles(); - } - } else { - if (checkFlag(EMITTER_0x20)) { - offFlag(EMITTER_0x20); - playDrawParticles(); - } - } - } - onFlag(EMITTER_0x1); - } else { - playCalcEmitters(); - if (checkFlag(EMITTER_0x20)) { - offFlag(EMITTER_0x20); - playDrawParticles(); - } - if (checkFlag(EMITTER_Fading) && mFadeTimer != 0) { - mFadeTimer--; - } - } -} - -bool EffectsStruct::getOwnerPolyAttrs(s32 *pOut1, s32 *pOut2) { - if (mpOwner != nullptr && mpOwner->group_type == fBase_c::ACTOR) { - dAcBase_c *actor = static_cast(mpOwner); - *pOut1 = actor->polyAttr0; - *pOut2 = actor->polyAttr1; - return true; - } else { - *pOut1 = 0; - *pOut2 = 0; - return false; - } -} - -void EffectsStruct::realizeAlpha() { - setGlobalAlpha(mFadeTimer * (255.0f / mFadeDuration)); -} - -void EffectsStruct::setFading(u8 lifetime) { - if (!checkFlag(EMITTER_Fading)) { - mFadeTimer = lifetime; - onFlag(EMITTER_Fading); - mFadeDuration = lifetime; - } -} - -bool dParticleFogProc_c::create(u32 idx, s32 prioOpa, s32 prioXlu, mHeapAllocator_c *alloc) { - if (!d3d::UnkProc::create(prioOpa, prioXlu, alloc)) { - return false; - } - mIdx = idx; - // idxes 0, 2, 4, 6, 10 - field_0x1C = idx <= 10 && ((1 << idx) & 0b10001010101) != 0; - return true; -} - -void dParticleFogProc_c::doDraw() { - nw4r::g3d::Camera c = m3d::getCurrentCamera(); - mMtx_c camMtx, texProjMtx; - c.GetCameraMtx(camMtx); - c.GetProjectionTexMtx(texProjMtx); - JPADrawInfo info; - MTXCopy(camMtx, info.mCamMtx); - MTXCopy(texProjMtx, info.mPrjMtx); - if (field_0x1C) { - m3d::getFogMgr(0); // ignored, maybe an inline on FogMgr? - nw4r::g3d::G3DState::LoadFog(0); - } else { - mColor c(0); - GXSetFog(GX_FOG_NONE, c, 0.0f, 0.0f, 0.0f, 0.0f); - GXSetFogRangeAdj(GX_FALSE, 0, nullptr); - } - GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); - dJEffManager_c::draw(&info, mIdx); -} - -extern "C" bool fn_80054AD0(); -void dEffect2D_c::draw() { - f32 proj[GX_PROJECTION_SZ]; - GXGetProjectionv(proj); - f32 base = proj[1]; - proj[1] = base / get_805751A4(); - GXSetProjectionv(proj); - f32 f = get_80575184() / 2; - mMtx_c mtx1, mtx2; - JPADrawInfo info; - - C_MTXLightOrtho(mtx1, -get_80575150(), get_80575150(), -f, f, 0.5f, 0.5f, 0.5f, 0.5f); - - MTXScale(mtx2, fn_80054AD0() ? get_805751A4() : 1.0f, 1.0f, 1.0f); - MTXCopy(mtx2, info.mCamMtx); - MTXCopy(mtx1, info.mPrjMtx); - dJEffManager_c::draw(&info, mGroupId); - proj[1] = base; - GXSetProjectionv(proj); -} - -void dEffect2D_c::create(u32 groupId, u8 prio) { - mGroupId = groupId; - setPriority(prio); -} - -void dMassObjEmitterCallback_c::executeAfter(JPABaseEmitter *) {} - -void dShpEmitterProc::doDraw() { - mMtx_c viewMtx; - getViewMtx(viewMtx); - s32 ctrl = 0; - mLightSetId = mAlpha[0]; - mMtx_c *pTransforms = mpTransforms; - bool *pFlags = mpFlags; - for (s32 idx = 0; idx < mCount;) { - if (*pFlags == false) { - mMtx_c mtx; - mtx.copyFrom(*pTransforms); - MTXConcat(viewMtx, mtx, mtx); - mMtx_c mtx2; - mtx2.copyFrom(mtx); - mtx2.fn_802F1C40(0, 1); - nw4r::math::MTX33 mtx3; - for (int a = 0; a < 3; a++) { - for (int b = 0; b < 3; b++) { - mtx3.m[a][b] = mtx2.m[a][b]; - } - } - if (mLightSetId != mAlpha[idx]) { - mLightSetId = mAlpha[idx]; - setupLight(); - } - mVec3_c v; - mVec3_c zero(0.0f, 0.0f, 0.0f); - MTXMultVec(*pTransforms, zero, v); - dShpProcBase_c::draw(&v); - nw4r::g3d::G3DState::SetViewPosNrmMtxArray(mtx, &mtx3, nullptr); - nw4r::g3d::Draw1Mat1ShpDirectly(nw4r::g3d::ResMat(nullptr), mShp, mtx, mtx2, ctrl, nullptr, nullptr); - if (ctrl == 0) { - ctrl = 2; - } - } - idx++; - pTransforms++; - pFlags++; - } - mpOwner->clear(); -} - -bool dShpEmitter_c::create(mHeapAllocator_c *alloc) { - if (!mProc.create(nw4r::g3d::ResMat(nullptr), nw4r::g3d::ResShp(nullptr), 100, alloc, false, nullptr)) { - return false; - } - mProc.setOwner(this); - return true; -} - -void dShpEmitter_c::init(const char *mdlName, const char *arcName, bool priority) { - clear(); - void *ptr = OarcManager::GetInstance()->getSubEntryData(arcName, "g3d/model.brres"); - if (ptr == nullptr) { - mProc.setResMat(nw4r::g3d::ResMat(nullptr)); - mProc.setResShp(nw4r::g3d::ResShp(nullptr)); - return; - } - - nw4r::g3d::ResFile f(ptr); - - if (strequals(arcName, "F300BrokenRockWall")) { - dStage_c::bindStageResToFile(&f); - } - - nw4r::g3d::ResMdl mdl = f.GetResMdl(mdlName); - nw4r::g3d::ResMat mat = mdl.GetResMat(0); - mProc.setResMat(mat); - mProc.setResShp(mdl.GetResShp(0)); - if (priority) { - mProc.setPriorityDraw(0x1C, 4); - } -} - -void dShpEmitter_c::clear() { - field_0xA0 = 0; - mProc.setAllFlags(); -} - -void dShpEmitter_c::draw(JPABaseEmitter *emitter, JPABaseParticle *particle) { - // TODO - for (s32 i = 0; i < 100; i++) { - if (mProc.isDrawDisabled(i)) { - mProc.setDrawDisabled(i, false); - mVec3_c pos; - mVec3_c velocity; - particle->getGlobalPosition(pos); - particle->getVelVec(velocity); - mVec3_c v; - if (cM::isZero(velocity.squareMagXZ())) { - v = mVec3_c::Ex; - } else { - v = mVec3_c::Ey.cross(velocity); - v.normalize(); - } - mMtx_c m; - m.setAxisRotation(v, mAng((u16)particle->mRotateAngle).radian2()); - m.setBase(3, pos); - mMtx_c mtx2; - mVec3_c scale( - particle->getParticleScaleX() * emitter->getGlobalParticleScaleX(), - particle->getParticleScaleY() * emitter->getGlobalParticleScaleY(), - particle->getParticleScaleX() * emitter->getGlobalParticleScaleX() - ); - MTXScale(mtx2, scale.x, scale.y, scale.z); - MTXConcat(m, mtx2, m); - mProc.setTransform(i, m); - mProc.setAlpha(i, emitter->getGlobalAlpha()); - field_0xA0++; - break; - } - } - // Hide the particle - we're doing all the drawing ourselves - particle->setInvisibleParticleFlag(); -} - -void CommonEmitterCallback::draw(JPABaseEmitter *emitter) { - emitter->loadTexture(field_0x04, GX_TEXMAP0); -} - -void dMassObjEmitter_c::remove() { - setEmitterCallback(nullptr); - mpEmitterHead = nullptr; -} - -extern "C" u32 sNumberOfMgrs; // should be const? -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_119_; -extern "C" dMassObjEmitter_c *CURRENT_EFFECT_MANAGER_INIT; - -// various grasses being cut -extern const u16 sEffectResourceIds[]; - -void dJEffManager_c::setupEffects() { - for (s32 idx = 0; idx < sNumberOfMgrs; idx++) { - sManagers[idx].create(sEffectResourceIds[idx]); - } - - sShpEmitters[TsuboA].init("FX_TsuboA", "Tubo", false); - sShpEmitters[TsuboB].init("FX_TsuboB", "Tubo", false); - sShpEmitters[BRockA].init("FX_BRockA", "FXBRockA", true); - sShpEmitters[FruitA].init("FX_FruitA", "FruitA", false); - sShpEmitters[GrassCoil].init("FX_GrassCoil", "GrassCoilPiece", false); - sShpEmitters[BRockB].init("FX_BRockB", "RockFace", true); - sShpEmitters[Beehive].init("FX_Beehive", "Bee", false); - sShpEmitters[VeraRock].init("FX_VeraRock", "Bvd", false); - sShpEmitters[Pumpkin].init("FX_Pumpkin", "Pumpkin", false); - sShpEmitters[BRockC].init("FX_BRockC", "FX_BRockC", true); - sShpEmitters[F300BrokenRockWall_00].init("FX_F300BrokenRockWall_00", "F300BrokenRockWall", true); - sShpEmitters[F300BrokenRockWall_01].init("FX_F300BrokenRockWall_01", "F300BrokenRockWall", true); - sShpEmitters[F300BrokenRockWall_01T].init("FX_F300BrokenRockWall_01T", "F300BrokenRockWall", true); - sShpEmitters[LotusSeed].init("FX_LotusSeed", "LotusSeed", false); - sShpEmitters[Beamoss].init("FX_Beamoss", "Beamos", false); - sShpEmitters[Cakram].init("FX_Cakram", "Asura", false); - sShpEmitters[Dodai].init("FX_Dodai", "Asura", false); - sShpEmitters[LegParts].init("FX_LegParts", "Asura", false); - sShpEmitters[AsuraFloorBrk].init("FX_AsuraFloorBrk", "Asura", false); - sShpEmitters[BreakPillar].init("FX_BreakPillar", "BreakPillar", false); - sShpEmitters[Barrel].init("FX_Barrel", "Barrel", false); - sShpEmitters[BarrelBomb].init("FX_BarrelBomb", "BarrelBomb", false); - sShpEmitters[RockMiddle].init("FX_RockMiddle", "RockCarryMiddle", false); - sShpEmitters[BocoBone].init("FX_BocoBone", "Skull", false); - sShpEmitters[BRockStopA].init("FX_BRockStopA", "BRockStopA", true); - sShpEmitters[BWallD201].init("FX_BWallD201", "BWallD201", true); - sShpEmitters[Gunho].init("FX_Gunho", "Gunho", false); - sShpEmitters[TuboBig].init("FX_TuboBig", "TuboBig", false); - sShpEmitters[Amos].init("FX_Amos", "Amos", false); - sShpEmitters[HidokariBoneA].init("FX_HidokariBoneA", "HidokariS", false); - sShpEmitters[HidokariBoneB].init("FX_HidokariBoneB", "HidokariS", false); - sShpEmitters[Hydra].init("FX_Hydra", "Hydra", false); - sShpEmitters[Captain].init("FX_Captain", "Captain", false); - sShpEmitters[KibakoHang].init("FX_KibakoHang", "KibakoHang", true); - sShpEmitters[IslTreIRock].init("FX_IslTreIRock", "IslTreIRock", false); - sShpEmitters[BirdraceTarget].init("FX_BirdraceTarget", "BirdraceTarget", false); - sShpEmitters[FlowerA00F].init("FX_FlowerA00F", "FlowerA00", false); - sShpEmitters[FlowerA00L].init("FX_FlowerA00L", "FlowerA00", false); - sShpEmitters[FlowerB00].init("FX_FlowerB00", "FlowerB00", false); - sShpEmitters[FlowerB01].init("FX_FlowerB01", "FlowerB01", false); - sShpEmitters[GirahimClaymore].init("FX_GirahimClaymore", "GirahimBt03", false); - sShpEmitters[BirdKobunAEgg].init("FX_BirdKobunAEgg", "BirdEgg", false); - sShpEmitters[BirdKobunBEgg].init("FX_BirdKobunBEgg", "BirdEgg", false); - sShpEmitters[BirdRivalEgg].init("FX_BirdRivalEgg", "BirdEgg", false); - sShpEmitters[BWallAF200].init("FX_BWallAF200", "BWallAF200", true); - sShpEmitters[BWallBF200].init("FX_BWallBF200", "BWallBF200", true); - sShpEmitters[BWallF210].init("FX_BWallF210", "BWallF210", true); -} - -void dJEffManager_c::removeEffManagers() { - for (s32 i = 0; i < sNumberOfMgrs; i++) { - sManagers[i].remove(); - } - - // TODO - EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); - while (it != sPlayingEffectsList.GetEndIter()) { - EffectsList::Iterator itCopy; - ++itCopy; - it->remove(true); - it = itCopy; - } - - dParticle::mgr_c::GetInstance()->forceDeleteAllEmitter(); - for (s32 i = 0; i < 47; i++) { - sShpEmitters[i].clear(); - } -} - -void dJEffManager_c::doCustomSkywardSwordThing(f32 x, f32 y) { - EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); - while (it != sPlayingEffectsList.GetEndIter()) { - if (it->getEmitterCallback() != nullptr && it->hasEmitters() && it->getGroupId() < 12) { - it->getEmitterCallback()->vt_0x20(x, y); - } - ++it; - } - - for (s32 i = 0; i < 12; i++) { - dParticle::mgr_c::GetInstance()->doCustomSkywardSwordThing(i, x, y); - } -} - -// TODO explain this -static u32 sInts[] = {0x28, 0x29, 0x87, 0x88, 0x89, 0x8A, 0x8C, 0x8D, 0x91, 0x86, 0x1, 0x2}; -static u32 sInts2[] = {0x2, 0x87, 0x8B}; - -s32 dEmitterBase_c::getGroupId(u16 resourceId) { - u32 mask = dParticle::mgr_c::GetInstance()->getResUserWork(resourceId); - s32 bit = 1; - for (int i = 0; i < 10; i++) { - if ((mask & (1 << i)) != 0) { - bit = i; - break; - } - } - - int i = sInts[bit]; - // TODO explain this - if ((mask & 0x8000) != 0) { - if (i == 3) { - i = 2; - } else if (i == 5) { - i = 4; - } else if (i == 7) { - i = 6; - } else if (i == 1) { - i = 0; - } else if (i == 11) { - i = 10; - } - } - - return i; -} - -void dJEffManager_c::execute() { - for (EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); it != sPlayingEffectsList.GetEndIter();) { - EffectsList::Iterator itNext = it; - ++itNext; - it->execute(); - if (it->checkFlag(EffectsStruct::EMITTER_Fading)) { - it->realizeAlpha(); - } - if (it->checkFlag(EffectsStruct::EMITTER_0x1)) { - it->offFlag(EffectsStruct::EMITTER_0x1); - } else { - if (it->areAllEmittersDone()) { - it->remove(false); - } else { - it->onFlag(EffectsStruct::EMITTER_0x2); - } - } - it = itNext; - } - - if (dStageMgr_c::GetInstance() != nullptr) { - CURRENT_EFFECT_MANAGER_INIT->setGlobalAlpha(dStageMgr_c::GetInstance()->getGlobalAlpha()); - } - - for (s32 i = 0; i < sNumberOfMgrs; i++) { - mColor c = sManagers[i].getField_0x67C(); - sManagers[i].loadColors(&c, nullptr, 0, 0); - sManagers[i].execute(); - } - - if ((dBase_c::s_ExecuteControlFlags & 0x6F9) == 0) { - for (int i = 0; i < 12; i++) { - dParticle::mgr_c::GetInstance()->calc(i); - } - } else { - dParticle::mgr_c::GetInstance()->calc(9); - } - - dParticle::mgr_c::GetInstance()->calc(12); - dParticle::mgr_c::GetInstance()->calc(13); - dParticle::mgr_c::GetInstance()->calc(14); -} - -void dJEffManager_c::draw() { - for (s32 i = 0; i < 12; i++) { - sFogProcs[i].entry(); - } - - s2DEffects[0].addToDrawList(); - s2DEffects[1].addToDrawList(); - s2DEffects[2].addToDrawList(); - - for (s32 i = 0; i < 47; i++) { - sShpEmitters[i].draw(); - } -} - -bool EffectsStruct::shouldBePaused(dBase_c *owner) { - return owner != nullptr && !owner->isBasePropertyFlag(dBase_c::BASE_PROP_0x4) && - (EventManager::isInEvent() || owner->isProcControlFlag(fBase_c::DISABLE_EXECUTE) || - // TODO execute control flags - (owner->s_ExecuteControlFlags & 0x6fb)); -} - -bool dJEffManager_c::createEffManagers() { - EGG::Heap *heap = dHeap::work1Heap.heap; - ms_allocator = new (heap, 4) mHeapAllocator_c(); - sManagers = new (heap, 4) dMassObjEmitter_c[sNumberOfMgrs]; - - for (s32 idx = 0; idx < sNumberOfMgrs; idx++) { - // TODO explain this - if (sEffectResourceIds[idx] == PARTICLE_RESOURCE_ID_MAPPING_119_) { - CURRENT_EFFECT_MANAGER_INIT = &sManagers[idx]; - break; - } - } - - ms_allocator->createNewTempFrmHeap(-1, dHeap::work1Heap.heap, "dJEffManager_c::ms_allocator", 0x20, 0); - for (s32 idx = 0; idx < 2; idx++) { - sFogProcs[idx].create(idx, sInts[idx], -1, ms_allocator); - } - for (s32 idx = 2; idx < 12; idx++) { - sFogProcs[idx].create(idx, -1, sInts[idx], ms_allocator); - } - - for (s32 idx = 0; idx < 3; idx++) { - s2DEffects[idx].create(idx + 12, sInts2[idx]); - } - - for (s32 idx = 0; idx < 47; idx++) { - sShpEmitters[idx].create(ms_allocator); - } - - ms_allocator->adjustFrmHeapRestoreCurrent(); - for (int i = 0; i < 2; i++) { - sCommonEmitterCallbacks[i].init(i); - } - return true; -} - -dEmitterBase_c *dJEffManager_c::spawnEffectInternal( - u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, - const GXColor *c2, s32 idx1, s32 idx2 -) { - if (!sEmitter.createEmitters(effectResourceId, position, rot, scale, c1, c2, idx1, idx2)) { - return nullptr; - } - return &sEmitter; -} - -dEmitterBase_c *dJEffManager_c::spawnEffectInternal( - u16 effectResourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2 -) { - dEmitterBase_c *e = spawnEffectInternal(effectResourceId, mVec3_c::Zero, nullptr, nullptr, c1, c2, idx1, idx2); - if (e != nullptr) { - e->setTransform(transform); - } - return e; -} - -dEmitterBase_c *dJEffManager_c::spawnEffect( - u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, - const GXColor *c2, s32 idx1, s32 idx2 -) { - return spawnEffectInternal(effectResourceId, position, rot, scale, c1, c2, idx1, idx2); -} - -dEmitterBase_c *dJEffManager_c::spawnUIEffect( - u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, - const GXColor *c2 -) { - mVec3_c adjustedPosition(position.x * getlbl_80571C50(), position.y, position.z); - return spawnEffectInternal(effectResourceId, adjustedPosition, rot, scale, c1, c2, 0, 0); -} - -dEmitterBase_c *dJEffManager_c::spawnEffect( - u16 effectResourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2 -) { - return spawnEffectInternal(effectResourceId, transform, c1, c2, idx1, idx2); -} - -bool EffectsStruct::createEffect(u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2) { - return createEffect(true, resourceId, pos, rot, scale, c1, c2); -} - -bool EffectsStruct::createUIEffect(u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2) { - mVec3_c adjustedPosition(pos.x * getlbl_80571C50(), pos.y, pos.z); - return createEffect(true, resourceId, adjustedPosition, rot, scale, c1, c2); -} - -bool EffectsStruct::createEffect(u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2) { - return createEffect(true, resourceId, transform, c1, c2); -} - -bool EffectsStruct::createContinuousEffect(u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2) { - return createEffect(false, resourceId, pos, rot, scale, c1, c2); -} - -bool EffectsStruct::createContinuousUIEffect(u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2) { - mVec3_c adjustedPosition(pos.x * getlbl_80571C50(), pos.y, pos.z); - return createEffect(false, resourceId, adjustedPosition, rot, scale, c1, c2); -} - -bool EffectsStruct::createContinuousEffect(u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2) { - return createEffect(false, resourceId, transform, c1, c2); -} - -void dEmitterBase_c::loadColors( - JPABaseEmitter *emitter, const GXColor *color1, const GXColor *color2, s32 plltIdx1, s32 plltIdx2 -) { - BlurAndPaletteManager &mgr = BlurAndPaletteManager::GetInstance(); - u8 r1 = 0xFF; - u8 g1 = 0xFF; - u8 b1 = 0xFF; - u8 r2 = 0xFF; - u8 g2 = 0xFF; - u8 b2 = 0xFF; - u8 r, g, b; - - mColor c1 = mgr.GetCurrentSph().black3_000000; - mColor c2 = mgr.GetCurrentSph().black4_000000; - - u32 flags = emitter->getDynResUserWork(); - u32 factor = flags >> 24; - bool useBlack4 = false; - if (factor > 100) { - useBlack4 = true; - factor = factor - 100; - } - f32 fFactor = factor / 100.0f; - if (fFactor > 1.0f) { - fFactor = 1.0f; - } - - f32 scaleR, scaleG, scaleB; - if (!useBlack4) { - scaleR = 1.0f - (1.0f - (c1.r / 255.0f)) * fFactor; - scaleG = 1.0f - (1.0f - (c1.g / 255.0f)) * fFactor; - scaleB = 1.0f - (1.0f - (c1.b / 255.0f)) * fFactor; - } else { - const mColor &c = mgr.GetCurrentSph().black4_000000; - scaleR = 1.0f - (1.0f - (c2.r / 255.0f)) * fFactor; - scaleG = 1.0f - (1.0f - (c2.g / 255.0f)) * fFactor; - scaleB = 1.0f - (1.0f - (c2.b / 255.0f)) * fFactor; - } - - if (color1 != nullptr) { - r1 = color1->r; - g1 = color1->g; - b1 = color1->b; - } - - if (plltIdx1 > 0) { - if ((flags & 0x1000) != 0) { - const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); - r1 = entry.field_0x00.r; - g1 = entry.field_0x00.g; - b1 = entry.field_0x00.b; - } else if ((flags & 0x2000) != 0) { - const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); - r1 = entry.field_0x08.r; - g1 = entry.field_0x08.g; - b1 = entry.field_0x08.b; - } - } - - if (factor != 0) { - r = mgr.getfield_0x2F14() * r1 * scaleR; - g = mgr.getfield_0x2F18() * g1 * scaleG; - b = mgr.getfield_0x2F1C() * b1 * scaleB; - } else { - r = r1 * scaleR; - g = g1 * scaleG; - b = b1 * scaleB; - } - - emitter->setGlobalPrmColor(r, g, b); - - if (color2 != nullptr) { - r2 = color2->r; - g2 = color2->g; - b2 = color2->b; - } - - if (plltIdx1 > 0) { - if ((flags & 0x1000) != 0) { - const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); - r2 = entry.field_0x04.r; - g2 = entry.field_0x04.g; - b2 = entry.field_0x04.b; - } else if ((flags & 0x2000) != 0) { - const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); - r2 = entry.field_0x0C.r; - g2 = entry.field_0x0C.g; - b2 = entry.field_0x0C.b; - } - } - - if (factor != 0) { - r = mgr.getfield_0x2F14() * r2 * scaleR; - g = mgr.getfield_0x2F18() * g2 * scaleG; - b = mgr.getfield_0x2F1C() * b2 * scaleB; - } else { - r = r2 * scaleR; - g = g2 * scaleG; - b = b2 * scaleB; - } - - emitter->setGlobalEnvColor(r, g, b); -} - -void EffectsStruct::removeFromActiveEmittersList() { - if (dJEffManager_c::sPlayingEffectsList.GetPosition(this) != dJEffManager_c::sPlayingEffectsList.GetEndIter()) { - dJEffManager_c::sPlayingEffectsList.remove(this); - } -} - -bool EffectsStruct::createEffect( - bool bFlags, u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, - const GXColor *c2 -) { - if (!bFlags && canReuse(resourceId)) { - setPosRotScale(pos, rot, scale); - s32 idx1 = 0; - s32 idx2 = 0; - getOwnerPolyAttrs(&idx1, &idx2); - loadColors(c1, c2, idx1, idx2); - onFlag(EMITTER_0x1); - } else { - remove(false); - s32 idx1 = 0; - s32 idx2 = 0; - getOwnerPolyAttrs(&idx1, &idx2); - if (createEmitters(resourceId, pos, rot, scale, c1, c2, idx1, idx2)) { - addToActiveEmittersList(resourceId, bFlags); - } - } - - return hasEmitters(); -} - -bool EffectsStruct::createEffect( - bool bFlags, u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2 -) { - if (!bFlags && canReuse(resourceId)) { - s32 idx1 = 0; - s32 idx2 = 0; - getOwnerPolyAttrs(&idx1, &idx2); - loadColors(c1, c2, idx1, idx2); - onFlag(EMITTER_0x1); - } else { - remove(false); - s32 idx1 = 0; - s32 idx2 = 0; - getOwnerPolyAttrs(&idx1, &idx2); - if (createEmitters(resourceId, mVec3_c::Zero, nullptr, nullptr, c1, c2, idx1, idx2)) { - addToActiveEmittersList(resourceId, bFlags); - } - } - setTransform(transform); - return hasEmitters(); -} - -void dWaterEffect_c::init(dAcObjBase_c *base, f32 height, f32 scale, f32 f3) { - mEff.init(base); - mHeight = height; - mScale = scale; - mDepth = f3; -} - -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_91_; -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_127_; -void dWaterEffect_c::execute(f32 water, f32 ground) { - dAcObjBase_c *ac = getActor(); - bool b = getActorGroundPos(ac) < water && ground < water; - if (b) { - if (!mIsInWater) { - mIsInWater = true; - mVec3_c pos(ac->position.x, water, ac->position.z); - mVec3_c scale(mScale, mScale, mScale); - if (mIsSmall || water - ground < 50.0f) { - // For small objects or shallow water, create a - // particle FX upon entering water - mAng3_c rot(0, cM::rndF(65536.0f), 0); - dJEffManager_c::spawnEffect( - PARTICLE_RESOURCE_ID_MAPPING_91_, pos, &rot, &scale, nullptr, nullptr, 0, 0 - ); - } else { - // Otherwise spawn a "water spout" with a 3d model - dAcObjBase_c::create(fProfile::OBJ_WATER_SPOUT, -1, 0, &pos, nullptr, &scale, -1); - } - } - } else if (getActorGroundPos(ac) - 5.0f > water) { - mIsInWater = false; - } - - if (mIsInWater && getActorCeilPos(ac) > water) { - // Spawn effect upon leaving water - mVec3_c pos(ac->position.x, water, ac->position.z); - mVec3_c scale(mScale, mScale, mScale); - mEff.createEffect(PARTICLE_RESOURCE_ID_MAPPING_127_, pos, nullptr, &scale, nullptr, nullptr); - f32 rate = nw4r::math::FAbs(ac->forwardSpeed) * 0.02f; - rate = rate > 0.95f ? 0.95f : rate; - mEff.setRate(rate + 0.05f); - } -} diff --git a/src/toBeSorted/d_emitter.cpp b/src/toBeSorted/d_emitter.cpp new file mode 100644 index 00000000..e1e63501 --- /dev/null +++ b/src/toBeSorted/d_emitter.cpp @@ -0,0 +1,1229 @@ +// clang-format off +// vtable order +#include "JSystem/JParticle/JPAEmitter.h" +#include "JSystem/JParticle/JPAParticle.h" +#include "rvl/GX/GXTypes.h" +#include "toBeSorted/d_d3d.h" +// clang-format on + +#include "toBeSorted/d_emitter.h" + +#include "JSystem/JParticle/JPADrawInfo.h" +#include "JSystem/JParticle/JPAEmitter.h" +#include "c/c_math.h" +#include "common.h" +#include "d/a/d_a_base.h" +#include "d/a/obj/d_a_obj_base.h" +#include "d/d_base.h" +#include "d/d_heap.h" +#include "d/d_stage.h" +#include "d/d_stage_mgr.h" +#include "egg/core/eggHeap.h" +#include "f/f_base.h" +#include "f/f_profile_name.h" +#include "m/m3d/m3d.h" +#include "m/m_allocator.h" +#include "m/m_angle.h" +#include "m/m_color.h" +#include "m/m_mtx.h" +#include "m/m_vec.h" +#include "nw4r/g3d/g3d_camera.h" +#include "nw4r/g3d/g3d_state.h" +#include "nw4r/g3d/res/g3d_resfile.h" +#include "nw4r/g3d/res/g3d_resmat.h" +#include "nw4r/g3d/res/g3d_resmdl.h" +#include "nw4r/g3d/res/g3d_resshp.h" +#include "nw4r/math/math_arithmetic.h" +#include "sized_string.h" +#include "toBeSorted/arc_managers/oarc_manager.h" +#include "toBeSorted/blur_and_palette_manager.h" +#include "toBeSorted/d_d3d.h" +#include "toBeSorted/d_particle.h" +#include "toBeSorted/event_manager.h" +#include "toBeSorted/lyt_related_floats.h" + +#include "rvl/GX.h" +#include "rvl/MTX.h" + +// There's a data gap at 0x805013b4 (right after dParticleFogProc_c's vtable) +// so maybe that's a data split. Unsure how to get all those vtables to appear +// there though... + +void float_ordering_1(s32 a) { + (f32) a; +} + +void float_ordering_2() { + 255.0f; +} + +void float_ordering_3(u32 a) { + (f32) a; +} + +void float_ordering_4() { + 0.0f; +} + +dJEffManager_c::EffectsList dJEffManager_c::sPlayingEffectsList; +CommonEmitterCallback dJEffManager_c::sCommonEmitterCallbacks[2]; +dShpEmitter_c dJEffManager_c::sShpEmitters[47]; +dEmitterBase_c dJEffManager_c::sEmitter; +dParticleFogProc_c dJEffManager_c::sFogProcs[12]; +dEffect2D_c dJEffManager_c::s2DEffects[3]; + +// broken by -ipa file - reconsider splits? +dEmitterCallback_c::~dEmitterCallback_c() { + for (EmitterCallbackList::Iterator it = mEmitterList.GetBeginIter(); it != mEmitterList.GetEndIter();) { + EmitterCallbackList::Iterator itCopy = it; + ++itCopy; + it->setEmitterCallback(nullptr); + it = itCopy; + } +} + +void dEmitterCallback_c::remove(dEmitterBase_c *emitter) { + if (mEmitterList.GetPosition(emitter) == mEmitterList.GetEndIter()) { + return; + } + mEmitterList.remove(emitter); +} + +// broken by -ipa file - reconsider splits? +dParticleCallback_c::~dParticleCallback_c() { + for (ParticleCallbackList::Iterator it = mEmitterList.GetBeginIter(); it != mEmitterList.GetEndIter();) { + ParticleCallbackList::Iterator itCopy = it; + ++itCopy; + it->setParticleCallback(nullptr); + it = itCopy; + } +} + +void dParticleCallback_c::remove(dEmitterBase_c *emitter) { + if (mEmitterList.GetPosition(emitter) == mEmitterList.GetEndIter()) { + return; + } + mEmitterList.remove(emitter); +} + +dEmitterBase_c::~dEmitterBase_c() { + deactivateEmitters(); + if (mpEmitterCallback != nullptr) { + mpEmitterCallback->remove(this); + mpEmitterCallback = nullptr; + } + + if (mpParticleCallback != nullptr) { + mpParticleCallback->remove(this); + mpParticleCallback = nullptr; + } +} + +JPABaseEmitter *dEmitterBase_c::GetNextEmitter(JPABaseEmitter *head) { + return reinterpret_cast(head->getUserWork()); +} + +bool dEmitterBase_c::createEmitters( + u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, + const GXColor *c2, s32 idx1, s32 idx2 +) { + u16 iter = effectResourceId; + JPABaseEmitter *head = nullptr; + JPABaseEmitter *last; + for (; iter != 0xFFFF; iter = dParticle::mgr_c::GetInstance()->getJpnData(iter)) { + last = dParticle::mgr_c::GetInstance()->createEmitter( + iter, dJEffManager_c::getGroupId(iter), position, rot, scale + ); + if (last != nullptr) { + if (head != nullptr) { + head->setUserWork(reinterpret_cast(last)); + } else { + mpEmitterHead = last; + } + head = last; + last->setEmitterCallBackPtr(mpEmitterCallback); + last->setParticleCallBackPtr(mpParticleCallback); + loadColors(last, c1, c2, idx1, idx2); + } + } + + if (mpEmitterHead != nullptr) { + if (mpEmitterCallback != nullptr) { + // why last and not head? + mpEmitterCallback->create(last); + } + if (mpParticleCallback != nullptr) { + // why last and not head? + mpParticleCallback->create(last); + } + } + return mpEmitterHead != nullptr; +} + +void dEmitterBase_c::setEmitterCallback(dEmitterCallback_c *cb) { + if (mpEmitterCallback != cb) { + if (mpEmitterCallback != nullptr) { + mpEmitterCallback->remove(this); + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setEmitterCallBackPtr(nullptr); + } + } + mpEmitterCallback = cb; + if (cb != nullptr) { + cb->mEmitterList.append(this); + } + } +} + +void dEmitterBase_c::setParticleCallback(dParticleCallback_c *cb) { + if (mpParticleCallback != cb) { + if (mpParticleCallback != nullptr) { + mpParticleCallback->remove(this); + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setParticleCallBackPtr(nullptr); + } + } + mpParticleCallback = cb; + if (cb != nullptr) { + cb->mEmitterList.append(this); + } + } +} + +void dEmitterBase_c::setImmortal() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->becomeImmortalEmitter(); + } +} + +void dEmitterBase_c::deactivateEmitters() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setEmitterCallBackPtr(nullptr); + emitter->setParticleCallBackPtr(nullptr); + emitter->quitImmortalEmitter(); + if (emitter->mMaxFrame == 0) { + emitter->becomeInvalidEmitter(); + } + emitter->playCalcEmitter(); + } + mpEmitterHead = nullptr; +} + +void dEmitterBase_c::stopCalcEmitters() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->stopCalcEmitter(); + } +} + +void dEmitterBase_c::playCalcEmitters() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->playCalcEmitter(); + } +} + +void dEmitterBase_c::stopDrawParticles() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->stopDrawParticle(); + } +} + +void dEmitterBase_c::playDrawParticles() { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->playDrawParticle(); + } +} + +void dEmitterBase_c::setPosRotScale(const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setGlobalTranslation(position); + if (rot != nullptr) { + emitter->setGlobalRotation(*rot); + } + if (scale != nullptr) { + emitter->setGlobalScale(*scale); + } + } +} + +extern "C" f32 lbl_80571C50; +inline f32 getlbl_80571C50() { + return lbl_80571C50; +} +void dEmitterBase_c::setPosRotScaleWithScreenScale(const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale) { + mVec3_c adjustedPosition(position.x * getlbl_80571C50(), position.y, position.z); + setPosRotScale(adjustedPosition, rot, scale); +} + +void dEmitterBase_c::setTransform(const mMtx_c &mtx) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setGlobalSRTMatrix(mtx); + } +} + +void dEmitterBase_c::loadColors(const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + loadColors(emitter, c1, c2, idx1, idx2); + } +} + +void dEmitterBase_c::setGlobalAlpha(u8 alpha) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setGlobalAlpha(alpha); + } +} + +void dEmitterBase_c::setRate(f32 rate) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setRate(rate); + } +} + +void dEmitterBase_c::setDynamicsScale(const mVec3_c &scale) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setGlobalDynamicsScale(scale); + } +} + +void dEmitterBase_c::setParticleScale(const mVec3_c &scale) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setGlobalParticleScale(scale); + } +} + +void dEmitterBase_c::setAwayFromCenterSpeed(f32 speed) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setAwayFromCenterSpeed(speed); + } +} + +void dEmitterBase_c::setVolumeSize(u16 size) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setVolumeSize(size); + } +} + +void dEmitterBase_c::setLifeTime(s16 lifetime) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setLifeTime(lifetime); + } +} + +void dEmitterBase_c::attachEmitterCallbackId(s32 id) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setEmitterCallBackPtr(&dJEffManager_c::sCommonEmitterCallbacks[id]); + } +} + +void dEmitterBase_c::bindShpEmitter(s32 id, bool unused) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setParticleCallBackPtr(&dJEffManager_c::sShpEmitters[id]); + emitter->setGlobalAlpha(0); + } +} + +EffectsStruct::EffectsStruct() : mpOwner(nullptr), mFlags(0), mEffect(0) {} + +EffectsStruct::EffectsStruct(dBase_c *base) : mpOwner(base), mFlags(0), mEffect(0) {} + +EffectsStruct::~EffectsStruct() { + mpOwner = nullptr; + remove(false); +} + +void EffectsStruct::remove(bool bForceDeleteEmitters) { + offFlag(EMITTER_0x1); + JPABaseEmitter *emitter = bForceDeleteEmitters ? mpEmitterHead : nullptr; + deactivateEmitters(); + for (; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + dParticle::mgr_c::GetInstance()->forceDeleteEmitter(emitter); + } + removeFromActiveEmittersList(); +} + +void EffectsStruct::addToActiveEmittersList(u16 resourceId, bool bFlags) { + mEffect = resourceId; + mFlags = 0; + setImmortal(); + dJEffManager_c::sPlayingEffectsList.append(this); + onFlag(EMITTER_0x1); + if (bFlags) { + onFlag(EMITTER_0x4); + } + if (dParticle::mgr_c::GetInstance()->getResUserWork(resourceId) & 0x4000) { + onFlag(EMITTER_0x10); + } +} + +bool EffectsStruct::areAllEmittersDone() { + bool allDone = true; + + if (mpEmitterHead != nullptr) { + if (checkFlag(EMITTER_Fading) && mFadeTimer != 0) { + return false; + } + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + bool canDelete = emitter->isEnableDeleteEmitter(); + if (!canDelete) { + if (emitter->mMaxFrame == 0) { + emitter->becomeInvalidEmitter(); + } + allDone = false; + } + } + } + + return allDone; +} + +void EffectsStruct::execute() { + if (mpOwner != nullptr && (mpOwner->delete_request || mpOwner->lifecycle_state == fBase_c::TO_BE_DELETED)) { + mpOwner = nullptr; + } + if (dJEffManager_c::shouldBePaused(mpOwner)) { + if (!checkFlag(EMITTER_0x10)) { + stopCalcEmitters(); + if (mpOwner != nullptr && !mpOwner->isBasePropertyFlag(0x100)) { + if (!mpEmitterHead->checkStatus(JPAEmtrStts_StopDraw)) { + onFlag(EMITTER_0x20); + stopDrawParticles(); + } + } else { + if (checkFlag(EMITTER_0x20)) { + offFlag(EMITTER_0x20); + playDrawParticles(); + } + } + } + onFlag(EMITTER_0x1); + } else { + playCalcEmitters(); + if (checkFlag(EMITTER_0x20)) { + offFlag(EMITTER_0x20); + playDrawParticles(); + } + if (checkFlag(EMITTER_Fading) && mFadeTimer != 0) { + mFadeTimer--; + } + } +} + +bool EffectsStruct::getOwnerPolyAttrs(s32 *pOut1, s32 *pOut2) { + if (mpOwner != nullptr && mpOwner->group_type == fBase_c::ACTOR) { + dAcBase_c *actor = static_cast(mpOwner); + *pOut1 = actor->polyAttr0; + *pOut2 = actor->polyAttr1; + return true; + } else { + *pOut1 = 0; + *pOut2 = 0; + return false; + } +} + +void EffectsStruct::realizeAlpha() { + setGlobalAlpha(mFadeTimer * (255.0f / mFadeDuration)); +} + +void EffectsStruct::setFading(u8 lifetime) { + if (!checkFlag(EMITTER_Fading)) { + mFadeTimer = lifetime; + onFlag(EMITTER_Fading); + mFadeDuration = lifetime; + } +} + +bool dParticleFogProc_c::create(u32 idx, s32 prioOpa, s32 prioXlu, mHeapAllocator_c *alloc) { + if (!d3d::UnkProc::create(prioOpa, prioXlu, alloc)) { + return false; + } + mIdx = idx; + // idxes 0, 2, 4, 6, 10 + field_0x1C = idx <= 10 && ((1 << idx) & 0b10001010101) != 0; + return true; +} + +void dParticleFogProc_c::doDraw() { + nw4r::g3d::Camera c = m3d::getCurrentCamera(); + mMtx_c camMtx, texProjMtx; + c.GetCameraMtx(camMtx); + c.GetProjectionTexMtx(texProjMtx); + JPADrawInfo info; + MTXCopy(camMtx, info.mCamMtx); + MTXCopy(texProjMtx, info.mPrjMtx); + if (field_0x1C) { + m3d::getFogMgr(0); // ignored, maybe an inline on FogMgr? + nw4r::g3d::G3DState::LoadFog(0); + } else { + mColor c(0); + GXSetFog(GX_FOG_NONE, c, 0.0f, 0.0f, 0.0f, 0.0f); + GXSetFogRangeAdj(GX_FALSE, 0, nullptr); + } + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + dJEffManager_c::draw(&info, mIdx); +} + +extern "C" bool fn_80054AD0(); +void dEffect2D_c::draw() { + f32 proj[GX_PROJECTION_SZ]; + GXGetProjectionv(proj); + f32 base = proj[1]; + proj[1] = base / get_805751A4(); + GXSetProjectionv(proj); + f32 f = get_80575184() / 2; + mMtx_c mtx1, mtx2; + JPADrawInfo info; + + C_MTXLightOrtho(mtx1, -get_80575150(), get_80575150(), -f, f, 0.5f, 0.5f, 0.5f, 0.5f); + + MTXScale(mtx2, fn_80054AD0() ? get_805751A4() : 1.0f, 1.0f, 1.0f); + MTXCopy(mtx2, info.mCamMtx); + MTXCopy(mtx1, info.mPrjMtx); + dJEffManager_c::draw(&info, mGroupId); + proj[1] = base; + GXSetProjectionv(proj); +} + +void dEffect2D_c::create(u32 groupId, u8 prio) { + mGroupId = groupId; + setPriority(prio); +} + +bool dMassObjEmitterCallback_c::start(const mVec3_c &v1, dAcObjBase_c *owner) { + if (field_0x658 >= 50) { + return false; + } + + field_0x010[field_0x658] = v1; + field_0x4C0[field_0x658] = owner; + + field_0x658++; + return true; +} + +void dMassObjEmitterCallback_c::executeAfter(JPABaseEmitter *emitter) { + s32 createNumber = emitter->getCurrentCreateNumber(); + if (createNumber > 0) { + s32 i = 0; + mVec3_c translate; + emitter->getLocalTranslation(translate); + if (field_0x654 != 0) { + for (; i < field_0x654; i++) { + mVec3_c newTranslate = mVec3_c(field_0x268[i] + translate); + emitter->setGlobalTranslation(newTranslate); + for (s32 j = 0; j < createNumber; j++) { + JPABaseParticle *p = emitter->createParticle(); + if (p != nullptr) { + p->setOffsetPosition(newTranslate); + } + } + } + } + } +} + +void dMassObjEmitterCallback_c::execute() { + for (s32 i = field_0x654 - 1; i >= 0; i--) { + if (field_0x588[i] != nullptr) { + if (!dJEffManager_c::shouldBePaused(field_0x588[i]) || field_0x588[i]->delete_request || + field_0x588[i]->lifecycle_state == fBase_c::TO_BE_DELETED) { + if (field_0x654 != 0 && i != field_0x654 - 1) { + field_0x588[i] = field_0x588[field_0x654 - 1]; + field_0x268[i] = field_0x268[field_0x654 - 1]; + } else { + field_0x588[i] = nullptr; + } + field_0x654--; + } + } else { + field_0x654--; + } + } + if (field_0x658 + field_0x654 > 50) { + field_0x658 = 50 - field_0x654; + } + + for (u32 i = 0; i < field_0x658; i++) { + field_0x588[field_0x654] = field_0x4C0[i]; + field_0x268[field_0x654] = field_0x010[i]; + field_0x654++; + } + field_0x658 = 0; +} + +#pragma opt_unroll_loops off +void dMassObjEmitterCallback_c::clear() { + // TODO: this unrolls the entire loops, + // but the original code uses an unroll + // factor of 10 (5 iterations). 2D arrays + // work here but are probably fake. + field_0x654 = 0; + for (u32 i = 0; i < 50; i++) { + field_0x588[i] = nullptr; + } + field_0x658 = 0; + for (u32 i = 0; i < 50; i++) { + field_0x4C0[i] = nullptr; + } +} +#pragma opt_unroll_loops reset + +void dMassObjEmitter_c::create(u16 resourceId) { + setEmitterCallback(&mCallback); + if (createEmitters(resourceId, mVec3_c::Zero, nullptr, nullptr, nullptr, nullptr, 0, 0)) { + for (JPABaseEmitter *emitter = mpEmitterHead; emitter != nullptr; emitter = GetNextEmitter(emitter)) { + emitter->setStatus(JPAEmtrStts_Immortal); + emitter->setStatus(JPAEmtrStts_StopEmit); + } + mCallback.clear(); + } +} + +void dShpEmitterProc::doDraw() { + mMtx_c viewMtx; + getViewMtx(viewMtx); + s32 ctrl = 0; + mLightSetId = mAlpha[0]; + mMtx_c *pTransforms = mpTransforms; + bool *pFlags = mpFlags; + for (s32 idx = 0; idx < mCount;) { + if (*pFlags == false) { + mMtx_c mtx; + mtx.copyFrom(*pTransforms); + MTXConcat(viewMtx, mtx, mtx); + mMtx_c mtx2; + mtx2.copyFrom(mtx); + mtx2.fn_802F1C40(0, 1); + nw4r::math::MTX33 mtx3; + for (int a = 0; a < 3; a++) { + for (int b = 0; b < 3; b++) { + mtx3.m[a][b] = mtx2.m[a][b]; + } + } + if (mLightSetId != mAlpha[idx]) { + mLightSetId = mAlpha[idx]; + setupLight(); + } + mVec3_c v; + mVec3_c zero(0.0f, 0.0f, 0.0f); + MTXMultVec(*pTransforms, zero, v); + dShpProcBase_c::draw(&v); + nw4r::g3d::G3DState::SetViewPosNrmMtxArray(mtx, &mtx3, nullptr); + nw4r::g3d::Draw1Mat1ShpDirectly(nw4r::g3d::ResMat(nullptr), mShp, mtx, mtx2, ctrl, nullptr, nullptr); + if (ctrl == 0) { + ctrl = 2; + } + } + idx++; + pTransforms++; + pFlags++; + } + mpOwner->clear(); +} + +bool dShpEmitter_c::create(mHeapAllocator_c *alloc) { + if (!mProc.create(nw4r::g3d::ResMat(nullptr), nw4r::g3d::ResShp(nullptr), 100, alloc, false, nullptr)) { + return false; + } + mProc.setOwner(this); + return true; +} + +void dShpEmitter_c::init(const char *mdlName, const char *arcName, bool priority) { + clear(); + void *ptr = OarcManager::GetInstance()->getSubEntryData(arcName, "g3d/model.brres"); + if (ptr == nullptr) { + mProc.setResMat(nw4r::g3d::ResMat(nullptr)); + mProc.setResShp(nw4r::g3d::ResShp(nullptr)); + return; + } + + nw4r::g3d::ResFile f(ptr); + + if (strequals(arcName, "F300BrokenRockWall")) { + dStage_c::bindStageResToFile(&f); + } + + nw4r::g3d::ResMdl mdl = f.GetResMdl(mdlName); + nw4r::g3d::ResMat mat = mdl.GetResMat(0); + mProc.setResMat(mat); + mProc.setResShp(mdl.GetResShp(0)); + if (priority) { + mProc.setPriorityDraw(0x1C, 4); + } +} + +void dShpEmitter_c::clear() { + field_0xA0 = 0; + mProc.setAllFlags(); +} + +void dShpEmitter_c::draw(JPABaseEmitter *emitter, JPABaseParticle *particle) { + // TODO + for (s32 i = 0; i < 100; i++) { + if (mProc.isDrawDisabled(i)) { + mProc.setDrawDisabled(i, false); + mVec3_c pos; + mVec3_c velocity; + particle->getGlobalPosition(pos); + particle->getVelVec(velocity); + mVec3_c v; + if (cM::isZero(velocity.squareMagXZ())) { + v = mVec3_c::Ex; + } else { + v = mVec3_c::Ey.cross(velocity); + v.normalize(); + } + mMtx_c m; + m.setAxisRotation(v, mAng((u16)particle->mRotateAngle).radian2()); + m.setBase(3, pos); + mMtx_c mtx2; + mVec3_c scale( + particle->getParticleScaleX() * emitter->getGlobalParticleScaleX(), + particle->getParticleScaleY() * emitter->getGlobalParticleScaleY(), + particle->getParticleScaleX() * emitter->getGlobalParticleScaleX() + ); + MTXScale(mtx2, scale.x, scale.y, scale.z); + MTXConcat(m, mtx2, m); + mProc.setTransform(i, m); + mProc.setAlpha(i, emitter->getGlobalAlpha()); + field_0xA0++; + break; + } + } + // Hide the particle - we're doing all the drawing ourselves + particle->setInvisibleParticleFlag(); +} + +void CommonEmitterCallback::draw(JPABaseEmitter *emitter) { + emitter->loadTexture(field_0x04, GX_TEXMAP0); +} + +void dMassObjEmitter_c::remove() { + setEmitterCallback(nullptr); + mpEmitterHead = nullptr; +} + +extern "C" u32 sNumMassObjEmitters; // should be const? +extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_119_; +extern "C" dMassObjEmitter_c *CURRENT_EFFECT_MANAGER_INIT; + +s32 dJEffManager_c::getGroupId(u16 resourceId) { + u32 mask = dParticle::mgr_c::GetInstance()->getResUserWork(resourceId); + s32 bit = 1; + for (int i = 0; i < 10; i++) { + if ((mask & (1 << i)) != 0) { + bit = i; + break; + } + } + + int i = sInts[bit]; + // TODO explain this + if ((mask & 0x8000) != 0) { + if (i == 3) { + i = 2; + } else if (i == 5) { + i = 4; + } else if (i == 7) { + i = 6; + } else if (i == 1) { + i = 0; + } else if (i == 11) { + i = 10; + } + } + + return i; +} + +// various grasses being cut +extern const u16 sEffectResourceIds[]; + +void dJEffManager_c::setupEffects() { + for (s32 idx = 0; idx < sNumMassObjEmitters; idx++) { + sMassObjEmitters[idx].create(sEffectResourceIds[idx]); + } + + sShpEmitters[TsuboA].init("FX_TsuboA", "Tubo", false); + sShpEmitters[TsuboB].init("FX_TsuboB", "Tubo", false); + sShpEmitters[BRockA].init("FX_BRockA", "FXBRockA", true); + sShpEmitters[FruitA].init("FX_FruitA", "FruitA", false); + sShpEmitters[GrassCoil].init("FX_GrassCoil", "GrassCoilPiece", false); + sShpEmitters[BRockB].init("FX_BRockB", "RockFace", true); + sShpEmitters[Beehive].init("FX_Beehive", "Bee", false); + sShpEmitters[VeraRock].init("FX_VeraRock", "Bvd", false); + sShpEmitters[Pumpkin].init("FX_Pumpkin", "Pumpkin", false); + sShpEmitters[BRockC].init("FX_BRockC", "FX_BRockC", true); + sShpEmitters[F300BrokenRockWall_00].init("FX_F300BrokenRockWall_00", "F300BrokenRockWall", true); + sShpEmitters[F300BrokenRockWall_01].init("FX_F300BrokenRockWall_01", "F300BrokenRockWall", true); + sShpEmitters[F300BrokenRockWall_01T].init("FX_F300BrokenRockWall_01T", "F300BrokenRockWall", true); + sShpEmitters[LotusSeed].init("FX_LotusSeed", "LotusSeed", false); + sShpEmitters[Beamoss].init("FX_Beamoss", "Beamos", false); + sShpEmitters[Cakram].init("FX_Cakram", "Asura", false); + sShpEmitters[Dodai].init("FX_Dodai", "Asura", false); + sShpEmitters[LegParts].init("FX_LegParts", "Asura", false); + sShpEmitters[AsuraFloorBrk].init("FX_AsuraFloorBrk", "Asura", false); + sShpEmitters[BreakPillar].init("FX_BreakPillar", "BreakPillar", false); + sShpEmitters[Barrel].init("FX_Barrel", "Barrel", false); + sShpEmitters[BarrelBomb].init("FX_BarrelBomb", "BarrelBomb", false); + sShpEmitters[RockMiddle].init("FX_RockMiddle", "RockCarryMiddle", false); + sShpEmitters[BocoBone].init("FX_BocoBone", "Skull", false); + sShpEmitters[BRockStopA].init("FX_BRockStopA", "BRockStopA", true); + sShpEmitters[BWallD201].init("FX_BWallD201", "BWallD201", true); + sShpEmitters[Gunho].init("FX_Gunho", "Gunho", false); + sShpEmitters[TuboBig].init("FX_TuboBig", "TuboBig", false); + sShpEmitters[Amos].init("FX_Amos", "Amos", false); + sShpEmitters[HidokariBoneA].init("FX_HidokariBoneA", "HidokariS", false); + sShpEmitters[HidokariBoneB].init("FX_HidokariBoneB", "HidokariS", false); + sShpEmitters[Hydra].init("FX_Hydra", "Hydra", false); + sShpEmitters[Captain].init("FX_Captain", "Captain", false); + sShpEmitters[KibakoHang].init("FX_KibakoHang", "KibakoHang", true); + sShpEmitters[IslTreIRock].init("FX_IslTreIRock", "IslTreIRock", false); + sShpEmitters[BirdraceTarget].init("FX_BirdraceTarget", "BirdraceTarget", false); + sShpEmitters[FlowerA00F].init("FX_FlowerA00F", "FlowerA00", false); + sShpEmitters[FlowerA00L].init("FX_FlowerA00L", "FlowerA00", false); + sShpEmitters[FlowerB00].init("FX_FlowerB00", "FlowerB00", false); + sShpEmitters[FlowerB01].init("FX_FlowerB01", "FlowerB01", false); + sShpEmitters[GirahimClaymore].init("FX_GirahimClaymore", "GirahimBt03", false); + sShpEmitters[BirdKobunAEgg].init("FX_BirdKobunAEgg", "BirdEgg", false); + sShpEmitters[BirdKobunBEgg].init("FX_BirdKobunBEgg", "BirdEgg", false); + sShpEmitters[BirdRivalEgg].init("FX_BirdRivalEgg", "BirdEgg", false); + sShpEmitters[BWallAF200].init("FX_BWallAF200", "BWallAF200", true); + sShpEmitters[BWallBF200].init("FX_BWallBF200", "BWallBF200", true); + sShpEmitters[BWallF210].init("FX_BWallF210", "BWallF210", true); +} + +u32 dJEffManager_c::sInts[] = {0x28, 0x29, 0x87, 0x88, 0x89, 0x8A, 0x8C, 0x8D, 0x91, 0x86, 0x1, 0x2}; +u32 dJEffManager_c::sInts2[] = {0x2, 0x87, 0x8B}; + +void dJEffManager_c::removeEffManagers() { + for (s32 i = 0; i < sNumMassObjEmitters; i++) { + sMassObjEmitters[i].remove(); + } + + // TODO + EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); + while (it != sPlayingEffectsList.GetEndIter()) { + EffectsList::Iterator itCopy; + ++itCopy; + it->remove(true); + it = itCopy; + } + + dParticle::mgr_c::GetInstance()->forceDeleteAllEmitter(); + for (s32 i = 0; i < 47; i++) { + sShpEmitters[i].clear(); + } +} + +void dJEffManager_c::doCustomSkywardSwordThing(f32 x, f32 y) { + EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); + while (it != sPlayingEffectsList.GetEndIter()) { + if (it->getEmitterCallback() != nullptr && it->hasEmitters() && it->getGroupId() < 12) { + it->getEmitterCallback()->vt_0x20(x, y); + } + ++it; + } + + for (s32 i = 0; i < 12; i++) { + dParticle::mgr_c::GetInstance()->doCustomSkywardSwordThing(i, x, y); + } +} + +void dJEffManager_c::execute() { + for (EffectsList::Iterator it = sPlayingEffectsList.GetBeginIter(); it != sPlayingEffectsList.GetEndIter();) { + EffectsList::Iterator itNext = it; + ++itNext; + it->execute(); + if (it->checkFlag(EffectsStruct::EMITTER_Fading)) { + it->realizeAlpha(); + } + if (it->checkFlag(EffectsStruct::EMITTER_0x1)) { + it->offFlag(EffectsStruct::EMITTER_0x1); + } else { + if (it->areAllEmittersDone()) { + it->remove(false); + } else { + it->onFlag(EffectsStruct::EMITTER_0x2); + } + } + it = itNext; + } + + if (dStageMgr_c::GetInstance() != nullptr) { + CURRENT_EFFECT_MANAGER_INIT->setGlobalAlpha(dStageMgr_c::GetInstance()->getGlobalAlpha()); + } + + for (s32 i = 0; i < sNumMassObjEmitters; i++) { + mColor c = sMassObjEmitters[i].getField_0x67C(); + sMassObjEmitters[i].loadColors(&c, nullptr, 0, 0); + sMassObjEmitters[i].execute(); + } + + if ((dBase_c::s_ExecuteControlFlags & 0x6F9) == 0) { + for (int i = 0; i < 12; i++) { + dParticle::mgr_c::GetInstance()->calc(i); + } + } else { + dParticle::mgr_c::GetInstance()->calc(9); + } + + dParticle::mgr_c::GetInstance()->calc(12); + dParticle::mgr_c::GetInstance()->calc(13); + dParticle::mgr_c::GetInstance()->calc(14); +} + +void dJEffManager_c::draw() { + for (s32 i = 0; i < 12; i++) { + sFogProcs[i].entry(); + } + + s2DEffects[0].addToDrawList(); + s2DEffects[1].addToDrawList(); + s2DEffects[2].addToDrawList(); + + for (s32 i = 0; i < 47; i++) { + sShpEmitters[i].draw(); + } +} + +bool dJEffManager_c::shouldBePaused(dBase_c *owner) { + return owner != nullptr && !owner->isBasePropertyFlag(dBase_c::BASE_PROP_0x4) && + (EventManager::isInEvent() || owner->isProcControlFlag(fBase_c::DISABLE_EXECUTE) || + // TODO execute control flags + (owner->s_ExecuteControlFlags & 0x6fb)); +} + +void dJEffManager_c::draw(const JPADrawInfo *info, u32 groupId) { + dParticle::mgr_c::GetInstance()->draw(info, groupId); +} + +bool dJEffManager_c::createEffManagers() { + EGG::Heap *heap = dHeap::work1Heap.heap; + ms_allocator = new (heap, 4) mHeapAllocator_c(); + sMassObjEmitters = new (heap, 4) dMassObjEmitter_c[sNumMassObjEmitters]; + + for (s32 idx = 0; idx < sNumMassObjEmitters; idx++) { + // TODO explain this + if (sEffectResourceIds[idx] == PARTICLE_RESOURCE_ID_MAPPING_119_) { + CURRENT_EFFECT_MANAGER_INIT = &sMassObjEmitters[idx]; + break; + } + } + + ms_allocator->createNewTempFrmHeap(-1, dHeap::work1Heap.heap, "dJEffManager_c::ms_allocator", 0x20, 0); + for (s32 idx = 0; idx < 2; idx++) { + sFogProcs[idx].create(idx, sInts[idx], -1, ms_allocator); + } + for (s32 idx = 2; idx < 12; idx++) { + sFogProcs[idx].create(idx, -1, sInts[idx], ms_allocator); + } + + for (s32 idx = 0; idx < 3; idx++) { + s2DEffects[idx].create(idx + 12, sInts2[idx]); + } + + for (s32 idx = 0; idx < 47; idx++) { + sShpEmitters[idx].create(ms_allocator); + } + + ms_allocator->adjustFrmHeapRestoreCurrent(); + for (int i = 0; i < 2; i++) { + sCommonEmitterCallbacks[i].init(i); + } + return true; +} + +dEmitterBase_c *dJEffManager_c::spawnEffectInternal( + u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, + const GXColor *c2, s32 idx1, s32 idx2 +) { + if (!sEmitter.createEmitters(effectResourceId, position, rot, scale, c1, c2, idx1, idx2)) { + return nullptr; + } + return &sEmitter; +} + +dEmitterBase_c *dJEffManager_c::spawnEffectInternal( + u16 effectResourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2 +) { + dEmitterBase_c *e = spawnEffectInternal(effectResourceId, mVec3_c::Zero, nullptr, nullptr, c1, c2, idx1, idx2); + if (e != nullptr) { + e->setTransform(transform); + } + return e; +} + +dEmitterBase_c *dJEffManager_c::spawnEffect( + u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, + const GXColor *c2, s32 idx1, s32 idx2 +) { + return spawnEffectInternal(effectResourceId, position, rot, scale, c1, c2, idx1, idx2); +} + +dEmitterBase_c *dJEffManager_c::spawnUIEffect( + u16 effectResourceId, const mVec3_c &position, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, + const GXColor *c2 +) { + mVec3_c adjustedPosition(position.x * getlbl_80571C50(), position.y, position.z); + return spawnEffectInternal(effectResourceId, adjustedPosition, rot, scale, c1, c2, 0, 0); +} + +dEmitterBase_c *dJEffManager_c::spawnEffect( + u16 effectResourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2, s32 idx1, s32 idx2 +) { + return spawnEffectInternal(effectResourceId, transform, c1, c2, idx1, idx2); +} + +bool EffectsStruct::createEffect( + u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2 +) { + return createEffect(true, resourceId, pos, rot, scale, c1, c2); +} + +bool EffectsStruct::createUIEffect( + u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2 +) { + mVec3_c adjustedPosition(pos.x * getlbl_80571C50(), pos.y, pos.z); + return createEffect(true, resourceId, adjustedPosition, rot, scale, c1, c2); +} + +bool EffectsStruct::createEffect(u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2) { + return createEffect(true, resourceId, transform, c1, c2); +} + +bool EffectsStruct::createContinuousEffect( + u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2 +) { + return createEffect(false, resourceId, pos, rot, scale, c1, c2); +} + +bool EffectsStruct::createContinuousUIEffect( + u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, const GXColor *c2 +) { + mVec3_c adjustedPosition(pos.x * getlbl_80571C50(), pos.y, pos.z); + return createEffect(false, resourceId, adjustedPosition, rot, scale, c1, c2); +} + +bool EffectsStruct::createContinuousEffect( + u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2 +) { + return createEffect(false, resourceId, transform, c1, c2); +} + +bool dJEffManager_c::createMassObjEffect( + u16 effectResourceId, const mVec3_c &v1, dAcObjBase_c *owner, const mColor *color +) { + for (s32 i = 0; i < sNumMassObjEmitters; i++) { + if (effectResourceId == sEffectResourceIds[i]) { + if (color != nullptr) { + sMassObjEmitters[i].setField_0x67C(*color); + } else { + sMassObjEmitters[i].setField_0x67C(mColor(0xFF, 0xFF, 0xFF, 0xFF)); + } + return sMassObjEmitters[i].start(v1, owner); + } + } + + return false; +} + +void dEmitterBase_c::loadColors( + JPABaseEmitter *emitter, const GXColor *color1, const GXColor *color2, s32 plltIdx1, s32 plltIdx2 +) { + BlurAndPaletteManager &mgr = BlurAndPaletteManager::GetInstance(); + u8 r1 = 0xFF; + u8 g1 = 0xFF; + u8 b1 = 0xFF; + u8 r2 = 0xFF; + u8 g2 = 0xFF; + u8 b2 = 0xFF; + u8 r, g, b; + + mColor c1 = mgr.GetCurrentSph().black3_000000; + mColor c2 = mgr.GetCurrentSph().black4_000000; + + u32 flags = emitter->getDynResUserWork(); + u32 factor = flags >> 24; + bool useBlack4 = false; + if (factor > 100) { + useBlack4 = true; + factor = factor - 100; + } + f32 fFactor = factor / 100.0f; + if (fFactor > 1.0f) { + fFactor = 1.0f; + } + + f32 scaleR, scaleG, scaleB; + if (!useBlack4) { + scaleR = 1.0f - (1.0f - (c1.r / 255.0f)) * fFactor; + scaleG = 1.0f - (1.0f - (c1.g / 255.0f)) * fFactor; + scaleB = 1.0f - (1.0f - (c1.b / 255.0f)) * fFactor; + } else { + const mColor &c = mgr.GetCurrentSph().black4_000000; + scaleR = 1.0f - (1.0f - (c2.r / 255.0f)) * fFactor; + scaleG = 1.0f - (1.0f - (c2.g / 255.0f)) * fFactor; + scaleB = 1.0f - (1.0f - (c2.b / 255.0f)) * fFactor; + } + + if (color1 != nullptr) { + r1 = color1->r; + g1 = color1->g; + b1 = color1->b; + } + + if (plltIdx1 > 0) { + if ((flags & 0x1000) != 0) { + const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); + r1 = entry.field_0x00.r; + g1 = entry.field_0x00.g; + b1 = entry.field_0x00.b; + } else if ((flags & 0x2000) != 0) { + const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); + r1 = entry.field_0x08.r; + g1 = entry.field_0x08.g; + b1 = entry.field_0x08.b; + } + } + + if (factor != 0) { + r = mgr.getfield_0x2F14() * r1 * scaleR; + g = mgr.getfield_0x2F18() * g1 * scaleG; + b = mgr.getfield_0x2F1C() * b1 * scaleB; + } else { + r = r1 * scaleR; + g = g1 * scaleG; + b = b1 * scaleB; + } + + emitter->setGlobalPrmColor(r, g, b); + + if (color2 != nullptr) { + r2 = color2->r; + g2 = color2->g; + b2 = color2->b; + } + + if (plltIdx1 > 0) { + if ((flags & 0x1000) != 0) { + const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); + r2 = entry.field_0x04.r; + g2 = entry.field_0x04.g; + b2 = entry.field_0x04.b; + } else if ((flags & 0x2000) != 0) { + const PaletteEAF_smol_entry &entry = mgr.getSmallEAF(plltIdx1 - 1, plltIdx2); + r2 = entry.field_0x0C.r; + g2 = entry.field_0x0C.g; + b2 = entry.field_0x0C.b; + } + } + + if (factor != 0) { + r = mgr.getfield_0x2F14() * r2 * scaleR; + g = mgr.getfield_0x2F18() * g2 * scaleG; + b = mgr.getfield_0x2F1C() * b2 * scaleB; + } else { + r = r2 * scaleR; + g = g2 * scaleG; + b = b2 * scaleB; + } + + emitter->setGlobalEnvColor(r, g, b); +} + +void EffectsStruct::removeFromActiveEmittersList() { + if (dJEffManager_c::sPlayingEffectsList.GetPosition(this) != dJEffManager_c::sPlayingEffectsList.GetEndIter()) { + dJEffManager_c::sPlayingEffectsList.remove(this); + } +} + +bool EffectsStruct::createEffect( + bool bFlags, u16 resourceId, const mVec3_c &pos, const mAng3_c *rot, const mVec3_c *scale, const GXColor *c1, + const GXColor *c2 +) { + if (!bFlags && canReuse(resourceId)) { + setPosRotScale(pos, rot, scale); + s32 idx1 = 0; + s32 idx2 = 0; + getOwnerPolyAttrs(&idx1, &idx2); + loadColors(c1, c2, idx1, idx2); + onFlag(EMITTER_0x1); + } else { + remove(false); + s32 idx1 = 0; + s32 idx2 = 0; + getOwnerPolyAttrs(&idx1, &idx2); + if (createEmitters(resourceId, pos, rot, scale, c1, c2, idx1, idx2)) { + addToActiveEmittersList(resourceId, bFlags); + } + } + + return hasEmitters(); +} + +bool EffectsStruct::createEffect( + bool bFlags, u16 resourceId, const mMtx_c &transform, const GXColor *c1, const GXColor *c2 +) { + if (!bFlags && canReuse(resourceId)) { + s32 idx1 = 0; + s32 idx2 = 0; + getOwnerPolyAttrs(&idx1, &idx2); + loadColors(c1, c2, idx1, idx2); + onFlag(EMITTER_0x1); + } else { + remove(false); + s32 idx1 = 0; + s32 idx2 = 0; + getOwnerPolyAttrs(&idx1, &idx2); + if (createEmitters(resourceId, mVec3_c::Zero, nullptr, nullptr, c1, c2, idx1, idx2)) { + addToActiveEmittersList(resourceId, bFlags); + } + } + setTransform(transform); + return hasEmitters(); +} + +void dWaterEffect_c::init(dAcObjBase_c *base, f32 height, f32 scale, f32 f3) { + mEff.init(base); + mHeight = height; + mScale = scale; + mDepth = f3; +} + +extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_91_; +extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_127_; +void dWaterEffect_c::execute(f32 water, f32 ground) { + dAcObjBase_c *ac = getActor(); + bool b = getActorGroundPos(ac) < water && ground < water; + if (b) { + if (!mIsInWater) { + mIsInWater = true; + mVec3_c pos(ac->position.x, water, ac->position.z); + mVec3_c scale(mScale, mScale, mScale); + if (mIsSmall || water - ground < 50.0f) { + // For small objects or shallow water, create a + // particle FX upon entering water + mAng3_c rot(0, cM::rndF(65536.0f), 0); + dJEffManager_c::spawnEffect( + PARTICLE_RESOURCE_ID_MAPPING_91_, pos, &rot, &scale, nullptr, nullptr, 0, 0 + ); + } else { + // Otherwise spawn a "water spout" with a 3d model + dAcObjBase_c::create(fProfile::OBJ_WATER_SPOUT, -1, 0, &pos, nullptr, &scale, -1); + } + } + } else if (getActorGroundPos(ac) - 5.0f > water) { + mIsInWater = false; + } + + if (mIsInWater && getActorCeilPos(ac) > water) { + // Spawn effect while in water + mVec3_c pos(ac->position.x, water, ac->position.z); + mVec3_c scale(mScale, mScale, mScale); + mEff.createContinuousEffect(PARTICLE_RESOURCE_ID_MAPPING_127_, pos, nullptr, &scale, nullptr, nullptr); + f32 rate = nw4r::math::FAbs(ac->forwardSpeed) * 0.02f; + rate = rate > 0.95f ? 0.95f : rate; + mEff.setRate(rate + 0.05f); + } +} -- cgit v1.2.3