//
// Generated by dtk
// Translation Unit: d_particle.cpp
//

#include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_particle.h"
#include "JSystem/J3DGraphAnimator/J3DMaterialAttach.h"
#include "JSystem/JParticle/JPAEmitter.h"
#include "JSystem/JParticle/JPAEmitterManager.h"
#include "JSystem/JParticle/JPAParticle.h"
#include "JSystem/JParticle/JPAResourceManager.h"
#include "JSystem/JSupport/JSUList.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "SSystem/SComponent/c_malloc.h"
#include "d/actor/d_a_sea.h"
#include "d/d_bg_s_gnd_chk.h"
#include "d/d_com_inf_game.h"
#include "d/d_kankyo.h"
#include "d/d_kankyo_wether.h"
#include "d/d_resorce.h"
#include "m_Do/m_Do_dvd_thread.h"
#include "m_Do/m_Do_ext.h"
#include "m_Do/m_Do_graphic.h"
#include "m_Do/m_Do_lib.h"
#include "stdio.h"

/* 8007A4D8-8007A514       .text __ct__18dPa_modelEmitter_cFv */
dPa_modelEmitter_c::dPa_modelEmitter_c() {
    cNd_ForcedClear(this);
}

/* 8007A514-8007A804       .text __ct__21dPa_J3DmodelEmitter_cFP14JPABaseEmitterP12J3DModelDataR12dKy_tevstr_cP16J3DAnmTexPatternUsi */
dPa_J3DmodelEmitter_c::dPa_J3DmodelEmitter_c(JPABaseEmitter* emitter, J3DModelData* param_2, dKy_tevstr_c& param_3, J3DAnmTexPattern* param_4, u16 param_5, int param_6) {
    mpBaseEmitter = emitter;
    modelData = param_2;
    field_0x26 = param_6;
    tevStr = param_3;
    field_0x1c = param_4;
    if (!field_0x1c) {
        mpHeap = NULL;
        field_0x20 = NULL;
    } else {
        u16 r29 = field_0x1c->getUpdateMaterialNum();
        mpHeap = mDoExt_createSolidHeapToCurrent(r29 * 12 + 16, NULL, 0);
        if (mpHeap) {
            field_0x20 = new J3DTexNoAnm[r29];
            if (field_0x20) {
                field_0x1c->searchUpdateMaterialID(modelData);
                J3DTexNoAnm* tex = field_0x20;
                for (u16 i = 0; i < r29; i++) {
                    tex->setAnmIndex(i);
                    tex->setAnmTexPattern(field_0x1c);
                    tex++;
                }
                field_0x24 = param_5;
            }
            mDoExt_restoreCurrentHeap();
            mDoExt_adjustSolidHeap(mpHeap);
        }
    }
    emitter->becomeImmortalEmitter();
}

/* 8007A84C-8007A8C8       .text __dt__21dPa_J3DmodelEmitter_cFv */
dPa_J3DmodelEmitter_c::~dPa_J3DmodelEmitter_c()  {
    if (mpHeap) {
        mDoExt_destroySolidHeap(mpHeap);
    }
}

/* 8007A8C8-8007ADC4       .text draw__21dPa_J3DmodelEmitter_cFv */
void dPa_J3DmodelEmitter_c::draw() {
    mpBaseEmitter->playDrawParticle();

    JSUList<JPABaseParticle>* list = mpBaseEmitter->getParticleList();
    if (list != NULL) {
        Mtx sp44, sp14;
        mDoMtx_identity(sp44);
        mDoMtx_identity(sp14);
        for (JSULink<JPABaseParticle>* link = list->getFirst(); link != NULL; link = link->getNext()) {
            J3DModel* model = dPa_modelControl_c::newModel(modelData);
            if (model == NULL)
                return;

            JPABaseParticle* ptcl = link->getObject();
            JPADrawParams* params = ptcl->getDrawParamPPtr();
            JGeometry::TVec3<f32> vel;
            ptcl->getVelVec(vel);
            if (vel.isZero()) {
                vel.set(0.0f, 1.0f, 0.0f);
            } else {
                vel.normalize();
            }
            JGeometry::TVec3<f32> tmp;
            tmp.cross(params->mAxis, vel);
            if (tmp.isZero()) {
                tmp.set(0.0f, 0.0f, 1.0f);
            } else {
                tmp.normalize();
            }
            params->mAxis.cross(vel, tmp);
            params->mAxis.normalize();
            sp44[0][0] = params->mAxis.x;
            sp44[0][1] = vel.x;
            sp44[0][2] = tmp.x;
            sp44[1][0] = params->mAxis.y;
            sp44[1][1] = vel.y;
            sp44[1][2] = tmp.y;
            sp44[2][0] = params->mAxis.z;
            sp44[2][1] = vel.z;
            sp44[2][2] = tmp.z;
            
            f32 f1 = S2DEG(params->mRotateAngle);
            if (f1) {
                switch (field_0x26) {
                case 0:
                    MTXRotRad(sp14, 'y', DEG2RAD(f1));
                    break;
                case 1:
                    MTXRotRad(sp14, 'x', DEG2RAD(f1));
                    break;
                case 2:
                    MTXRotRad(sp14, 'z', DEG2RAD(f1));
                    break;
                case 3:
                    Vec sp08 = {1.0f, 1.0f, 1.0f};
                    MTXRotAxisRad(sp14, &sp08, DEG2RAD(f1));
                    break;
                }
                MTXConcat(sp44, sp14, sp44);
            }
            
            MTXConcat(sp44, sp14, sp44);

            JGeometry::TVec3<f32> temp;
            ptcl->getGlobalPosition(temp);
            sp44[0][3] = temp.x;
            sp44[1][3] = temp.y;
            sp44[2][3] = temp.z;

            JGeometry::TVec3<f32> scale;
            mpBaseEmitter->getGlobalParticleScale(scale);
            
            scale.x *= params->mScaleX;
            scale.y *= params->mScaleY;
            scale.z *= params->mScaleX;

            g_env_light.setLightTevColorType(model, &tevStr);

            if (field_0x1c != NULL && field_0x20 != NULL) {
                field_0x1c->setFrame(field_0x24);
                modelData->setTexNoAnimator(field_0x1c, field_0x20);
            }

            model->setBaseScale(scale);
            model->setBaseTRMtx(sp44);
            mDoExt_modelUpdateDL(model);
            if (field_0x1c != NULL) {
                modelData->removeTexNoAnimator(field_0x1c);
            }
        }
    }

    mpBaseEmitter->stopDrawParticle();
}

/* 8007ADC4-8007AECC       .text __ct__18dPa_modelControl_cFP12J3DModelData */
dPa_modelControl_c::dPa_modelControl_c(J3DModelData* modelData) {
    mModel = new dPa_J3Dmodel_c[0x80];
    JUT_ASSERT(271, mModel != NULL);

    dPa_J3Dmodel_c * model = mModel;
    for (s32 i = 0; i < 0x80; i++, model++) {
        model->mModel = mDoExt_J3DModel__create(modelData, 0x80000, 0x37221223);
        JUT_ASSERT(288, model->mModel != NULL);
    }

    cLs_Create(this);
}

/* 8007AECC-8007AED8       .text __ct__14dPa_J3Dmodel_cFv */
dPa_J3Dmodel_c::dPa_J3Dmodel_c() {
    mInit = 0;
}

/* 8007AED8-8007AF64       .text __dt__18dPa_modelControl_cFv */
dPa_modelControl_c::~dPa_modelControl_c() {
    dPa_modelEmitter_c* node = (dPa_modelEmitter_c*)mpHead;
    while (node) {
        dPa_modelEmitter_c* nextNode = (dPa_modelEmitter_c*)node->mpNextNode;
        cLs_SingleCut(node);
        delete node;
        node = nextNode;
    }
}

