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

#include "JSystem/JSystem.h" // IWYU pragma: keep

#include "JSystem/JParticle/JPADrawVisitor.h"
#include "JSystem/JParticle/JPABaseShape.h"
#include "JSystem/JParticle/JPAEmitter.h"
#include "JSystem/JParticle/JPAExtraShape.h"
#include "JSystem/JParticle/JPAParticle.h"
#include "JSystem/JParticle/JPAResourceManager.h"
#include "JSystem/JParticle/JPASweepShape.h"
#include "JSystem/JMath/JMATrigonometric.h"
#include "JSystem/JGeometry.h"
#include "dolphin/gx/GX.h"
#include "dolphin/mtx/mtx.h"
#include "dolphin/mtx/mtxvec.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "JSystem/JParticle/JPAExTexShape.h"

static inline u32 JPA_U8_THRE(u32 a, u32 b) {
    return ((a * (b + 1)) * 0x10000) >> 24;
}

JPADrawClipBoard* JPADrawContext::pcb;

/* 8025F960-8025FBE4       .text exec__20JPADrawExecLoadExTexFPC14JPADrawContext */
void JPADrawExecLoadExTex::exec(const JPADrawContext* pDC) {
    JUT_ASSERT(50, pDC->pTexIdx);

    u16 texIdx;
    GXTexCoordID coord = GX_TEXCOORD1;
    switch (pDC->petx->getIndTexMode()) {
        case 1:
            GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
            GXEnableTexOffsets(GX_TEXCOORD1, GX_TRUE, GX_TRUE);
            texIdx = pDC->pTexIdx[pDC->petx->getIndTextureID()];
            pDC->mpTextureResource->pTexResArray[texIdx]->load(GX_TEXMAP5);
            coord = GX_TEXCOORD2;
            break;
        case 2:
            GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
            GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
            GXEnableTexOffsets(GX_TEXCOORD1, GX_TRUE, GX_TRUE);
            GXEnableTexOffsets(GX_TEXCOORD2, GX_TRUE, GX_TRUE);
            texIdx = pDC->pTexIdx[pDC->petx->getIndTextureID()];
            pDC->mpTextureResource->pTexResArray[texIdx]->load(GX_TEXMAP5);
            texIdx = pDC->pTexIdx[pDC->petx->getSubTextureID()];
            pDC->mpTextureResource->pTexResArray[texIdx]->load(GX_TEXMAP6);
            coord = GX_TEXCOORD3;
            break;
    }

    if (pDC->petx->isEnableSecondTex()) {
        GXSetTexCoordGen(coord, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
        GXEnableTexOffsets(coord, GX_TRUE, GX_TRUE);
        texIdx = pDC->pTexIdx[pDC->petx->getSecondTexIndex()];
        pDC->mpTextureResource->pTexResArray[texIdx]->load(GX_TEXMAP7);
    }
}

/* 8025FBE4-8025FC78       .text exec__20JPADrawExecGenPrjMtxFPC14JPADrawContext */
void JPADrawExecGenPrjMtx::exec(const JPADrawContext* pDC) {
    Mtx mtx;
    f32 aspect = JPABaseEmitter::getAspect();
    f32 fovy = JPABaseEmitter::getFovy();
    C_MTXLightPerspective(mtx, fovy, aspect, 0.5f, -0.5f, 0.5f, 0.5f);
    MTXConcat(mtx, JPADrawContext::pcb->mDrawMtx, mtx);
    GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX3x4);
    GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_POS, GX_TEXMTX0);
    GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
}

/* 8025FC78-8025FF20       .text exec__23JPADrawExecGenPrjTexMtxFPC14JPADrawContext */
void JPADrawExecGenPrjTexMtx::exec(const JPADrawContext* pDC) {
    Mtx projMtx;
    f32 aspect = JPABaseEmitter::getAspect();
    f32 fovy = JPABaseEmitter::getFovy();
    C_MTXLightPerspective(projMtx, fovy, aspect, 0.5f, -0.5f, 0.5f, 0.5f);

    f32 tick = pDC->pbe->getFrame();
    f32 transX = tick * pDC->pbsp->getTexScrollTransX() + pDC->pbsp->getTexStaticTransX();
    f32 transY = tick * pDC->pbsp->getTexScrollTransY() + pDC->pbsp->getTexStaticTransY();
    f32 scaleX = tick * pDC->pbsp->getTexScrollScaleX() + pDC->pbsp->getTexStaticScaleX();
    f32 scaleY = tick * pDC->pbsp->getTexScrollScaleY() + pDC->pbsp->getTexStaticScaleY();
    int angle = 0x8000 * (tick * pDC->pbsp->getTexScrollRotate());
    f32 sin = JMASSin(angle);
    f32 cos = JMASCos(angle);

    Mtx mtx;
    mtx[0][0] = scaleX * cos;
    mtx[0][1] = -scaleX * sin;
    mtx[0][2] = scaleX * (sin * (transY + 0.5f) - cos * (transX + 0.5f)) + 0.5f;
    mtx[0][3] = 0.0f;

    mtx[1][0] = scaleY * sin;
    mtx[1][1] = scaleY * cos;
    mtx[1][2] = -scaleY * (sin * (transX + 0.5f) + cos * (transY + 0.5f)) + 0.5f;
    mtx[1][3] = 0.0f;

    mtx[2][0] = 0.0f;
    mtx[2][1] = 0.0f;
    mtx[2][2] = 1.0f;
    mtx[2][3] = 0.0f;

    MTXConcat(mtx, projMtx, projMtx);
    MTXConcat(projMtx, JPADrawContext::pcb->mDrawMtx, mtx);
    GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX3x4);
    GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_POS, GX_TEXMTX0);
    GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
}

/* 8025FF20-8025FF68       .text exec__21JPADrawExecGenTexMtx0FPC14JPADrawContext */
void JPADrawExecGenTexMtx0::exec(const JPADrawContext* pDC) {
    GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
    GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
}

/* 8025FF68-8025FFB0       .text exec__20JPADrawExecGenIdtMtxFPC14JPADrawContext */
void JPADrawExecGenIdtMtx::exec(const JPADrawContext* pDC) {
    GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
    GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
}

/* 8025FFB0-802602F0       .text exec__20JPADrawExecSetTexMtxFPC14JPADrawContext */
void JPADrawExecSetTexMtx::exec(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    f32 tilingX = 0.5f * pDC->pbsp->getTilingX();
    f32 tilingY = 0.5f * pDC->pbsp->getTilingY();
    f32 transX = tick * pDC->pbsp->getTexScrollTransX() + pDC->pbsp->getTexStaticTransX();
    f32 transY = tick * pDC->pbsp->getTexScrollTransY() + pDC->pbsp->getTexStaticTransY();
    f32 scaleX = tick * pDC->pbsp->getTexScrollScaleX() + pDC->pbsp->getTexStaticScaleX();
    f32 scaleY = tick * pDC->pbsp->getTexScrollScaleY() + pDC->pbsp->getTexStaticScaleY();
    int angle = 0x8000 * (tick * pDC->pbsp->getTexScrollRotate());
    f32 sin = JMASSin(angle);
    f32 cos = JMASCos(angle);

    Mtx mtx;
    mtx[0][0] = scaleX * cos;
    mtx[0][1] = -scaleX * sin;
    mtx[0][2] = 0.0f;
    mtx[0][3] = tilingX + scaleX * (sin * (tilingY + transY) - cos * (tilingX + transX));

    mtx[1][0] = scaleY * sin;
    mtx[1][1] = scaleY * cos;
    mtx[1][2] = 0.0f;
    mtx[1][3] = tilingY + -scaleY * (sin * (tilingX + transX) + cos * (tilingY + transY));

    mtx[2][0] = 0.0f;
    mtx[2][1] = 0.0f;
    mtx[2][2] = 1.0f;
    mtx[2][3] = 0.0f;

    GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX2x4);
    GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
    GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
}

/* 802602F0-8026031C       .text exec__29JPADrawExecLoadDefaultTextureFPC14JPADrawContext */
void JPADrawExecLoadDefaultTexture::exec(const JPADrawContext* pDC) {
    pDC->mpTextureResource->loadDefaultTexture(GX_TEXMAP0);
}