dPa_J3Dmodel_c * dPa_modelControl_c::mModel;

/* 8007AF64-8007B074       .text newModel__18dPa_modelControl_cFP12J3DModelData */
J3DModel * dPa_modelControl_c::newModel(J3DModelData* modelData) {
    dPa_J3Dmodel_c * model = mModel;
    for (s32 i = 0; i < 0x80; i++, model++) {
        if (model->mInit == 0) {
            model->mInit = 1;
            J3DModel * j3dmodel = model->mModel;
            j3dmodel->setModelData(modelData);

            J3DShapePacket * shapePacket = j3dmodel->getShapePacketArray();
            for (u16 j = 0; j < modelData->getShapeNum(); shapePacket++, j++) {
                shapePacket->setShape(modelData->getShapeNodePointer(j));
            }

            J3DMatPacket * matPacket = j3dmodel->getMatPacketArray();
            for (u16 j = 0; j < modelData->getMaterialNum(); matPacket++, j++) {
                J3DMaterial* mat = modelData->getMaterialNodePointer(j);
                matPacket->setMaterial(mat);
                J3DShapePacket * shapePacket = j3dmodel->getShapePacket(mat->getShape()->getIndex());
                matPacket->setInitShapePacket(shapePacket);
                matPacket->addShapePacket(shapePacket);
                matPacket->setTexture(modelData->getTexture());
                matPacket->setDisplayListObj(mat->getSharedDisplayListObj());
            }

            j3dmodel->getVertexBuffer()->setVertexData(&modelData->getVertexData());
            return model->mModel;
        }
    }

    return NULL;
}

/* 8007B074-8007B158       .text draw__18dPa_modelControl_cFv */
void dPa_modelControl_c::draw() {
    dPa_J3Dmodel_c* model = mModel;
    for (u32 i = 0; i < 0x80; i++, model++)
        model->mInit = 0;

    dKy_GxFog_set();

    for (dPa_J3DmodelEmitter_c* node = (dPa_J3DmodelEmitter_c*)mpHead; node != NULL;) {
        dPa_J3DmodelEmitter_c* nextNode = (dPa_J3DmodelEmitter_c*)node->mpNextNode;

        JPABaseEmitter* emitter = node->mpBaseEmitter;
        if (emitter->isEnableDeleteEmitter()) {
            emitter->quitImmortalEmitter();
            cLs_SingleCut(node);
            delete node;
        } else {
            node->draw();
        }

        node = nextNode;
    }
}

/* 8007B158-8007B194       .text __ct__19dPa_followEcallBackFUcUc */
dPa_followEcallBack::dPa_followEcallBack(u8 param_1, u8 param_2) {
    mRateOff = param_1;
    field_0x12 = param_2;
    field_0x13 = 0;
    mpEmitter = NULL;
}

/* 8007B194-8007B288       .text execute__19dPa_followEcallBackFP14JPABaseEmitter */
void dPa_followEcallBack::execute(JPABaseEmitter* emtr) {
    if (field_0x12 == 0 && !(mFlag & 2)) {
        emtr->setGlobalTranslation(mPos->x, mPos->y, mPos->z);
        if (mAngle != NULL) {
            JGeometry::TVec3<s16> tmp(mAngle->x, mAngle->y, mAngle->z);
            emtr->setGlobalRotation(tmp);
        }
    }

    if (emtr->isEnableDeleteEmitter()) {
        end();
    }

    if (mFlag & 1) {
        s16 alpha = emtr->getGlobalAlpha();
        cLib_chaseS(&alpha, 1, 4);
        emtr->setGlobalAlpha(alpha);
    }
}

/* 8007B288-8007B2C8       .text draw__19dPa_followEcallBackFP14JPABaseEmitter */
void dPa_followEcallBack::draw(JPABaseEmitter* emtr) {
    if (emtr->getGroupID() == 4) {
        GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    }
}

/* 8007B2C8-8007B360       .text setup__19dPa_followEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_followEcallBack::setup(JPABaseEmitter* emtr, const cXyz* pos, const csXyz* angle, s8) {
    end();
    if (field_0x13 == 0) {
        mpEmitter = emtr;
        emtr->becomeImmortalEmitter();
    }
    if (field_0x12 == 0) {
        if (mRateOff != 0)
            emtr->becomeContinuousParticle();
        mPos = pos;
        mAngle = angle;
        mFlag = 0;
    }
}

/* 8007B360-8007B3B0       .text end__19dPa_followEcallBackFv */
void dPa_followEcallBack::end() {
    if (mpEmitter == NULL)
        return;
    mpEmitter->becomeInvalidEmitter();
    mpEmitter->quitImmortalEmitter();
    mpEmitter->setEmitterCallBackPtr(NULL);
    mFlag |= 1;
    mpEmitter = NULL;
}

/* 8007B3B0-8007B444       .text __ct__18dPa_smokeEcallBackFUc */
dPa_smokeEcallBack::dPa_smokeEcallBack(u8 param_1) {
    GXColor local_18 = {0xa0, 0xa0, 0x80, 0xff};
    mColor = local_18;
    mRateOff = param_1;
    field_0x12 = 0;
    mTevstr = NULL;
    field_0x14 = -1;
    mWindOff = 0;
}

/* 8007B4B0-8007B558       .text __ct__18dPa_smokeEcallBackFUcUcUcUc */
dPa_smokeEcallBack::dPa_smokeEcallBack(u8 param_1, u8 param_2, u8 param_3, u8 param_4) {
    GXColor local_28 = {0xa0, 0xa0, 0x80, 0xff};
    mColor = local_28;
    mRateOff = param_1;
    field_0x12 = param_2;
    field_0x13 = param_4;
    mTevstr = NULL;
    field_0x14 = -1;
    mFlag = param_3;
    mWindOff = 0;

}

/* 8007B558-8007B5E8       .text __ct__18dPa_smokeEcallBackFRC8_GXColorP12dKy_tevstr_cUc */
dPa_smokeEcallBack::dPa_smokeEcallBack(const GXColor& param_1, dKy_tevstr_c* param_2, u8 param_3) {
    mColor = param_1;
    mTevstr = param_2;
    mRateOff = param_3;
    field_0x12 = 0;
    field_0x14 = -1;
}

/* 8007B5E8-8007B698       .text setup__18dPa_smokeEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_smokeEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    static dPa_smokePcallBack l_smokePcallBack;
    dPa_followEcallBack::setup(emitter, pos, rot, param_4);
    field_0x14 = param_4;
    emitter->setParticleCallBackPtr(dPa_control_c::getSmokePcallback());
    emitter->setUserWork(mWindOff);
}

/* 8007B73C-8007B804       .text initiateLighting__FR11_GXColorS10R8_GXColorR8_GXColor */
void initiateLighting(GXColorS10& dif, GXColor& amb, GXColor& k1) {
    GXSetChanCtrl(GX_COLOR0A0, GX_TRUE, GX_SRC_REG, GX_SRC_VTX, 1, GX_DF_CLAMP, GX_AF_NONE);
    GXSetChanAmbColor(GX_COLOR0A0, g_blackColor);
    GXSetTevColorS10(GX_TEVREG0, dif);
    GXSetTevKColor(GX_KCOLOR0, amb);
    GXSetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
    GXSetTevKColor(GX_KCOLOR1, k1);
    GXSetTevKColorSel(GX_TEVSTAGE2, GX_TEV_KCSEL_K1);
}

/* 8007B804-8007BB44       .text smokeEcallBack__FP14JPABaseEmitterP12dKy_tevstr_cSc8_GXColor */
void smokeEcallBack(JPABaseEmitter* emtr, dKy_tevstr_c* tevStr, s8, GXColor color) {
    GXFlush();
    GXLoadNrmMtxImm(emtr->getCamMtxPtr(), GX_PNMTX0);
    GXInvalidateVtxCache();
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
    GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
    GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
    GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
    if (!emtr->isZDraw()) {
        GXSetNumChans(1);
        if (tevStr == NULL) {
            GXColorS10 dif;
            dif.r = g_env_light.mActorC0.r;
            dif.g = g_env_light.mActorC0.g;
            dif.b = g_env_light.mActorC0.b;
            dif.a = 0xFF;
            GXColor amb;
            amb.r = g_env_light.mActorK0.r;
            amb.g = g_env_light.mActorK0.g;
            amb.b = g_env_light.mActorK0.b;
            amb.a = 0xFF;
            initiateLighting(dif, amb, color);
        } else {
            initiateLighting(tevStr->mColorC0, tevStr->mColorK0, color);
        }
        color.a = emtr->getGlobalAlpha();
        GXSetNumTexGens(2);
        GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
        GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_SRTG, GX_TG_COLOR0, GX_IDENTITY);
        emtr->loadTexture(1, GX_TEXMAP1);
        GXSetNumTevStages(3);                             
        GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C0, GX_CC_KONST, GX_CC_TEXC, GX_CC_ZERO);
        GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_RASA, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
        GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0);
        GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_C0, GX_CC_CPREV, GX_CC_TEXC, GX_CC_ZERO);
        GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_APREV, GX_CA_TEXA, GX_CA_ZERO);
        GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
        GXSetTevColorIn(GX_TEVSTAGE2, GX_CC_ZERO, GX_CC_CPREV, GX_CC_KONST, GX_CC_ZERO);
        GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevAlphaIn(GX_TEVSTAGE2, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
        GXSetTevAlphaOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
        GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
    }
}

/* 8007BB44-8007BB80       .text draw__18dPa_smokeEcallBackFP14JPABaseEmitter */
void dPa_smokeEcallBack::draw(JPABaseEmitter* emtr) {
    smokeEcallBack(emtr, mTevstr, field_0x14, mColor);
}

/* 8007BB80-8007BBD8       .text end__18dPa_smokeEcallBackFv */
void dPa_smokeEcallBack::end() {
    if (mpEmitter == NULL)
        return;

    mpEmitter->becomeInvalidEmitter();
    mpEmitter->quitImmortalEmitter();
    mpEmitter->setEmitterCallBackPtr(dPa_control_c::getSmokeEcallback());
    mFlag |= 1;
    mpEmitter = NULL;
}

/* 8007BBD8-8007BC84       .text dPa_setWindPower__FP15JPABaseParticle */
void dPa_setWindPower(JPABaseParticle* ptcl) {
    JGeometry::TVec3<f32> offsetPos;
    cXyz wind;
    f32 pow;
    ptcl->getOffsetPosition(offsetPos);
    dKyw_get_AllWind_vec((cXyz*)&offsetPos, &wind, &pow);
    offsetPos += wind * (pow * 8.0f);
    ptcl->setOffsetPosition(offsetPos);
}

/* 8007BC84-8007BCB4       .text execute__18dPa_smokePcallBackFP14JPABaseEmitterP15JPABaseParticle */
void dPa_smokePcallBack::execute(JPABaseEmitter* emtr, JPABaseParticle* ptcl) {
    if (emtr->getUserWork() == 0)
        dPa_setWindPower(ptcl);
}

/* 8007BCB4-8007C380       .text draw__18dPa_smokePcallBackFP14JPABaseEmitterP15JPABaseParticle */
void dPa_smokePcallBack::draw(JPABaseEmitter* emtr, JPABaseParticle* ptcl) {
    /* Nonmatching */
}

/* 8007C380-8007C3B0       .text draw__22dPa_selectTexEcallBackFP14JPABaseEmitter */
void dPa_selectTexEcallBack::draw(JPABaseEmitter* emtr) {
    emtr->loadTexture(mTexNo, GX_TEXMAP0);
}

/* 8007C3B0-8007C420       .text __ct__19dPa_simpleEcallBackFv */
dPa_simpleEcallBack::dPa_simpleEcallBack() {
    mpBaseEmitter = NULL;
    mCount = 0;
}

/* 8007C45C-8007C460       .text __ct__16dPa_simpleData_cFv */
dPa_simpleData_c::dPa_simpleData_c() {}

/* 8007C460-8007C618       .text executeAfter__19dPa_simpleEcallBackFP14JPABaseEmitter */
void dPa_simpleEcallBack::executeAfter(JPABaseEmitter* emitter) {
    s32 r28 = emitter->getCurrentCreateNumber();
    if (r28 <= 0) {
        mCount = 0;
    } else {
        dPa_simpleData_c* simpleData = mSimpleData;
        emitter->playCreateParticle();
        while (mCount != 0) {
            if (!mDoLib_clipper::clip(j3dSys.getViewMtx(), simpleData->mPos, 200.0f)) {
                emitter->setGlobalTranslation(simpleData->mPos.x, simpleData->mPos.y, simpleData->mPos.z);
                emitter->setGlobalPrmColor(simpleData->mPrmColor.r, simpleData->mPrmColor.g, simpleData->mPrmColor.b);
                emitter->setGlobalAlpha(simpleData->mPrmColor.a);
                emitter->setGlobalEnvColor(simpleData->mEnvColor[0], simpleData->mEnvColor[1], simpleData->mEnvColor[2]);
                for (int i = 0; i < r28; i++) {
                    JPABaseParticle* particle = emitter->createParticle();
                    if (particle == NULL) {
                        break;
                    }
                    particle->setOffsetPosition(simpleData->mPos.x, simpleData->mPos.y, simpleData->mPos.z);
                    if (simpleData->mbAffectedByWind) {
                        static dPa_windPcallBack l_windPcallBack;
                        particle->setCallBackPtr(&l_windPcallBack);
                    }
                }
            }
            mCount--;
            simpleData++;
        }
    }
    emitter->stopCreateParticle();
}

/* 8007C674-8007C6EC       .text draw__19dPa_simpleEcallBackFP14JPABaseEmitter */
void dPa_simpleEcallBack::draw(JPABaseEmitter* emtr) {
    if (mbIsSmoke)
        smokeEcallBack(emtr, NULL, -1, (GXColor){ 0xA0, 0xA0, 0x80, 0xFF });

    if (emtr->getGroupID() == dPa_control_c::dPtclGroup_Projection_e)
        GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
}

/* 8007C6EC-8007C774       .text create__19dPa_simpleEcallBackFP17JPAEmitterManagerUsUc */
JPABaseEmitter* dPa_simpleEcallBack::create(JPAEmitterManager* manager, u16 effectID, u8 groupID) {
    mpBaseEmitter = NULL;
    mGrpID = groupID;
    mResID = effectID;
    if (createEmitter(manager)) {
        if (
            effectID == dPa_name::ID_AK_ST_O_BKMSATTACKSMOKE00
#if VERSION != VERSION_DEMO
            || effectID == dPa_name::ID_AK_ST_O_KGTT2JUMPHANDSMOKE00
#endif
        ) {
            mbIsSmoke = true;
#if VERSION == VERSION_DEMO
            mpBaseEmitter->setEmitterCallBackPtr(dPa_control_c::getSmokeEcallback());
#endif
            mpBaseEmitter->setParticleCallBackPtr(dPa_control_c::getSmokePcallback());
        } else {
            mbIsSmoke = false;
        }
    }
    return mpBaseEmitter;
}