/* 8026031C-80260364       .text exec__22JPADrawExecLoadTextureFPC14JPADrawContext */
void JPADrawExecLoadTexture::exec(const JPADrawContext* pDC) {
    pDC->mpTextureResource->load(pDC->mpDraw->mTexIdx, GX_TEXMAP0);
}

/* 80260364-802603A4       .text exec__23JPADrawExecSetPointSizeFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecSetPointSize::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXSetPointSize(JPADrawContext::pcb->mGlobalScaleX * params->mScaleX, GX_TO_ONE);
}

/* 802603A4-802603E4       .text exec__23JPADrawExecSetLineWidthFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecSetLineWidth::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXSetLineWidth(JPADrawContext::pcb->mGlobalScaleX * params->mScaleX, GX_TO_ONE);
}

/* 802603E4-802604AC       .text exec__30JPADrawExecRegisterPrmColorAnmFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRegisterPrmColorAnm::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXColor prm = params->mPrmColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    u8 a  = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    prm.a = params->mAlphaOut * a;
    GXSetTevColor(GX_TEVREG0, prm);
}

/* 802604AC-80260578       .text exec__30JPADrawExecRegisterPrmAlphaAnmFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRegisterPrmAlphaAnm::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXColor prm = pDC->mpDraw->mPrmColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    u8 a  = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    prm.a = params->mAlphaOut * a;
    GXSetTevColor(GX_TEVREG0, prm);
}

/* 80260578-802605FC       .text exec__30JPADrawExecRegisterEnvColorAnmFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRegisterEnvColorAnm::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXColor env = params->mEnvColor;
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 802605FC-80260728       .text exec__26JPADrawExecRegisterPrmCEnvFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRegisterPrmCEnv::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXColor prm = params->mPrmColor;
    GXColor env = params->mEnvColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    u8 a  = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    prm.a = params->mAlphaOut * a;
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG0, prm);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 80260728-80260858       .text exec__26JPADrawExecRegisterPrmAEnvFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRegisterPrmAEnv::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    GXColor prm = pDC->mpDraw->mPrmColor;
    GXColor env = params->mEnvColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    u8 a  = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    prm.a = params->mAlphaOut * a;
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG0, prm);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 80260858-80260B68       .text exec__20JPADrawExecSetTexMtxFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecSetTexMtx::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    int tick = ptcl->getAge();
    f32 tilingX = 0.5f * pDC->pbsp->getTilingX();
    f32 tilingY = 0.5f * pDC->pbsp->getTilingY();
    f32 transX = tick * pDC->pbsp->getTexScrollTransX() + pDC->pbsp->getTexStaticTransX();
    f32 transY = tick * pDC->pbsp->getTexScrollTransY() + pDC->pbsp->getTexStaticTransY();
    f32 scaleX = tick * pDC->pbsp->getTexScrollScaleX() + pDC->pbsp->getTexStaticScaleX();
    f32 scaleY = tick * pDC->pbsp->getTexScrollScaleY() + pDC->pbsp->getTexStaticScaleY();
    int angle = 0x8000 * (tick * pDC->pbsp->getTexScrollRotate());
    f32 sin = JMASSin(angle);
    f32 cos = JMASCos(angle);

    Mtx mtx;
    mtx[0][0] = scaleX * cos;
    mtx[0][1] = -scaleX * sin;
    mtx[0][2] = 0.0f;
    mtx[0][3] = tilingX + (scaleX * ((sin * (tilingY + transY)) - (cos * (tilingX + transX))));

    mtx[1][0] = scaleY * sin;
    mtx[1][1] = scaleY * cos;
    mtx[1][2] = 0.0f;
    mtx[1][3] = tilingY + (-scaleY * ((sin * (tilingX + transX)) + (cos * (tilingY + transY))));

    mtx[2][0] = 0.0f;
    mtx[2][1] = 0.0f;
    mtx[2][2] = 1.0f;
    mtx[2][3] = 0.0f;

    GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX2x4);
}

/* 80260B68-80260BAC       .text exec__22JPADrawExecLoadTextureFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecLoadTexture::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    pDC->mpTextureResource->load(params->mTexIdx, GX_TEXMAP0);
}

/* 80260BAC-80260D24       .text exec__20JPADrawExecBillBoardFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecBillBoard::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 scaleX = params->mScaleX;
    f32 scaleY = params->mScaleY;

    f32 x0 = scaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y0 = scaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);
    scaleX *= (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    scaleY *= (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt;
    ptcl->getGlobalPosition(pt);
    MTXMultVec(JPADrawContext::pcb->mDrawMtxPtr, &pt, &pt);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(-scaleX + pt.x, +scaleY + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(+x0 + pt.x, +scaleY + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(+x0 + pt.x, -y0 + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(-scaleX + pt.x, -y0 + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80260D24-80260F2C       .text exec__23JPADrawExecRotBillBoardFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotBillBoard::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    /* Nonmatching */
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    f32 scaleX = params->mScaleX;
    f32 scaleY = params->mScaleY;

    f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    f32 y0 = +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
    f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt;
    ptcl->getGlobalPosition(pt);
    MTXMultVec(JPADrawContext::pcb->mDrawMtxPtr, &pt, &pt);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32((x0 * cos - y0 * sin) + pt.x, (x0 * sin + y0 * cos) + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32((x1 * cos - y0 * sin) + pt.x, (x1 * sin + y0 * cos) + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32((x1 * cos - y1 * sin) + pt.x, (x1 * sin + y1 * cos) + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32((x0 * cos - y1 * sin) + pt.x, (x0 * sin + y1 * cos) + pt.y, pt.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80260F2C-8026110C       .text exec__21JPADrawExecYBillBoardFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecYBillBoard::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 scaleX = params->mScaleX;
    f32 scaleY = params->mScaleY;

    f32 x0 = scaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y0 = scaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);
    scaleX *= (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    scaleY *= (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt[4];
    pt[0].set(-scaleX, +scaleY, 0.0f);
    pt[1].set(+x0, +scaleY, 0.0f);
    pt[2].set(+x0, -y0, 0.0f);
    pt[3].set(-scaleX, -y0, 0.0f);
    MTXMultVecArray(JPADrawContext::pcb->mDrawYBBMtx, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);
    MTXMultVecSR(JPADrawContext::pcb->mDrawMtxPtr, &pos, &pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 8026110C-8026134C       .text exec__24JPADrawExecRotYBillBoardFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotYBillBoard::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    f32 y0 = +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
    f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt[4];
    pt[0].set(x0 * cos - y0 * sin, y0 * cos + x0 * sin, 0.0f);
    pt[1].set(x1 * cos - y0 * sin, y0 * cos + x1 * sin, 0.0f);
    pt[2].set(x1 * cos - y1 * sin, y1 * cos + x1 * sin, 0.0f);
    pt[3].set(x0 * cos - y1 * sin, y1 * cos + x0 * sin, 0.0f);
    MTXMultVecArray(JPADrawContext::pcb->mDrawYBBMtx, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);
    MTXMultVecSR(JPADrawContext::pcb->mDrawMtxPtr, &pos, &pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 8026134C-80261368       .text dirTypeVel__FP15JPABaseParticleP14JPABaseEmitterRQ29JGeometry8TVec3<f> */
void dirTypeVel(JPABaseParticle* ptcl, JPABaseEmitter* emtr, JGeometry::TVec3<f32>& out) {
    ptcl->getVelVec(out);
}

/* 80261368-80261384       .text dirTypePos__FP15JPABaseParticleP14JPABaseEmitterRQ29JGeometry8TVec3<f> */
void dirTypePos(JPABaseParticle* ptcl, JPABaseEmitter* emtr, JGeometry::TVec3<f32>& out) {
    ptcl->getLocalPosition(out);
}

/* 80261384-802613C4       .text dirTypePosInv__FP15JPABaseParticleP14JPABaseEmitterRQ29JGeometry8TVec3<f> */
void dirTypePosInv(JPABaseParticle* ptcl, JPABaseEmitter* emtr, JGeometry::TVec3<f32>& out) {
    ptcl->getLocalPosition(out);
    out.negate();
}

/* 802613C4-802613E8       .text dirTypeEmtrDir__FP15JPABaseParticleP14JPABaseEmitterRQ29JGeometry8TVec3<f> */
void dirTypeEmtrDir(JPABaseParticle* ptcl, JPABaseEmitter* emtr, JGeometry::TVec3<f32>& out) {
    emtr->getgReRDirection(out);
}

/* 802613E8-802614A8       .text dirTypePrevPtcl__FP15JPABaseParticleP14JPABaseEmitterRQ29JGeometry8TVec3<f> */
void dirTypePrevPtcl(JPABaseParticle* ptcl, JPABaseEmitter* emtr, JGeometry::TVec3<f32>& out) {
    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);
    JSULink<JPABaseParticle>* prev = ptcl->getLinkBufferPtr()->getPrev();
    if (prev != NULL) {
        prev->getObject()->getGlobalPosition(out);
    } else {
        emtr->calcEmitterGlobalTranslation(out);
    }
    out.x -= pos.x;
    out.y -= pos.y;
    out.z -= pos.z;
}

/* 802614A8-802614E8       .text rotTypeY__FffRA3_A4_f */
void rotTypeY(f32 sin, f32 cos, Mtx& out) {
    out[0][0] = cos;
    out[0][1] = 0.0f;
    out[0][2] = -sin;
    out[0][3] = 0.0f;

    out[1][0] = 0.0f;
    out[1][1] = 1.0f;
    out[1][2] = 0.0f;
    out[1][3] = 0.0f;

    out[2][0] = sin;
    out[2][1] = 0.0f;
    out[2][2] = cos;
    out[2][3] = 0.0f;
}

/* 802614E8-80261528       .text rotTypeX__FffRA3_A4_f */
void rotTypeX(f32 sin, f32 cos, Mtx& out) {
    out[0][0] = 1.0f;
    out[0][1] = 0.0f;
    out[0][2] = 0.0f;
    out[0][3] = 0.0f;

    out[1][0] = 0.0f;
    out[1][1] = cos;
    out[1][2] = -sin;
    out[1][3] = 0.0f;

    out[2][0] = 0.0f;
    out[2][1] = sin;
    out[2][2] = cos;
    out[2][3] = 0.0f;
}

/* 80261528-80261568       .text rotTypeZ__FffRA3_A4_f */
void rotTypeZ(f32 sin, f32 cos, Mtx& out) {
    out[0][0] = cos;
    out[0][1] = -sin;
    out[0][2] = 0.0f;
    out[0][3] = 0.0f;

    out[1][0] = sin;
    out[1][1] = cos;
    out[1][2] = 0.0f;
    out[1][3] = 0.0f;

    out[2][0] = 0.0f;
    out[2][1] = 0.0f;
    out[2][2] = 1.0f;
    out[2][3] = 0.0f;
}

/* 80261568-802615C4       .text rotTypeXYZ__FffRA3_A4_f */
void rotTypeXYZ(f32 sin, f32 cos, Mtx& out) {
    f32 a, b, c;
    a = (1.0f - cos) * 0.333333f;
    c = a + (0.57735f * sin);
    b = a - (0.57735f * sin);
    a = a + cos;

    out[0][0] = a;
    out[0][1] = b;
    out[0][2] = c;
    out[0][3] = 0.0f;

    out[1][0] = c;
    out[1][1] = a;
    out[1][2] = b;
    out[1][3] = 0.0f;

    out[2][0] = b;
    out[2][1] = c;
    out[2][2] = a;
    out[2][3] = 0.0f;
}

/* 802615C4-8026161C       .text rotTypeYJiggle__FffRA3_A4_f */
void rotTypeYJiggle(f32 sin, f32 cos, Mtx& out) {
    out[0][0] = cos;
    out[0][1] = -sin * 0.207912f;
    out[0][2] = -sin * 0.978148f;
    out[0][3] = 0.0f;

    out[1][0] = 0.0f;
    out[1][1] = 0.978148f;
    out[1][2] = -0.207912f;
    out[1][3] = 0.0f;

    out[2][0] = sin;
    out[2][1] = cos * 0.207912f;
    out[2][2] = cos * 0.978148f;
    out[2][3] = 0.0f;
}

/* 8026161C-80261654       .text basePlaneTypeXY__FffffPQ29JGeometry8TVec3<f> */
void basePlaneTypeXY(f32 x0, f32 x1, f32 y0, f32 y1, JGeometry::TVec3<f32>* out) {
    out[0].set(x0, y0, 0.0f);
    out[1].set(x1, y0, 0.0f);
    out[2].set(x1, y1, 0.0f);
    out[3].set(x0, y1, 0.0f);
}

/* 80261654-8026168C       .text basePlaneTypeXZ__FffffPQ29JGeometry8TVec3<f> */
void basePlaneTypeXZ(f32 x0, f32 x1, f32 y0, f32 y1, JGeometry::TVec3<f32>* out) {
    out[0].set(x0, 0.0f, y1);
    out[1].set(x1, 0.0f, y1);
    out[2].set(x1, 0.0f, y0);
    out[3].set(x0, 0.0f, y0);
}

/* 8026168C-80261AD0       .text exec__22JPADrawExecDirectionalFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecDirectional::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();

    JGeometry::TVec3<f32> pt[4];
    JPADrawContext::pcb->mBasePlaneTypeFunc(
        -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX),
        +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX),
        +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY),
        -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY),
        pt
    );

    JGeometry::TVec3<f32> dir;
    JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
    if (dir.isZero())
        return;
    dir.normalize();

    JGeometry::TVec3<f32> side;
    side.cross(params->mAxis, dir);
    if (side.isZero())
        return;
    side.normalize();

    params->mAxis.cross(dir, side);
    params->mAxis.normalize();

    Mtx mtx;
    mtx[0][0] = params->mAxis.x;
    mtx[0][1] = dir.x;
    mtx[0][2] = side.x;
    mtx[0][3] = 0.0f;
    mtx[1][0] = params->mAxis.y;
    mtx[1][1] = dir.y;
    mtx[1][2] = side.y;
    mtx[1][3] = 0.0f;
    mtx[2][0] = params->mAxis.z;
    mtx[2][1] = dir.z;
    mtx[2][2] = side.z;
    mtx[2][3] = 0.0f;
    MTXMultVecArray(mtx, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80261AD0-80261F60       .text exec__25JPADrawExecRotDirectionalFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotDirectional::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    Mtx rotMtx;
    JGeometry::TVec3<f32> pt[4];
    JPADrawContext::pcb->mBasePlaneTypeFunc(
        -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX),
        +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX),
        +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY),
        -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY),
        pt
    );
    JPADrawContext::pcb->mRotTypeFunc(sin, cos, rotMtx);

    JGeometry::TVec3<f32> dir;
    JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
    if (dir.isZero())
        return;
    dir.normalize();

    JGeometry::TVec3<f32> side;
    side.cross(params->mAxis, dir);
    if (side.isZero())
        return;
    side.normalize();

    params->mAxis.cross(dir, side);
    params->mAxis.normalize();

    Mtx mtx;
    mtx[0][0] = params->mAxis.x;
    mtx[0][1] = dir.x;
    mtx[0][2] = side.x;
    mtx[0][3] = 0.0f;
    mtx[1][0] = params->mAxis.y;
    mtx[1][1] = dir.y;
    mtx[1][2] = side.y;
    mtx[1][3] = 0.0f;
    mtx[2][0] = params->mAxis.z;
    mtx[2][1] = dir.z;
    mtx[2][2] = side.z;
    mtx[2][3] = 0.0f;

    Mtx concat;
    MTXConcat(mtx, rotMtx, concat);
    MTXMultVecArray(concat, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80261F60-802624D4       .text exec__27JPADrawExecDirectionalCrossFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecDirectionalCross::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();

    f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    f32 y0 = +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
    f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt[8];
    pt[0].set(x0, y0, 0.0f);
    pt[1].set(x1, y0, 0.0f);
    pt[2].set(x1, y1, 0.0f);
    pt[3].set(x0, y1, 0.0f);
    f32 z0 = 0.5f * (x1 - x0);
    f32 x2 = 0.5f * (x1 + x0);
    pt[4].set(x2, y0, z0);
    f32 z1 = 0.5f * (x0 - x1);
    pt[5].set(x2, y0, z1);
    pt[6].set(x2, y1, z1);
    pt[7].set(x2, y1, z0);

    JGeometry::TVec3<f32> dir;
    JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
    if (dir.isZero())
        return;
    dir.normalize();

    JGeometry::TVec3<f32> side;
    side.cross(params->mAxis, dir);
    if (side.isZero())
        return;
    side.normalize();

    params->mAxis.cross(dir, side);
    params->mAxis.normalize();

    Mtx mtx;
    mtx[0][0] = params->mAxis.x;
    mtx[0][1] = dir.x;
    mtx[0][2] = side.x;
    mtx[0][3] = 0.0f;
    mtx[1][0] = params->mAxis.y;
    mtx[1][1] = dir.y;
    mtx[1][2] = side.y;
    mtx[1][3] = 0.0f;
    mtx[2][0] = params->mAxis.z;
    mtx[2][1] = dir.z;
    mtx[2][2] = side.z;
    mtx[2][3] = 0.0f;
    MTXMultVecArray(mtx, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 8);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXPosition3f32(pt[4].x + pos.x, pt[4].y + pos.y, pt[4].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[5].x + pos.x, pt[5].y + pos.y, pt[5].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[6].x + pos.x, pt[6].y + pos.y, pt[6].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[7].x + pos.x, pt[7].y + pos.y, pt[7].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 802624D4-80262A98       .text exec__30JPADrawExecRotDirectionalCrossFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotDirectionalCross::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    f32 y0 = +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
    f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);

    Mtx rotMtx;
    JGeometry::TVec3<f32> pt[8];
    pt[0].set(x0, y0, 0.0f);
    pt[1].set(x1, y0, 0.0f);
    pt[2].set(x1, y1, 0.0f);
    pt[3].set(x0, y1, 0.0f);
    f32 z0 = 0.5f * (x1 - x0);
    f32 x2 = 0.5f * (x1 + x0);
    pt[4].set(x2, y0, z0);
    f32 z1 = 0.5f * (x0 - x1);
    pt[5].set(x2, y0, z1);
    pt[6].set(x2, y1, z1);
    pt[7].set(x2, y1, z0);

    JPADrawContext::pcb->mRotTypeFunc(sin, cos, rotMtx);

    JGeometry::TVec3<f32> dir;
    JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
    if (dir.isZero())
        return;
    dir.normalize();

    JGeometry::TVec3<f32> side;
    side.cross(params->mAxis, dir);
    if (side.isZero())
        return;
    side.normalize();

    params->mAxis.cross(dir, side);
    params->mAxis.normalize();

    Mtx mtx;
    mtx[0][0] = params->mAxis.x;
    mtx[0][1] = dir.x;
    mtx[0][2] = side.x;
    mtx[0][3] = 0.0f;
    mtx[1][0] = params->mAxis.y;
    mtx[1][1] = dir.y;
    mtx[1][2] = side.y;
    mtx[1][3] = 0.0f;
    mtx[2][0] = params->mAxis.z;
    mtx[2][1] = dir.z;
    mtx[2][2] = side.z;
    mtx[2][3] = 0.0f;

    Mtx concat;
    MTXConcat(mtx, rotMtx, concat);
    MTXMultVecArray(concat, pt, pt, ARRAY_SIZE(pt));

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 8);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXPosition3f32(pt[4].x + pos.x, pt[4].y + pos.y, pt[4].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[5].x + pos.x, pt[5].y + pos.y, pt[5].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[6].x + pos.x, pt[6].y + pos.y, pt[6].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[7].x + pos.x, pt[7].y + pos.y, pt[7].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80262A98-80262DC0       .text exec__23JPADrawExecDirBillBoardFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecDirBillBoard::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JGeometry::TVec3<f32> dir;
    JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
    JGeometry::TVec3<f32> zdir(*(Vec*)JPADrawContext::pcb->mDrawMtxPtr[2]);
    dir.cross(dir, zdir);
    if (dir.isZero())
        return;
    dir.normalize();
    MTXMultVecSR(JPADrawContext::pcb->mDrawMtxPtr, &dir, &dir);

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 dirY = dir.y;
    f32 scaleX = params->mScaleX;
    f32 scaleY = params->mScaleY;

    f32 x1 = scaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = scaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);
    scaleX *= (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    scaleY *= (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);

    f32 x0 = -scaleX;
    y1 = -y1;
    f32 dirX = dir.x;

    JGeometry::TVec2<f32> p0;
    JGeometry::TVec2<f32> p1;
    JGeometry::TVec2<f32> p2;
    JGeometry::TVec2<f32> p3;
    p0.set(x0, scaleY);
    p1.set(x1, scaleY);
    p2.set(x1, y1);
    p3.set(x0, y1);
    p0.set(dirX * p0.x - dirY * p0.y, dirX * p0.y + dirY * p0.x);
    p1.set(dirX * p1.x - dirY * p1.y, dirX * p1.y + dirY * p1.x);
    p2.set(dirX * p2.x - dirY * p2.y, dirX * p2.y + dirY * p2.x);
    p3.set(dirX * p3.x - dirY * p3.y, dirX * p3.y + dirY * p3.x);

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);
    MTXMultVec(JPADrawContext::pcb->mDrawMtxPtr, &pos, &pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(p0.x + pos.x, p0.y + pos.y, pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(p1.x + pos.x, p1.y + pos.y, pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(p2.x + pos.x, p2.y + pos.y, pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(p3.x + pos.x, p3.y + pos.y, pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80262DC0-80262FBC       .text exec__19JPADrawExecRotationFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotation::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    Mtx rotMtx;
    JGeometry::TVec3<f32> pt[4];
    JPADrawContext::pcb->mBasePlaneTypeFunc(
        -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX),
        +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX),
        +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY),
        -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY),
        pt
    );
    JPADrawContext::pcb->mRotTypeFunc(sin, cos, rotMtx);

    MTXMultVecArray(rotMtx, pt, pt, ARRAY_SIZE(pt));
    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 80262FBC-802632EC       .text exec__24JPADrawExecRotationCrossFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecRotationCross::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    /* Nonmatching */
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin(params->mRotateAngle);
    f32 cos = JMASCos(params->mRotateAngle);

    f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
    f32 y0 = +params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
    f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
    f32 y1 = -params->mScaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);

    JGeometry::TVec3<f32> pt[8];
    pt[0].set(x0, y0, 0.0f);
    pt[1].set(x1, y0, 0.0f);
    pt[2].set(x1, y1, 0.0f);
    pt[3].set(x0, y1, 0.0f);

    pt[4].set((pt[1].x + pt[0].x) * 0.5f, y0, (pt[1].x - pt[0].x) * 0.5f);
    pt[5].set((pt[1].x + pt[0].x) * 0.5f, y0, (pt[0].x - pt[1].x) * 0.5f);
    pt[6].set((pt[1].x + pt[0].x) * 0.5f, y1, (pt[0].x - pt[1].x) * 0.5f);
    pt[7].set((pt[1].x + pt[0].x) * 0.5f, y1, (pt[1].x - pt[0].x) * 0.5f);

    Mtx rotMtx;
    JPADrawContext::pcb->mRotTypeFunc(sin, cos, rotMtx);

    MTXMultVecArray(rotMtx, pt, pt, ARRAY_SIZE(pt));
    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);

    GXBegin(GX_QUADS, GX_VTXFMT0, 8);
    GXPosition3f32(pt[0].x + pos.x, pt[0].y + pos.y, pt[0].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[1].x + pos.x, pt[1].y + pos.y, pt[1].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[2].x + pos.x, pt[2].y + pos.y, pt[2].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[3].x + pos.x, pt[3].y + pos.y, pt[3].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXPosition3f32(pt[4].x + pos.x, pt[4].y + pos.y, pt[4].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[0].x, JPADrawContext::pcb->mTexCoordPt[0].y);
    GXPosition3f32(pt[5].x + pos.x, pt[5].y + pos.y, pt[5].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[1].x, JPADrawContext::pcb->mTexCoordPt[1].y);
    GXPosition3f32(pt[6].x + pos.x, pt[6].y + pos.y, pt[6].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[2].x, JPADrawContext::pcb->mTexCoordPt[2].y);
    GXPosition3f32(pt[7].x + pos.x, pt[7].y + pos.y, pt[7].z + pos.z);
    GXTexCoord2f32(JPADrawContext::pcb->mTexCoordPt[3].x, JPADrawContext::pcb->mTexCoordPt[3].y);
    GXEnd();
}

/* 802632EC-80263380       .text exec__16JPADrawExecPointFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecPoint::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JGeometry::TVec3<f32> pos;
    ptcl->getGlobalPosition(pos);
    GXBegin(GX_POINTS, GX_VTXFMT0, 1);
    GXPosition3f32(pos.x, pos.y, pos.z);
    GXTexCoord2f32(0.0f, 0.0f);
    GXEnd();
}

/* 80263380-80263508       .text exec__15JPADrawExecLineFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecLine::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    if (ptcl->isInvisibleParticle())
        return;

    JPADrawParams* params = ptcl->getDrawParamPPtr();
    JGeometry::TVec3<f32> pt0;
    JGeometry::TVec3<f32> vel;

    ptcl->getGlobalPosition(pt0);
    ptcl->getVelVec(vel);
    if (!vel.isZero()) {
        vel.normalize();

        f32 size = JPADrawContext::pcb->mGlobalScaleY * params->mScaleY;
        vel.scale(size);
        JGeometry::TVec3<f32> pt1;
        pt1.sub(pt0, vel);

        GXBegin(GX_LINES, GX_VTXFMT0, 2);
        GXPosition3f32(pt0.x, pt0.y, pt0.z);
        GXTexCoord2f32(0.0f, 0.0f);
        GXPosition3f32(pt1.x, pt1.y, pt1.z);
        GXTexCoord2f32(0.0f, 1.0f);
        GXEnd();
    }
}

/* 80263508-80263510       .text stripeGetNext__FP26JSULink<15JPABaseParticle> */
JSULink<JPABaseParticle>* stripeGetNext(JSULink<JPABaseParticle>* link) {
    return link->getNext();
}

/* 80263510-80263518       .text stripeGetPrev__FP26JSULink<15JPABaseParticle> */
JSULink<JPABaseParticle>* stripeGetPrev(JSULink<JPABaseParticle>* link) {
    return link->getPrev();
}

/* 80263518-80263A68       .text exec__17JPADrawExecStripeFPC14JPADrawContext */
void JPADrawExecStripe::exec(const JPADrawContext* pDC) {
    u32 numLinks = pDC->mpActiveParticles->getNumLinks();
    if (numLinks < 2)
        return;

    typedef JSULink<JPABaseParticle>* (*NextFunc)(JSULink<JPABaseParticle>*);

    JSULink<JPABaseParticle>* start;
    NextFunc getNext;
    f32 texT = 0.0f;
    f32 texStep = 1.0f / (numLinks - 1);
    if (!pDC->pbsp->getListOrder()) {
        start = pDC->mpActiveParticles->getFirst();
        getNext = stripeGetNext;
    } else {
        start = pDC->mpActiveParticles->getLast();
        getNext = stripeGetPrev;
        texT = 1.0f;
        texStep = -texStep;
    }

    GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, numLinks * 2);
    for (JSULink<JPABaseParticle>* link = start; link != NULL; link = getNext(link), texT += texStep) {
        JPABaseParticle* ptcl = link->getObject();
        JGeometry::TVec3<f32> pos;
        ptcl->getGlobalPosition(pos);

        JPADrawParams* params = ptcl->getDrawParamPPtr();
        f32 sin = JMASSin(params->mRotateAngle);
        f32 cos = JMASCos(params->mRotateAngle);

        f32 sx0;
        f32 sx1;
        f32 cx0;
        f32 cx1;
        f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
        sx0 = x0 * sin;
        cx0 = x0 * cos;
        f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
        sx1 = x1 * sin;
        cx1 = x1 * cos;

        JGeometry::TVec3<f32> dir;
        JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
        if (dir.isZero())
            dir.set(0.0f, 1.0f, 0.0f);
        else
            dir.normalize();

        JGeometry::TVec3<f32> side;
        side.cross(params->mAxis, dir);
        if (side.isZero())
            side.set(1.0f, 0.0f, 0.0f);
        else
            side.normalize();

        params->mAxis.cross(dir, side);
        params->mAxis.normalize();

        JGeometry::TRotation3<JGeometry::TMatrix33<JGeometry::SMatrix33R<f32> > > mtx;
        mtx.setXYZDir(side, dir, params->mAxis);

        f32* hack = &mtx.mMtx[0][0];

        JGeometry::TVec3<f32> v1(cx0, 0.0f, sx0);
        JGeometry::TVec3<f32> v2(cx1, 0.0f, sx1);
        mtx.mult(v1);
        mtx.mult(v2);

        GXPosition3f32(v1.x + pos.x, v1.y + pos.y, v1.z + pos.z);
        GXTexCoord2f32(0.0f, texT);
        GXPosition3f32(v2.x + pos.x, v2.y + pos.y, v2.z + pos.z);
        GXTexCoord2f32(1.0f, texT);
    }
    GXEnd();
}

/* 80263A68-802643B0       .text exec__22JPADrawExecStripeCrossFPC14JPADrawContext */
void JPADrawExecStripeCross::exec(const JPADrawContext* pDC) {
    u32 numLinks = pDC->mpActiveParticles->getNumLinks();
    if (numLinks < 2)
        return;

    typedef JSULink<JPABaseParticle>* (*NextFunc)(JSULink<JPABaseParticle>*);

    JSULink<JPABaseParticle>* start;
    NextFunc getNext;
    f32 texT0;
    f32 texT;
    f32 texStep = 1.0f / (numLinks - 1);
    if (!pDC->pbsp->getListOrder()) {
        start = pDC->mpActiveParticles->getFirst();
        getNext = stripeGetNext;
        texT = texT0 = 0.0f;
    } else {
        start = pDC->mpActiveParticles->getLast();
        getNext = stripeGetPrev;
        texT = texT0 = 1.0f;
        texStep = -texStep;
    }

    // `dir` is shared between both loops: loop 1 passes its address to the
    // indirect mDirTypeFunc call, which pins it to the stack for the whole
    // function, so loop 2's accesses go through memory as well.
    JGeometry::TVec3<f32> dir;
    JGeometry::TRotation3<JGeometry::TMatrix33<JGeometry::SMatrix33R<f32> > > mtx;
    GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, numLinks * 2);
    for (JSULink<JPABaseParticle>* link = start; link != NULL; link = getNext(link), texT += texStep) {
        JPABaseParticle* ptcl = link->getObject();
        JGeometry::TVec3<f32> pos;
        ptcl->getGlobalPosition(pos);

        JPADrawParams* params = ptcl->getDrawParamPPtr();
        f32 sin = JMASSin(params->mRotateAngle);
        f32 cos = JMASCos(params->mRotateAngle);

        f32 x0 = -params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX + JPADrawContext::pcb->mPivotX);
        JGeometry::TVec3<f32> v1(x0 * cos, 0.0f, x0 * sin);
        f32 x1 = +params->mScaleX * (JPADrawContext::pcb->mGlobalScaleX - JPADrawContext::pcb->mPivotX);
        JGeometry::TVec3<f32> v2(x1 * cos, 0.0f, x1 * sin);

        JPADrawContext::pcb->mDirTypeFunc(ptcl, pDC->pbe, dir);
        if (dir.isZero())
            dir.set(0.0f, 1.0f, 0.0f);
        else
            dir.normalize();

        JGeometry::TVec3<f32> side;
        side.cross(params->mAxis, dir);
        if (side.isZero())
            side.set(1.0f, 0.0f, 0.0f);
        else
            side.normalize();

        params->mAxis.cross(dir, side);
        params->mAxis.normalize();

        mtx.setXYZDir(side, dir, params->mAxis);

        f32* hack = &mtx.mMtx[0][0];

        mtx.mult(v1);
        mtx.mult(v2);

        GXPosition3f32(v1.x + pos.x, v1.y + pos.y, v1.z + pos.z);
        GXTexCoord2f32(0.0f, texT);
        GXPosition3f32(v2.x + pos.x, v2.y + pos.y, v2.z + pos.z);
        GXTexCoord2f32(1.0f, texT);
    }
    GXEnd();

    texT = texT0;
    GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, numLinks * 2);
    for (JSULink<JPABaseParticle>* link = start; link != NULL; link = getNext(link), texT += texStep) {
        JPABaseParticle* ptcl = link->getObject();
        JGeometry::TVec3<f32> pos;
        ptcl->getGlobalPosition(pos);

        JPADrawParams* params = ptcl->getDrawParamPPtr();
        f32 cos = JMASCos(params->mRotateAngle);
        f32 sin = -JMASSin(params->mRotateAngle);

        f32 scaleY = params->mScaleY;
        f32 x0 = scaleY * (JPADrawContext::pcb->mGlobalScaleY + JPADrawContext::pcb->mPivotY);
        // This stripe is the perpendicular one, so the width direction is
        // (-sin, 0, cos) instead of the first loop's (cos, 0, sin).
        JGeometry::TVec3<f32> v1(x0 * sin, 0.0f, x0 * cos);
        scaleY = -scaleY;
        f32 x1 = scaleY * (JPADrawContext::pcb->mGlobalScaleY - JPADrawContext::pcb->mPivotY);
        JGeometry::TVec3<f32> v2(x1 * sin, 0.0f, x1 * cos);

        ptcl->getVelVec(dir);

        if (dir.isZero())
            dir.set(0.0f, 1.0f, 0.0f);
        else
            dir.normalize();

        JGeometry::TVec3<f32> side;
        side.cross(params->mAxis, dir);
        if (side.isZero())
            side.set(1.0f, 0.0f, 0.0f);
        else
            side.normalize();

        params->mAxis.cross(dir, side);
        params->mAxis.normalize();

        mtx.setXYZDir(side, dir, params->mAxis);

        f32* hack2 = &mtx.mMtx[0][0];

        mtx.mult(v1);
        mtx.mult(v2);

        GXPosition3f32(v1.x + pos.x, v1.y + pos.y, v1.z + pos.z);
        GXTexCoord2f32(0.0f, texT);
        GXPosition3f32(v2.x + pos.x, v2.y + pos.y, v2.z + pos.z);
        GXTexCoord2f32(1.0f, texT);
    }
    GXEnd();
}