/* 8007C774-8007C840       .text createEmitter__19dPa_simpleEcallBackFP17JPAEmitterManager */
JPABaseEmitter* dPa_simpleEcallBack::createEmitter(JPAEmitterManager* manager) {
    if (!mpBaseEmitter) {
        static JGeometry::TVec3<f32> pos(0.0f, 0.0f, 0.0f);
        mpBaseEmitter = manager->createSimpleEmitterID(pos, mResID, mGrpID, dPa_control_c::getRM_ID(mResID), NULL, NULL);
        if (!mpBaseEmitter) {
            return mpBaseEmitter;
        }
        mpBaseEmitter->setEmitterCallBackPtr(this);
        mpBaseEmitter->setMaxFrame(0);
        mpBaseEmitter->stopCreateParticle();
    }
    return mpBaseEmitter;
}

/* 8007C840-8007C8C4       .text set__19dPa_simpleEcallBackFPC4cXyzUcRC8_GXColorRC8_GXColori */
bool dPa_simpleEcallBack::set(const cXyz* pos, u8 alpha, const GXColor& prm, const GXColor& env, int flag) {
    if (mCount >= (s32)ARRAY_SIZE(mSimpleData))
        return false;

    dPa_simpleData_c& data = mSimpleData[mCount];
    data.mPos = *pos;
    data.mPrmColor.r = prm.r;
    data.mPrmColor.g = prm.g;
    data.mPrmColor.b = prm.b;
    data.mPrmColor.a = alpha;
    data.mEnvColor[0] = env.r;
    data.mEnvColor[1] = env.g;
    data.mEnvColor[2] = env.b;
    data.mbAffectedByWind = flag;
    mCount++;
    return true;
}

/* 8007C8C4-8007C8E8       .text execute__17dPa_windPcallBackFP14JPABaseEmitterP15JPABaseParticle */
void dPa_windPcallBack::execute(JPABaseEmitter* emtr, JPABaseParticle* ptcl) {
    dPa_setWindPower(ptcl);
}

static GXColor l_lifeBallColor[] = {
    0xeb, 0x20, 0x78, 0xff,
    0x20, 0xf1, 0x9b, 0xff,
    0xeb, 0xd7, 0x2f, 0xff
};

dPa_selectTexEcallBack dPa_control_c::mTsubo[] = {
    dPa_selectTexEcallBack(0),
    dPa_selectTexEcallBack(1),
    dPa_selectTexEcallBack(2),
    dPa_selectTexEcallBack(3),
};

dPa_setColorEcallBack dPa_control_c::mLifeBall[] = {
    dPa_setColorEcallBack(l_lifeBallColor[0]),
    dPa_setColorEcallBack(l_lifeBallColor[1]),
    dPa_setColorEcallBack(l_lifeBallColor[2]),
};

JPAEmitterManager* dPa_control_c::mEmitterMng;
dPa_stripesEcallBack dPa_control_c::mStripes;
dPa_kageroEcallBack dPa_control_c::mKagero;
dPa_smokeEcallBack dPa_control_c::mSmokeEcallback(0, 1, 1, 1);
dPa_smokePcallBack dPa_control_c::mSmokePcallback;
dPa_singleRippleEcallBack dPa_control_c::mSingleRippleEcallBack;
dPa_ripplePcallBack dPa_control_c::mRipplePcallBack;
dPa_bombSmokeEcallBack dPa_control_c::mBombSmokeEcallBack;
Mtx dPa_control_c::mWindViewMatrix;
u8 dPa_control_c::mStatus;

/* 8007C8E8-8007C9A4       .text __ct__13dPa_control_cFv */
dPa_control_c::dPa_control_c() {
    mHeap = mDoExt_createSolidHeapFromSystem(0x16e800, 0);
    JUT_ASSERT(VERSION_SELECT(1240, 1240, 1240, 1241), mHeap != NULL);
    mSceneNo = 0xFF;
    mCount = 0;
    mEmitterMng = NULL;
    mNumSimple = 0;
    mCommonResMng = NULL;
    mSceneResMng = NULL;
}

/* 8007CA28-8007CA30       .text getRM_ID__13dPa_control_cFUs */
u8 dPa_control_c::getRM_ID(u16 uid) {
    return (uid >> 15) & 0x01;
}

/* 8007CA30-8007CA98       .text swapFrameBufferTexture__13dPa_control_cFv */
void dPa_control_c::swapFrameBufferTexture() {
    if (mCommonResMng) {
        mCommonResMng->swapTexture(mDoGph_gInf_c::mFrameBufferTimg, "AK_kagerouSwap00");
    }
    if (mSceneResMng) {
        mSceneResMng->swapTexture(mDoGph_gInf_c::mFrameBufferTimg, "AK_kagerouSwap00");
    }
}

/* 8007CA98-8007CCC8       .text createCommon__13dPa_control_cFPCv */
void dPa_control_c::createCommon(const void* param_1) {
    mCommonResMng = new (mHeap, 0) JPAResourceManager(param_1, mHeap);
    JUT_ASSERT(VERSION_SELECT(1312, 1312, 1313, 1314), mCommonResMng != NULL);
    mCommonResMng->swapTexture(mDoGph_gInf_c::mFrameBufferTimg, "AK_kagerouSwap00");
    mEmitterMng = new(mHeap, 0) JPAEmitterManager(mCommonResMng, 3000, 150, 200, mHeap);
    JUT_ASSERT(VERSION_SELECT(1322, 1322, 1324, 1325), mEmitterMng != NULL);
    JKRHeap* oldHeap = mDoExt_setCurrentHeap(mHeap);
    mModelControl = new dPa_modelControl_c((J3DModelData*)dComIfG_getObjectRes("Always", dRes_INDEX_ALWAYS_BDL_MPM_TUBO_e));
    JUT_ASSERT(VERSION_SELECT(1329, 1329, 1332, 1333), mModelControl != NULL);
    for (u16 i = 0; i < 8; i++) {
        u16 id = dPa_name::j_o_id[i];
        if (mCommonResMng->pEmtrRes->checkUserIndexDuplication(id)) {
            u8 groupID = (id & 0x4000) ? dPtclGroup_Projection_e :
                         dPtclGroup_Normal_e;
            newSimple(id, groupID);
        }
    }
    mNumSimpleCommon = mNumSimple;
    mDoExt_setCurrentHeap(oldHeap);
#if VERSION >= VERSION_USA
    mDoExt_adjustSolidHeap(mHeap);
#endif
}

/* 8007CCC8-8007CE50       .text createRoomScene__13dPa_control_cFPCv */
void dPa_control_c::createRoomScene(const void* param_1) {
    mSceneHeap = mDoExt_createSolidHeapFromGame(0, 0);
    JUT_ASSERT(VERSION_SELECT(1360, 1360, 1369, 1370), mSceneHeap != NULL);
    mpData = param_1;
    mSceneResMng = new (mSceneHeap, 0) JPAResourceManager(mpData, mSceneHeap);
    JUT_ASSERT(VERSION_SELECT(1364, 1364, 1373, 1374), mSceneResMng != NULL);
    mSceneResMng->swapTexture(mDoGph_gInf_c::mFrameBufferTimg, "AK_kagerouSwap00");
    mEmitterMng->pResMgrArray[1] = mSceneResMng;
    mDoExt_adjustSolidHeap(mSceneHeap);
    for (u16 i = 0; i < 34; i++) {
        u16 id = dPa_name::s_o_id[i];
        if (mSceneResMng->pEmtrRes->checkUserIndexDuplication(id)) {
            u8 groupID = (id & 0x4000) ? dPtclGroup_Projection_e :
                         (id & 0x2000) ? dPtclGroup_Toon_e :
                         dPtclGroup_Normal_e;
            newSimple(id, groupID);
        }
    }
}

/* 8007CE50-8007CF20       .text readScene__13dPa_control_cFUcPP21mDoDvdThd_toMainRam_c */
bool dPa_control_c::readScene(u8 i_no, mDoDvdThd_toMainRam_c** param_2) {
    if (i_no == 0xff) {
        return false;
    }
    if (mCount++) {
        JUT_ASSERT(VERSION_SELECT(1404, 1404, 1415, 1416), i_no != mSceneNo);
        return true;
    }
    mSceneNo = i_no;
    static char jpcName[32];
    sprintf(jpcName, "/res/Particle/Pscene%03d.jpc", i_no);
    *param_2 = mDoDvdThd_toMainRam_c::create(jpcName, JKRArchive::DEFAULT_MOUNT_DIRECTION, NULL);
    return true;
}

/* 8007CF20-8007CF98       .text createScene__13dPa_control_cFPCv */
void dPa_control_c::createScene(const void* data) {
    for (s32 i = 0; i < mNumSimpleCommon; i++)
        mSimpleCallbacks[i].createEmitter(mEmitterMng);
    if (data != NULL)
        createRoomScene(data);
}

/* 8007CF98-8007D028       .text removeRoomScene__13dPa_control_cFv */
bool dPa_control_c::removeRoomScene() {
    if (mSceneHeap != NULL && mCount != 0 && --mCount == 0) {
        mEmitterMng->clearResourceManager(1);
        mDoExt_destroySolidHeap(mSceneHeap);
        mSceneHeap = NULL;
        mSceneResMng = NULL;
        JKRFree((void*)mpData);
        mNumSimple = mNumSimpleCommon;
        return true;
    } else {
        return false;
    }
}

/* 8007D028-8007D094       .text removeScene__13dPa_control_cFv */
void dPa_control_c::removeScene() {
    removeRoomScene();
    for (s32 i = 0; i < mNumSimpleCommon; i++)
        mSimpleCallbacks[i].mpBaseEmitter = NULL;
    mEmitterMng->forceDeleteAllEmitter();
    mModelControl->~dPa_modelControl_c();
}

/* 8007D094-8007D0DC       .text calc3D__13dPa_control_cFv */
void dPa_control_c::calc3D() {
    for (u8 i = dPtclGroup_Normal_e; i <= dPtclGroup_Wind_e; i++)
        mEmitterMng->calc(i);
}

/* 8007D0DC-8007D124       .text calc2D__13dPa_control_cFv */
void dPa_control_c::calc2D() {
    for (u8 i = dPtclGroup_2Dfore_e; i <= dPtclGroup_2Dback_e; i++)
        mEmitterMng->calc(i);
}

/* 8007D124-8007D16C       .text calcMenu__13dPa_control_cFv */
void dPa_control_c::calcMenu() {
    for (u8 i = dPtclGroup_2DmenuFore_e; i <= dPtclGroup_2DmenuBack_e; i++)
        mEmitterMng->calc(i);
}

/* 8007D16C-8007D1DC       .text draw__13dPa_control_cFP11JPADrawInfoUc */
void dPa_control_c::draw(JPADrawInfo* param_1, u8 param_2) {
    if (!mEmitterMng) {
        return;
    }
    j3dSys.reinitGX();
    dKy_setLight_again();
    mEmitterMng->draw(param_1, param_2);
    GXSetAlphaUpdate(GX_DISABLE);
#if VERSION != VERSION_DEMO
    GXSetNumIndStages(0);
#endif
}

/* 8007D1DC-8007D378       .text set__13dPa_control_cFUcUsPC4cXyzPC5csXyzPC4cXyzUcP18dPa_levelEcallBackScPC8_GXColorPC8_GXColorPC4cXyz */
JPABaseEmitter* dPa_control_c::set(u8 groupID, u16 userID, const cXyz* pos, const csXyz* angle, const cXyz* scale, u8 alpha, dPa_levelEcallBack* pCallBack, s8 setupInfo, const GXColor* prm, const GXColor* env, const cXyz* globalScale) {
    JGeometry::TVec3<f32> tmp(pos->x, pos->y, pos->z);
    JPABaseEmitter* emtr = mEmitterMng->createSimpleEmitterID(tmp, userID, groupID, getRM_ID(userID), NULL, NULL);
    if (emtr == NULL)
        return NULL;

    if (angle != NULL) {
        JGeometry::TVec3<s16> tmp2(angle->x, angle->y, angle->z);
        emtr->setGlobalRotation(tmp2);
    }

    if (scale != NULL) {
        JGeometry::TVec3<f32> tmp2(scale->x, scale->y, scale->z);
        emtr->setGlobalScale(tmp2);
    }

    emtr->setGlobalAlpha(alpha);
    if (pCallBack != NULL) {
        emtr->setEmitterCallBackPtr(pCallBack);
        pCallBack->setup(emtr, pos, angle, setupInfo);
    } else if (userID & 0x4000) {
        emtr->setEmitterCallBackPtr(getKageroEcallBack());
    }

    if (prm != NULL)
        emtr->setGlobalPrmColor(prm->r, prm->g, prm->b);
    if (env != NULL)
        emtr->setGlobalEnvColor(env->r, env->g, env->b);
    if (globalScale != NULL) {
        JGeometry::TVec3<f32> tmp2(globalScale->x, globalScale->y, globalScale->z);
        emtr->setGlobalParticleScale(tmp2);
    }
    return emtr;
}

/* 8007D378-8007D414       .text setBombSmoke__13dPa_control_cFUsPC4cXyzPC5csXyzPC4cXyzUc */
JPABaseEmitter* dPa_control_c::setBombSmoke(u16 userID, const cXyz* pos, const csXyz* angle, const cXyz* scale, u8 alpha) {
    JPABaseEmitter* emtr = setToonP1(userID, pos, angle, scale, alpha, &mBombSmokeEcallBack, -1, NULL, NULL, NULL);
    if (emtr != NULL) {
        if (userID == 0x2009)
            emtr->setUserWork(0x460501);
        else
            emtr->setUserWork(0x280478);
    }
    return emtr;
}