/* 802643B0-802644B4       .text exec__33JPADrawExecRegisterColorEmitterPEFPC14JPADrawContext */
void JPADrawExecRegisterColorEmitterPE::exec(const JPADrawContext* pDC) {
    GXColor prm = pDC->mpDraw->mPrmColor;
    GXColor env = pDC->mpDraw->mEnvColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    prm.a = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG0, prm);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 802644B4-80264554       .text exec__32JPADrawExecRegisterColorEmitterPFPC14JPADrawContext */
void JPADrawExecRegisterColorEmitterP::exec(const JPADrawContext* pDC) {
    GXColor prm = pDC->mpDraw->mPrmColor;
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    prm.a = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    GXSetTevColor(GX_TEVREG0, prm);
}

/* 80264554-802645DC       .text exec__32JPADrawExecRegisterColorEmitterEFPC14JPADrawContext */
void JPADrawExecRegisterColorEmitterE::exec(const JPADrawContext* pDC) {
    GXColor env = pDC->mpDraw->mEnvColor;
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 802645DC-80264708       .text exec__31JPADrawExecRegisterColorChildPEFPC14JPADrawContext */
void JPADrawExecRegisterColorChildPE::exec(const JPADrawContext* pDC) {
    GXColor prm = pDC->pssp->getPrm();
    GXColor env = pDC->pssp->getEnv();
    prm.r = JPA_U8_THRE(prm.r, JPADrawContext::pcb->mPrmColor.r);
    prm.g = JPA_U8_THRE(prm.g, JPADrawContext::pcb->mPrmColor.g);
    prm.b = JPA_U8_THRE(prm.b, JPADrawContext::pcb->mPrmColor.b);
    prm.a = JPA_U8_THRE(prm.a, JPADrawContext::pcb->mPrmColor.a);
    env.r = JPA_U8_THRE(env.r, JPADrawContext::pcb->mEnvColor.r);
    env.g = JPA_U8_THRE(env.g, JPADrawContext::pcb->mEnvColor.g);
    env.b = JPA_U8_THRE(env.b, JPADrawContext::pcb->mEnvColor.b);
    GXSetTevColor(GX_TEVREG0, prm);
    GXSetTevColor(GX_TEVREG1, env);
}

/* 80264708-80264774       .text calc__19JPADrawCalcColorPrmFPC14JPADrawContext */
void JPADrawCalcColorPrm::calc(const JPADrawContext* pDC) {
    pDC->mpDraw->mPrmColor = pDC->pbsp->getPrmColor(JPADrawContext::pcb->mColorAnmFrame);
}

/* 80264774-802647E0       .text calc__19JPADrawCalcColorEnvFPC14JPADrawContext */
void JPADrawCalcColorEnv::calc(const JPADrawContext* pDC) {
    pDC->mpDraw->mEnvColor = pDC->pbsp->getEnvColor(JPADrawContext::pcb->mColorAnmFrame);
}

/* 802647E0-8026486C       .text calc__30JPADrawCalcColorAnmFrameNormalFPC14JPADrawContext */
void JPADrawCalcColorAnmFrameNormal::calc(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    int frame = (tick < pDC->pbsp->getColorRegAnmMaxFrm()) ? tick : pDC->pbsp->getColorRegAnmMaxFrm();
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 8026486C-802648E0       .text calc__30JPADrawCalcColorAnmFrameRepeatFPC14JPADrawContext */
void JPADrawCalcColorAnmFrameRepeat::calc(const JPADrawContext* pDC) {
    f32 tick = pDC->pbe->getFrame();
    int frame = ((u32)tick) % (pDC->pbsp->getColorRegAnmMaxFrm() + 1);
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 802648E0-8026495C       .text calc__31JPADrawCalcColorAnmFrameReverseFPC14JPADrawContext */
void JPADrawCalcColorAnmFrameReverse::calc(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    int maxFrame = pDC->pbsp->getColorRegAnmMaxFrm();
    int odd = (tick / maxFrame) & 1; // whether we're on an even or odd loop
    int frame = tick % maxFrame;
    JPADrawContext::pcb->mColorAnmFrame = frame + (odd * maxFrame) - 2 * (odd * frame);
}

/* 8026495C-8026496C       .text calc__29JPADrawCalcColorAnmFrameMergeFPC14JPADrawContext */
void JPADrawCalcColorAnmFrameMerge::calc(const JPADrawContext* pDC) {
    JPADrawContext::pcb->mColorAnmFrame = 0;
}

/* 8026496C-8026497C       .text calc__30JPADrawCalcColorAnmFrameRandomFPC14JPADrawContext */
void JPADrawCalcColorAnmFrameRandom::calc(const JPADrawContext* pDC) {
    JPADrawContext::pcb->mColorAnmFrame = 0;
}

/* 8026497C-80264A34       .text calc__32JPADrawCalcTextureAnmIndexNormalFPC14JPADrawContext */
void JPADrawCalcTextureAnmIndexNormal::calc(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    int idx = ((pDC->pbsp->getTextureAnmKeyNum() - 1) < tick) ? pDC->pbsp->getTextureAnmKeyNum() - 1 : tick;
    pDC->mpDraw->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(idx)];
}

/* 80264A34-80264AD0       .text calc__32JPADrawCalcTextureAnmIndexRepeatFPC14JPADrawContext */
void JPADrawCalcTextureAnmIndexRepeat::calc(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    pDC->mpDraw->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(tick % pDC->pbsp->getTextureAnmKeyNum())];
}

/* 80264AD0-80264B80       .text calc__33JPADrawCalcTextureAnmIndexReverseFPC14JPADrawContext */
void JPADrawCalcTextureAnmIndexReverse::calc(const JPADrawContext* pDC) {
    int tick = pDC->pbe->getFrame();
    int maxFrame = pDC->pbsp->getTextureAnmKeyNum() - 1;
    int odd = (tick / maxFrame) & 1; // whether we're on an even or odd loop
    int frame = tick % maxFrame;
    pDC->mpDraw->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(frame + (odd * maxFrame) - 2 * (odd * frame))];
}