/* 8007D414-8007D998       .text setSimpleLand__13dPa_control_cFiPC4cXyzPC5csXyzfffP12dKy_tevstr_cPii */
JPABaseEmitter* dPa_control_c::setSimpleLand(int code, const cXyz* pos, const csXyz* angle, f32 scale1, f32 scale2, f32 scale3, dKy_tevstr_c* i_tevStr, int* i_return_id, int flag) {
    JUT_ASSERT(VERSION_SELECT(1698, 1702, 1713, 1714), (i_tevStr != NULL) && (i_return_id != NULL));
    *i_return_id = checkAtrCodeEffect(code);
    if (*i_return_id == -1)
        return NULL;

    if (code == -1) {
        dBgS_ObjGndChk chk;
        cXyz chkPos(pos->x, pos->y + 10.0f, pos->z);
        chk.SetPos(&chkPos);
        if (dComIfG_Bgsp()->GroundCross(&chk) != -G_CM3D_F_INF) {
            code = dComIfG_Bgsp()->GetAttributeCode(chk);
        }
    }

    cXyz ptclScale;
    JPABaseEmitter* emtr = NULL;
    if (*i_return_id == dPa_name::ID_AK_JN_ELEMENTSHIBUKI00) {
        if (flag & 0x04) {
            ptclScale.set(scale3, scale3, scale3);
            GXColor amb, dif;
            dKy_get_seacolor(&amb, &dif);
            if (flag & 0x10) {
                emtr = setNormalP1(*i_return_id, pos, angle, &ptclScale, 0xFF, NULL, -1, &amb, NULL, NULL);
            } else {
                emtr = setNormal(*i_return_id, pos, angle, &ptclScale, 0xFF, NULL, -1, &amb, NULL, NULL);
            }
        }
    } else if (*i_return_id == dPa_name::ID_AK_JN_ELEMENTKUSA00) {
        if (flag & 0x02) {
            ptclScale.set(scale2, scale2, scale2);

            GXColor amb = {0x00, 0x00, 0x00, 0x00};
            amb.r = i_tevStr->mColorC0.r;
            amb.g = i_tevStr->mColorC0.g;
            amb.b = i_tevStr->mColorC0.b;
            amb.a = i_tevStr->mColorC0.a;

            if (flag & 0x10) {
                emtr = setNormalP1(*i_return_id, pos, angle, &ptclScale, 0xFF, NULL, -1, &amb, &i_tevStr->mColorK0, NULL);
            } else {
                emtr = setNormal(*i_return_id, pos, angle, &ptclScale, 0xFF, NULL, -1, &amb, &i_tevStr->mColorK0, NULL);
            }
        }
    } else if (*i_return_id == dPa_name::ID_AK_JT_ELEMENTSMOKE00) {
        if (flag & 0x08)
            *i_return_id = dPa_name::ID_AK_JT_ELEMENTSMOKE01;

        if (flag & 0x09) {
            ptclScale.set(scale1, scale1, scale1);
            if (flag & 0x10) {
                emtr = setToonP1(*i_return_id, pos, angle, &ptclScale, 0x80, &mSmokeEcallback, -1, NULL, NULL, NULL);
            } else {
                emtr = setToon(*i_return_id, pos, angle, &ptclScale, 0x80, &mSmokeEcallback, -1, NULL, NULL, NULL);
            }
        }
    }

    if (emtr != NULL) {
        emtr->setMaxFrame(1);
        emtr->setRate(3.0f);
        emtr->setSpread(0.05f);
    }

    return emtr;
}

/* 8007D998-8007DA58       .text setSimpleLand__13dPa_control_cFR13cBgS_PolyInfoPC4cXyzPC5csXyzfffP12dKy_tevstr_cPii */
JPABaseEmitter* dPa_control_c::setSimpleLand(cBgS_PolyInfo& polyInfo, const cXyz* pos, const csXyz* angle, f32 scale1, f32 scale2, f32 scale3, dKy_tevstr_c* i_tevStr, int* i_return_id, int flag) {
    if (dComIfG_Bgsp()->ChkPolySafe(polyInfo)) {
        return setSimpleLand(dComIfG_Bgsp()->GetAttributeCode(polyInfo), pos, angle, scale1, scale2, scale3, i_tevStr, i_return_id, flag);
    }
    return NULL;
}

/* 8007DA58-8007DAA8       .text checkAtrCodeEffect__13dPa_control_cFi */
s32 dPa_control_c::checkAtrCodeEffect(int code) {
    if (code == dBgS_Attr_WATER_e) {
        return dPa_name::ID_AK_JN_ELEMENTSHIBUKI00;
    } else if (code == dBgS_Attr_GRASS_e) {
        return dPa_name::ID_AK_JN_ELEMENTKUSA00;
    } else if (code != dBgS_Attr_UNK1B_e && code != dBgS_Attr_ICE_e && code != dBgS_Attr_GIANT_FLOWER_e && code != dBgS_Attr_CARPET_e) {
        return dPa_name::ID_AK_JT_ELEMENTSMOKE00;
    } else {
        return -1;
    }
}

/* 8007DAA8-8007DB34       .text setNormalStripes__13dPa_control_cFUsPC4cXyzPC5csXyzPC4cXyzUcUs */
JPABaseEmitter* dPa_control_c::setNormalStripes(u16 ptclID, const cXyz* pos, const csXyz* angle, const cXyz* scale, u8 alpha, u16 user) {
    JPABaseEmitter* emtr = setNormal(ptclID, pos, angle, scale, alpha, &mStripes, -1, NULL, NULL, NULL);
    if (emtr != NULL)
        emtr->setUserWork(user);
    return emtr;
}

/* 8007DB34-8007DBC4       .text newSimple__13dPa_control_cFUsUc */
bool dPa_control_c::newSimple(u16 effectID, u8 groupID) {
    if (mNumSimple >= 25) {
        OSReport("\x1b[43;30m１エミッター登録数オーバー！！\n");
        return false;
    }
    JPABaseEmitter* emitter = mSimpleCallbacks[mNumSimple].create(mEmitterMng, effectID, groupID);
    if (!emitter) {
        return false;
    }
    mNumSimple++;
    return true;
}

/* 8007DBC4-8007DC30       .text setSimple__13dPa_control_cFUsPC4cXyzUcRC8_GXColorRC8_GXColori */
bool dPa_control_c::setSimple(u16 param_1, const cXyz* param_2, u8 param_3, const GXColor& param_4, const GXColor& param_5, int param_6) {
    dPa_simpleEcallBack* simple = getSimple(param_1);
    if (simple == NULL) {
        return false;
    }
    return simple->set(param_2, param_3, param_4, param_5, param_6);
}

/* 8007DC30-8007DC6C       .text getSimple__13dPa_control_cFUs */
dPa_simpleEcallBack* dPa_control_c::getSimple(u16 id) {
    dPa_simpleEcallBack* simple = mSimpleCallbacks;
    for (int i = 0; i < mNumSimple; i++, simple++) {
        if (simple->getID() == id) {
            return simple;
        }
    }
    return NULL;
}

/* 8007DC6C-8007DC94       .text setup__19dPa_rippleEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_rippleEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    emitter->setParticleCallBackPtr(dPa_control_c::getRipplePcallBack());
    mPos = pos;
    mRate = 1.0f;
    mFlags |= 1;
    mpBaseEmitter = emitter;
}

/* 8007DC94-8007DCE4       .text end__19dPa_rippleEcallBackFv */
void dPa_rippleEcallBack::end() {
    if (!mpBaseEmitter) {
        return;
    }
    mpBaseEmitter->becomeInvalidEmitter();
    mpBaseEmitter->quitImmortalEmitter();
    mpBaseEmitter->setEmitterCallBackPtr(NULL);
    mFlags |= 2;
    mpBaseEmitter = NULL;
}

/* 8007DCE4-8007DD70       .text execute__19dPa_rippleEcallBackFP14JPABaseEmitter */
void dPa_rippleEcallBack::execute(JPABaseEmitter* emtr) {
    emtr->setGlobalTranslation(mPos->x, mPos->y, mPos->z);
    emtr->setRate(mRate * 0.1333f + 0.0667f);
    if (mFlags & 1) {
        GXColor amb, dif;
        dKy_get_seacolor(&amb, &dif);
        emtr->setGlobalPrmColor(amb.r, amb.g, amb.b);
    }
}

/* 8007DD70-8007DDA8       .text draw__19dPa_rippleEcallBackFP14JPABaseEmitter */
void dPa_rippleEcallBack::draw(JPABaseEmitter* emitter) {
    if (dPa_control_c::isStatus(1)) {
        GXSetZMode(GX_FALSE, GX_NEVER, GX_FALSE);
    }
}

/* 8007DDA8-8007DDB4       .text setup__25dPa_singleRippleEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_singleRippleEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8) {
    emitter->setParticleCallBackPtr(dPa_control_c::getRipplePcallBack());
}

/* 8007DDB4-8007DE00       .text execute__25dPa_singleRippleEcallBackFP14JPABaseEmitter */
void dPa_singleRippleEcallBack::execute(JPABaseEmitter* emitter) {
    GXColor c1, c2;
    dKy_get_seacolor(&c1, &c2);
    emitter->setGlobalPrmColor(c1.r, c1.g, c1.b);
}

/* 8007DE00-8007DE38       .text draw__25dPa_singleRippleEcallBackFP14JPABaseEmitter */
void dPa_singleRippleEcallBack::draw(JPABaseEmitter* emitter) {
    if (dPa_control_c::isStatus(1)) {
        GXSetZMode(GX_FALSE, GX_NEVER, GX_FALSE);
    }
}

/* 8007DE38-8007DE94       .text execute__19dPa_ripplePcallBackFP14JPABaseEmitterP15JPABaseParticle */
void dPa_ripplePcallBack::execute(JPABaseEmitter* emitter, JPABaseParticle* ptcl) {
    /* Nonmatching - regalloc */
    JGeometry::TVec3<f32> local_18;
    ptcl->getGlobalPosition(local_18);
    cXyz pos(local_18.x, local_18.y, local_18.z);
    f32 height;
    if (fopAcM_getWaterY(&pos, &height)) {
        JGeometry::TVec3<f32> offsetPos;
        ptcl->getOffsetPosition(offsetPos);
        offsetPos.y = height;
        ptcl->setOffsetPosition(offsetPos);
    }
}

/* 8007DE94-8007E254       .text draw__19dPa_ripplePcallBackFP14JPABaseEmitterP15JPABaseParticle */
void dPa_ripplePcallBack::draw(JPABaseEmitter* emitter, JPABaseParticle* particle) {
    /* Nonmatching */
}

/* 8007E254-8007E288       .text setup__17dPa_waveEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_waveEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    mpPos = pos;
    mpRot = rot;
    mVel = 0.0f;
    mVelFade2 = 1.0f;
    mpBaseEmitter = emitter;
    mMaxParticleVelocity = 10000.0f;
    mState = 0;
    mFadeTimer = 0;
}

/* 8007E288-8007E2BC       .text remove__17dPa_waveEcallBackFv */
void dPa_waveEcallBack::remove() {
    if (!mpBaseEmitter) {
        return;
    }
    mpBaseEmitter->setEmitterCallBackPtr(NULL);
    mpBaseEmitter->becomeInvalidEmitter();
    mpBaseEmitter = NULL;
}

/* 8007E2BC-8007E484       .text executeAfter__17dPa_waveEcallBackFP14JPABaseEmitter */
void dPa_waveEcallBack::executeAfter(JPABaseEmitter* emitter) {
    emitter->getEmitterAxis(reinterpret_cast<JGeometry::TVec3<f32>&>(mRotMtx[0]), reinterpret_cast<JGeometry::TVec3<f32>&>(mRotMtx[1]), reinterpret_cast<JGeometry::TVec3<f32>&>(mRotMtx[2]));

    if (mState != 0) {
        emitter->setDirectionalSpeed(0.0f);
        if (mFadeTimer > 0) {
            mFadeTimer--;
        } else {
            remove();
        }
        return;
    }

    JGeometry::TVec3<f32> oldPos;
    emitter->getGlobalTranslation(oldPos);
    JGeometry::TVec3<f32> pos(*mpPos);
    emitter->setGlobalTranslation(pos);
    pos.sub(oldPos);
    f32 vel = pos.length();
    if (vel >= mMaxParticleVelocity) {
        vel = mMaxParticleVelocity;
    }
    f32 speed = mVelFade1 * vel * mVelFade2;
    
    JGeometry::TVec3<s16> rot((s16)0, mpRot->y, (s16)0);
    emitter->setGlobalRotation(rot);
    
    if (std::fabsf(speed - mVel) > mVelSpeed) {
        if (speed - mVel > 0.0f) {
            speed = mVel + mVelSpeed;
        } else {
            speed = mVel - mVelSpeed;
        }
    }
    
    emitter->setDirectionalSpeed(speed);
    mVel = speed;
}

/* 8007E484-8007E804       .text draw__17dPa_waveEcallBackFP14JPABaseEmitter */
void dPa_waveEcallBack::draw(JPABaseEmitter* emitter) {
    /* Nonmatching */
}

/* 8007E804-8007E81C       .text setup__19dPa_splashEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_splashEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    mpPos = pos;
    mpRot = rot;
    mpBaseEmitter = emitter;
    mState = 0;
}

/* 8007E81C-8007E850       .text remove__19dPa_splashEcallBackFv */
void dPa_splashEcallBack::remove() {
    if (!mpBaseEmitter) {
        return;
    }
    mpBaseEmitter->setEmitterCallBackPtr(NULL);
    mpBaseEmitter->becomeInvalidEmitter();
    mpBaseEmitter = NULL;
}

/* 8007E850-8007E9B8       .text execute__19dPa_splashEcallBackFP14JPABaseEmitter */
void dPa_splashEcallBack::execute(JPABaseEmitter* emitter) {
    GXColor local_24;
    GXColor local_28;
    dKy_get_seacolor(&local_24, &local_28);
    emitter->setGlobalPrmColor(local_24.r, local_24.g, local_24.b);
    if (mState) {
        JGeometry::TVec3<f32> local_20;
        emitter->getGlobalParticleScale(local_20);
        if (cLib_chaseF(&local_20.x, 0.0, 0.2)) {
            remove();
            return;
        }
        local_20.z = local_20.y = local_20.x;
        emitter->setGlobalDynamicsScale(local_20);
        emitter->setGlobalParticleScale(local_20);
        emitter->setDirectionalSpeed(local_20.x * 15.0f);
    } else {
        emitter->setGlobalTranslation(mpPos->x, mpPos->y, mpPos->z);
        f32 scaleF = mScaleTimer / mMaxScaleTimer;
        s16 yaw = mpRot->y;
        if (scaleF > 1.0f) {
            scaleF = 1.0f;
        }
        JGeometry::TVec3<f32> scale(scaleF, scaleF, scaleF);
        emitter->setGlobalDynamicsScale(scale);
        emitter->setGlobalParticleScale(scale);
        emitter->setDirectionalSpeed(scaleF * 15.0f);
        JGeometry::TVec3<s16> rot(s16(0), yaw, s16(0));
        emitter->setGlobalRotation(rot);
    }
}

/* 8007E9B8-8007E9D4       .text setup__22dPa_cutTurnEcallBack_cFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_cutTurnEcallBack_c::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    mpBaseEmitter = emitter;
    field_0x6 = 0;
    field_0x5 = 0;
    mAlpha = 0xFF;
}

/* 8007E9D4-8007EAC4       .text executeAfter__22dPa_cutTurnEcallBack_cFP14JPABaseEmitter */
void dPa_cutTurnEcallBack_c::executeAfter(JPABaseEmitter* emitter) {
    if (field_0x5) {
        emitter->becomeInvalidEmitter();
        emitter->setEmitterCallBackPtr(NULL);
        mpBaseEmitter = NULL;
        return;
    }
    if (field_0x6 > 0 && mPosArray) {
        cXyz* pos = &mPosArray[field_0x6] - 1;
        int i = field_0x6 - 1;
        for (; i >= 1; i--, pos--) {
            JPABaseParticle* particle = emitter->createParticle();
            if (particle) {
                particle->setOffsetPosition(*pos);
            }
        }
        emitter->setGlobalTranslation(pos->x, pos->y, pos->z);
        emitter->setGlobalAlpha(mAlpha);
        field_0x6 = 0;
    }
}