/* 80264B80-80264BC8       .text calc__31JPADrawCalcTextureAnmIndexMergeFPC14JPADrawContext */
void JPADrawCalcTextureAnmIndexMerge::calc(const JPADrawContext* pDC) {
    pDC->mpDraw->mTexIdx = pDC->pbsp->getTextureIndex();
}

/* 80264BC8-80264C10       .text calc__32JPADrawCalcTextureAnmIndexRandomFPC14JPADrawContext */
void JPADrawCalcTextureAnmIndexRandom::calc(const JPADrawContext* pDC) {
    pDC->mpDraw->mTexIdx = pDC->pbsp->getTextureIndex();
}

/* 80264C10-80264C4C       .text exec__19JPADrawExecCallBackFPC14JPADrawContext */
void JPADrawExecCallBack::exec(const JPADrawContext* pDC) {
    pDC->pbe->drawEmitterCallBack();
}

/* 80264C4C-80264C88       .text exec__19JPADrawExecCallBackFPC14JPADrawContextP15JPABaseParticle */
void JPADrawExecCallBack::exec(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPABaseEmitter* pbe = pDC->pbe;
    ptcl->drawCB(pbe);
}

/* 80264C88-80264DB8       .text calc__17JPADrawCalcScaleXFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleX::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    if (JPADrawContext::pcb->mScaleAnmTiming < pDC->pesp->getScaleInTiming()) {
        params->mScaleX = params->mScaleOut * ((pDC->pesp->getIncreaseRateX() * JPADrawContext::pcb->mScaleAnmTiming) + pDC->pesp->getScaleInValueX());
    } else if (JPADrawContext::pcb->mScaleAnmTiming > pDC->pesp->getScaleOutTiming()) {
        params->mScaleX = params->mScaleOut * ((pDC->pesp->getDecreaseRateX() * (JPADrawContext::pcb->mScaleAnmTiming - pDC->pesp->getScaleOutTiming())) + 1.0f);
    } else {
        params->mScaleX = params->mScaleOut;
    }
}

/* 80264DB8-80264EE8       .text calc__17JPADrawCalcScaleYFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleY::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    if (JPADrawContext::pcb->mScaleAnmTiming < pDC->pesp->getScaleInTiming()) {
        params->mScaleY = params->mScaleOut * ((pDC->pesp->getIncreaseRateY() * JPADrawContext::pcb->mScaleAnmTiming) + pDC->pesp->getScaleInValueY());
    } else if (JPADrawContext::pcb->mScaleAnmTiming > pDC->pesp->getScaleOutTiming()) {
        params->mScaleY = params->mScaleOut * ((pDC->pesp->getDecreaseRateY() * (JPADrawContext::pcb->mScaleAnmTiming - pDC->pesp->getScaleOutTiming())) + 1.0f);
    } else {
        params->mScaleY = params->mScaleOut;
    }
}

/* 80264EE8-802650B8       .text calc__24JPADrawCalcScaleXBySpeedFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleXBySpeed::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    JGeometry::TVec3<f32> vel;
    ptcl->getVelVec(vel);
    if (JPADrawContext::pcb->mScaleAnmTiming < pDC->pesp->getScaleInTiming()) {
        params->mScaleX = params->mScaleOut * ((pDC->pesp->getIncreaseRateX() * JPADrawContext::pcb->mScaleAnmTiming) + pDC->pesp->getScaleInValueX());
    } else if (JPADrawContext::pcb->mScaleAnmTiming > pDC->pesp->getScaleOutTiming()) {
        params->mScaleX = params->mScaleOut * ((pDC->pesp->getDecreaseRateX() * (JPADrawContext::pcb->mScaleAnmTiming - pDC->pesp->getScaleOutTiming())) + 1.0f);
    } else {
        params->mScaleX = params->mScaleOut;
    }
    params->mScaleX *= vel.length() * 0.01f;
}

/* 802650B8-80265288       .text calc__24JPADrawCalcScaleYBySpeedFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleYBySpeed::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    JGeometry::TVec3<f32> vel;
    ptcl->getVelVec(vel);
    if (JPADrawContext::pcb->mScaleAnmTiming < pDC->pesp->getScaleInTiming()) {
        params->mScaleY = params->mScaleOut * ((pDC->pesp->getIncreaseRateY() * JPADrawContext::pcb->mScaleAnmTiming) + pDC->pesp->getScaleInValueY());
    } else if (JPADrawContext::pcb->mScaleAnmTiming > pDC->pesp->getScaleOutTiming()) {
        params->mScaleY = params->mScaleOut * ((pDC->pesp->getDecreaseRateY() * (JPADrawContext::pcb->mScaleAnmTiming - pDC->pesp->getScaleOutTiming())) + 1.0f);
    } else {
        params->mScaleY = params->mScaleOut;
    }
    params->mScaleY *= vel.length() * 0.01f;
}

/* 80265288-80265294       .text calc__23JPADrawCalcScaleCopyX2YFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleCopyX2Y::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mScaleY = params->mScaleX;
}

/* 80265294-802652A4       .text calc__31JPADrawCalcScaleAnmTimingNormalFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleAnmTimingNormal::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawContext::pcb->mScaleAnmTiming = ptcl->mCurNormTime;
}

/* 802652A4-80265374       .text calc__32JPADrawCalcScaleAnmTimingRepeatXFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleAnmTimingRepeatX::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawContext::pcb->mScaleAnmTiming = (ptcl->getAge() % pDC->pesp->getAnmCycleX()) / (f32)pDC->pesp->getAnmCycleX();
}

/* 80265374-80265444       .text calc__32JPADrawCalcScaleAnmTimingRepeatYFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleAnmTimingRepeatY::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawContext::pcb->mScaleAnmTiming = (ptcl->getAge() % pDC->pesp->getAnmCycleY()) / (f32)pDC->pesp->getAnmCycleY();
}

/* 80265444-80265588       .text calc__33JPADrawCalcScaleAnmTimingReverseXFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleAnmTimingReverseX::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    f32 odd = (ptcl->getAge() / pDC->pesp->getAnmCycleX()) & 1; // whether we're on an even or odd loop
    f32 frame = (f32)(ptcl->getAge() % pDC->pesp->getAnmCycleX()) / pDC->pesp->getAnmCycleX();
    JPADrawContext::pcb->mScaleAnmTiming = odd + (frame - odd * 2.0f * frame);
}

/* 80265588-802656CC       .text calc__33JPADrawCalcScaleAnmTimingReverseYFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcScaleAnmTimingReverseY::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    f32 odd = (ptcl->getAge() / pDC->pesp->getAnmCycleY()) & 1; // whether we're on an even or odd loop
    f32 frame = (f32)(ptcl->getAge() % pDC->pesp->getAnmCycleY()) / pDC->pesp->getAnmCycleY();
    JPADrawContext::pcb->mScaleAnmTiming = odd + (frame - odd * 2.0f * frame);
}

/* 802656CC-80265734       .text calc__19JPADrawCalcColorPrmFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorPrm::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mPrmColor = pDC->pbsp->getPrmColor(JPADrawContext::pcb->mColorAnmFrame);
}

/* 80265734-8026579C       .text calc__19JPADrawCalcColorEnvFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorEnv::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mEnvColor = pDC->pbsp->getEnvColor(JPADrawContext::pcb->mColorAnmFrame);
}

/* 8026579C-802657E8       .text calc__31JPADrawCalcColorCopyFromEmitterFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorCopyFromEmitter::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mPrmColor = pDC->mpDraw->mPrmColor;
    params->mEnvColor = pDC->mpDraw->mEnvColor;
}

/* 802657E8-80265880       .text calc__30JPADrawCalcColorAnmFrameNormalFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorAnmFrameNormal::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    int frame = (ptcl->getAge() < pDC->pbsp->getColorRegAnmMaxFrm()) ? ptcl->getAge() : pDC->pbsp->getColorRegAnmMaxFrm();
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 80265880-80265918       .text calc__30JPADrawCalcColorAnmFrameRepeatFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorAnmFrameRepeat::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int tick = ptcl->getAge();
    int frame = ((params->mLoopOffset & pDC->pbsp->getColLoopOffset()) + tick) % (pDC->pbsp->getColorRegAnmMaxFrm() + 1);
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 80265918-802659C4       .text calc__31JPADrawCalcColorAnmFrameReverseFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorAnmFrameReverse::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int loopOffset = pDC->pbsp->getColLoopOffset();
    loopOffset = params->mLoopOffset & loopOffset;
    int maxFrame = pDC->pbsp->getColorRegAnmMaxFrm();
    int t = loopOffset + ptcl->getAge();
    int odd = (t / maxFrame) & 1;
    int frame = t % maxFrame;
    JPADrawContext::pcb->mColorAnmFrame = frame + (odd * maxFrame) - 2 * (odd * frame);
}

/* 802659C4-80265A90       .text calc__29JPADrawCalcColorAnmFrameMergeFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorAnmFrameMerge::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int start = params->mLoopOffset & pDC->pbsp->getColLoopOffset();
    int maxFrame = pDC->pbsp->getColorRegAnmMaxFrm() + 1;
    int frame = (int)(start + maxFrame * ptcl->mCurNormTime) % maxFrame;
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 80265A90-80265B14       .text calc__30JPADrawCalcColorAnmFrameRandomFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcColorAnmFrameRandom::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int frame = (params->mLoopOffset & pDC->pbsp->getColLoopOffset()) % (pDC->pbsp->getColorRegAnmMaxFrm() + 1);
    JPADrawContext::pcb->mColorAnmFrame = frame;
}

/* 80265B14-80265C40       .text calc__16JPADrawCalcAlphaFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcAlpha::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 time = ptcl->mCurNormTime;
    f32 alpha;
    if (time < pDC->pesp->getAlphaInTiming()) {
        alpha = time * pDC->pesp->getAlphaIncreaseRate() + pDC->pesp->getAlphaInValue();
    } else if (time > pDC->pesp->getAlphaOutTiming()) {
        alpha = pDC->pesp->getAlphaBaseValue() + pDC->pesp->getAlphaDecreaseRate() * (time - pDC->pesp->getAlphaOutTiming());
    } else {
        alpha = pDC->pesp->getAlphaBaseValue();
    }
    params->mAlphaOut = alpha;
}

/* 80265C40-80265D54       .text calc__27JPADrawCalcAlphaFlickNrmSinFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcAlphaFlickNrmSin::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 sin = JMASSin((ptcl->getAge() * 0x4000) * params->mAlphaWaveRandom * (1.0f - pDC->pesp->getAlphaWaveParam1()));
    params->mAlphaOut *= params->mAlphaWaveRandom * (((sin - 1.0f) * 0.5f) * pDC->pesp->getAlphaWaveParam3()) + 1.0f;
    if (params->mAlphaOut < 0.0f)
        params->mAlphaOut = 0.0f;
}

/* 80265D54-80265EC4       .text calc__27JPADrawCalcAlphaFlickAddSinFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcAlphaFlickAddSin::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 theta = (ptcl->getAge() * 0x4000) * params->mAlphaWaveRandom;
    params->mAlphaOut *=
        (params->mAlphaWaveRandom *
             ((((JMASSin(theta * (1.0f - pDC->pesp->getAlphaWaveParam1())) + JMASSin(theta * (1.0f - pDC->pesp->getAlphaWaveParam2()))) - 2.0f) * 0.5f) *
              pDC->pesp->getAlphaWaveParam3()) +
         2.0f) *
        0.5f;
    if (params->mAlphaOut < 0.0f)
        params->mAlphaOut = 0.0f;
}

/* 80265EC4-80266048       .text calc__28JPADrawCalcAlphaFlickMultSinFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcAlphaFlickMultSin::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    f32 theta = (ptcl->getAge() * 0x4000) * params->mAlphaWaveRandom;
    f32 mul3 = (pDC->pesp->getAlphaWaveParam3() * 0.5f) * params->mAlphaWaveRandom;
    f32 sin2 = JMASSin(theta * (1.0f - pDC->pesp->getAlphaWaveParam2()));
    f32 sin1 = JMASSin(theta * (1.0f - pDC->pesp->getAlphaWaveParam1()));
    params->mAlphaOut *= ((mul3 * (sin1 - 1.0f)) + 1.0f) * ((mul3 * (sin2 - 1.0f)) + 1.0f);
    if (params->mAlphaOut < 0.0f)
        params->mAlphaOut = 0.0f;
}

/* 80266048-80266100       .text calc__32JPADrawCalcTextureAnmIndexNormalFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcTextureAnmIndexNormal::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int idx = ((pDC->pbsp->getTextureAnmKeyNum() - 1) < (int)ptcl->getAge()) ? (pDC->pbsp->getTextureAnmKeyNum() - 1) : ptcl->getAge();
    params->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(idx)];
}

/* 80266100-802661B4       .text calc__32JPADrawCalcTextureAnmIndexRepeatFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcTextureAnmIndexRepeat::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int tick = ptcl->getAge();
    params->mTexIdx =
        pDC->pTexIdx[pDC->pbsp->getTextureIndex(((params->mLoopOffset & pDC->pbsp->getTexLoopOffset()) + tick) % pDC->pbsp->getTextureAnmKeyNum())];
}

/* 802661B4-80266284       .text calc__33JPADrawCalcTextureAnmIndexReverseFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcTextureAnmIndexReverse::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int loopOffset = pDC->pbsp->getTexLoopOffset();
    loopOffset = params->mLoopOffset & loopOffset;
    int maxFrame = pDC->pbsp->getTextureAnmKeyNum() - 1;
    int t = loopOffset + ptcl->getAge();
    int odd = (t / maxFrame) & 1;
    int frame = t % maxFrame;
    params->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(frame + (odd * maxFrame) - 2 * (odd * frame))];
}

/* 80266284-8026636C       .text calc__31JPADrawCalcTextureAnmIndexMergeFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcTextureAnmIndexMerge::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int maxFrame = pDC->pbsp->getTextureAnmKeyNum();
    int start = params->mLoopOffset & pDC->pbsp->getTexLoopOffset();
    int frame = (int)(start + maxFrame * ptcl->mCurNormTime) % maxFrame;
    params->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(frame)];
}

/* 8026636C-8026640C       .text calc__32JPADrawCalcTextureAnmIndexRandomFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcTextureAnmIndexRandom::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    int start = params->mLoopOffset & pDC->pbsp->getTexLoopOffset();
    params->mTexIdx = pDC->pTexIdx[pDC->pbsp->getTextureIndex(start % pDC->pbsp->getTextureAnmKeyNum())];
}

/* 8026640C-80266420       .text calc__24JPADrawCalcChildAlphaOutFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcChildAlphaOut::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mAlphaOut = 1.0f - ptcl->mCurNormTime;
}

/* 80266420-80266450       .text calc__24JPADrawCalcChildScaleOutFPC14JPADrawContextP15JPABaseParticle */
void JPADrawCalcChildScaleOut::calc(const JPADrawContext* pDC, JPABaseParticle* ptcl) {
    JPADrawParams* params = ptcl->getDrawParamPPtr();
    params->mScaleX = params->mScaleOut * (1.0f - ptcl->mCurNormTime);
    params->mScaleY = params->mAlphaWaveRandom * (1.0f - ptcl->mCurNormTime);
}