/* 8007EAC4-8007EB00       .text end__22dPa_cutTurnEcallBack_cFv */
void dPa_cutTurnEcallBack_c::end() {
    if (!mpBaseEmitter) {
        return;
    }
    mpBaseEmitter->setEmitterCallBackPtr(NULL);
    mpBaseEmitter->becomeInvalidEmitter();
    mpBaseEmitter = NULL;
    field_0x5 = 1;
}

/* 8007EB00-8007F028       .text draw__20dPa_stripesEcallBackFP14JPABaseEmitter */
void dPa_stripesEcallBack::draw(JPABaseEmitter* emitter) {
    /* Nonmatching */
}

/* 8007F028-8007F05C       .text draw__19dPa_kageroEcallBackFP14JPABaseEmitter */
void dPa_kageroEcallBack::draw(JPABaseEmitter* emitter) {
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
}

/* 8007F05C-8007F108       .text execute__22dPa_bombSmokeEcallBackFP14JPABaseEmitter */
void dPa_bombSmokeEcallBack::execute(JPABaseEmitter* emitter) {
    u32 local_14 = emitter->getUserWork() >> 16;
    s16 r31 = emitter->getUserWork() & 0xFF;
    s16 r30 = (emitter->getUserWork() >> 8) & 0xFF;
    if (cLib_calcTimer(&local_14) == 0) {
        s16 local_18 = emitter->getGlobalAlpha();
        if (cLib_chaseS(&local_18, r31, r30)) {
            emitter->setEmitterCallBackPtr(NULL);
        }
        emitter->setGlobalAlpha(local_18);
    }
    emitter->setUserWork(local_14 << 16 | r30 << 8 | r31);
}

/* 8007F108-8007F1A8       .text getMaxWaterY__18dPa_trackEcallBackFPQ29JGeometry8TVec3<f> */
void dPa_trackEcallBack::getMaxWaterY(JGeometry::TVec3<f32>* pos) {
    if (daSea_ChkArea(pos->x, pos->z)) {
        pos->y = daSea_calcWave(pos->x, pos->z);
        if (mMinY > pos->y) {
            pos->y = mMinY;
        }
    } else {
        if (mMinY != - G_CM3D_F_INF) {
            pos->y = mMinY;
        } else {
            pos->y = mBaseY;
        }
    }
    pos->y += 2.0f;
}

/* 8007F1A8-8007F1C0       .text setup__18dPa_trackEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_trackEcallBack::setup(JPABaseEmitter* emitter, const cXyz* pos, const csXyz* rot, s8 param_4) {
    mpPos = pos;
    mState = 0;
    mpRot = rot;
    mpBaseEmitter = emitter;
}

/* 8007F1C0-8007F1F4       .text remove__18dPa_trackEcallBackFv */
void dPa_trackEcallBack::remove() {
    if (!mpBaseEmitter) {
        return;
    }
    mpBaseEmitter->setEmitterCallBackPtr(NULL);
    mpBaseEmitter->becomeInvalidEmitter();
    mpBaseEmitter = NULL;
}

/* 8007F1F4-8007F3BC       .text execute__18dPa_trackEcallBackFP14JPABaseEmitter */
void dPa_trackEcallBack::execute(JPABaseEmitter* emitter) {
    /* Nonmatching - regalloc */
    GXColor local_30;
    GXColor local_34;
    dKy_get_seacolor(&local_30, &local_34);
    emitter->setGlobalPrmColor(local_30.r, local_30.g, local_30.b);
    if (mState) {
        JGeometry::TVec3<f32> local_20;
        emitter->getGlobalTranslation(local_20);
        getMaxWaterY(&local_20);
        s16 local_36 = emitter->getGlobalAlpha();
        cLib_chaseS(&local_36, 0, 10);
        emitter->setGlobalAlpha(local_36);
        if (local_36 == 0) {
            remove();
            return;
        }
    } else {
        emitter->setGlobalTranslation(mpPos->x, mpPos->y, mpPos->z);
        JGeometry::TVec3<s16> rot(0, mVel >= 0.0f ? mpRot->y : mpRot->y + 0x8000, 0);
        emitter->setGlobalRotation(rot);
        s16 local_38 = emitter->getGlobalAlpha();
        if (std::fabsf(mVel) > mMinVel) {
            cLib_chaseS(&local_38, 255, 5);
        } else {
            cLib_chaseS(&local_38, 0, 5);
        }
        emitter->setGlobalAlpha(local_38);
    }
    for (JSULink<JPABaseParticle>* link = emitter->getParticleList()->getFirst(); link;) {
        JSULink<JPABaseParticle>* next = link->getNext();
        JPABaseParticle* particle = link->getObject();
        JGeometry::TVec3<f32> local_2c;
        particle->getOffsetPosition(local_2c);
        getMaxWaterY(&local_2c);
        particle->setOffsetPosition(local_2c);
        link = next;
    }
}

/* 8007F3BC-8007F62C       .text draw__18dPa_trackEcallBackFP14JPABaseEmitter */
void dPa_trackEcallBack::draw(JPABaseEmitter* emitter) {
    /* Nonmatching - regalloc, instruction order */
    u32 r28 = emitter->getParticleList()->getNumLinks();
    if (r28 < 6) {
        return;
    }
    if (dPa_control_c::isStatus(1)) {
        GXSetZMode(GX_DISABLE, GX_NEVER, GX_DISABLE);
    }
    r28 = r28 * (1.0f / 3.0f);
    f32 f30 = 1.0f / (r28 - 1);
    GXSetCullMode(GX_CULL_NONE);
    Mtx local_bc;
    MTXIdentity(local_bc);
    local_bc[1][1] = mExScaleY;
    local_bc[1][3] = mExTransY * emitter->getFrame();
    GXLoadTexMtxImm(local_bc, GX_TEXMTX1, GX_MTX2x4);
    GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX1);
    JSULink<JPABaseParticle>* link = emitter->getParticleList()->getFirst();
    u32 i = 0;
    f32 f31 = 0.0f;
    for (; i < r28; i++) {
        if (i) {
            GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 6);
            u32 j = 0;
            f32 f27 = 0.0f;
            for (; j < 3; j++) {
                JPABaseParticle* particle = link->getObject();
                JGeometry::TVec3<f32> local_c8;
                particle->getGlobalPosition(local_c8);
                getMaxWaterY(&local_c8);
                GXPosition3f32(local_c8.x, local_c8.y, local_c8.z);
                GXTexCoord2f32(f27, f31);
                GXPosition3f32(mPos[j].x, mPos[j].y, mPos[j].z);
                GXTexCoord2f32(f27, f31 - f30);
                mPos[j].set(local_c8);
                f27 += 0.5f;
                link = link->getNext();
            }
            GXEnd();
        } else {
            for (int j = 0; j < 3; j++) {
                JPABaseParticle* particle = link->getObject();
                particle->getGlobalPosition(mPos[j]);
                link = link->getNext();
            }
        }
        f31 += f30;
    }
}

/* 8007F704-8007F708       .text setup__22dPa_bombSmokeEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_bombSmokeEcallBack::setup(JPABaseEmitter*, const cXyz*, const csXyz*, s8) {
}

/* 8007F7D0-8007F7D4       .text setup__20dPa_stripesEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_stripesEcallBack::setup(JPABaseEmitter*, const cXyz*, const csXyz*, s8) {
}

/* 8007FAE8-8007FAEC       .text setup__22dPa_selectTexEcallBackFP14JPABaseEmitterPC4cXyzPC5csXyzSc */
void dPa_selectTexEcallBack::setup(JPABaseEmitter*, const cXyz*, const csXyz*, s8) {
}
