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

#include "d/dolzel.h" // IWYU pragma: keep
#include "m_Do/m_Do_ext.h"
#include "JSystem/J3DGraphBase/J3DTransform.h"
#include "JSystem/JKernel/JKRArchive.h"
#include "JSystem/JKernel/JKRSolidHeap.h"
#include "JSystem/JMath/JMath.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "JSystem/JUtility/JUTCacheFont.h"
#include "JSystem/JKernel/JKRHeap.h"
#include "SSystem/SComponent/c_m3d.h"
#include "d/d_com_inf_game.h"
#include "d/d_s_play.h"
#include "dolphin/gf/GF.h"
#include "m_Do/m_Do_mtx.h"
#include "m_Do/m_Do_printf.h"

/* 8000DA70-8000DCF0       .text mDoExt_setJ3DData__FPA4_fPC16J3DTransformInfoUs */
void mDoExt_setJ3DData(Mtx mtx, const J3DTransformInfo* transformInfo, u16 jnt_no) {
    bool local_28;
    if (cM3d_IsZero(transformInfo->mScale.x - 1.0f) && cM3d_IsZero(transformInfo->mScale.y - 1.0f) && cM3d_IsZero(transformInfo->mScale.z - 1.0f)) {
        j3dSys.getModel()->setScaleFlag(jnt_no, 1);
        local_28 = true;
    } else {
        j3dSys.getModel()->setScaleFlag(jnt_no, 0);
        local_28 = false;
    }
    mtx[0][3] = transformInfo->mTranslate.x;
    mtx[1][3] = transformInfo->mTranslate.y;
    mtx[2][3] = transformInfo->mTranslate.z;

    if (!local_28) {
        mtx[0][0] *= transformInfo->mScale.x;
        mtx[0][1] *= transformInfo->mScale.y;
        mtx[0][2] *= transformInfo->mScale.z;
        mtx[1][0] *= transformInfo->mScale.x;
        mtx[1][1] *= transformInfo->mScale.y;
        mtx[1][2] *= transformInfo->mScale.z;
        mtx[2][0] *= transformInfo->mScale.x;
        mtx[2][1] *= transformInfo->mScale.y;
        mtx[2][2] *= transformInfo->mScale.z;
    }
    if (j3dSys.getModel()->getModelData()->getJointNodePointer(jnt_no)->getScaleCompensate() == 1) {
        f32 x = 1.0f / J3DSys::mParentS.x;
        f32 y = 1.0f / J3DSys::mParentS.y;
        f32 z = 1.0f / J3DSys::mParentS.z;
        mtx[0][0] *= x;
        mtx[0][1] *= x;
        mtx[0][2] *= x;
        mtx[1][0] *= y;
        mtx[1][1] *= y;
        mtx[1][2] *= y;
        mtx[2][0] *= z;
        mtx[2][1] *= z;
        mtx[2][2] *= z;
    }
    mDoMtx_concat(J3DSys::mCurrentMtx, mtx, J3DSys::mCurrentMtx);
    j3dSys.getModel()->setAnmMtx(jnt_no, J3DSys::mCurrentMtx);
    J3DSys::mParentS.x = transformInfo->mScale.x;
    J3DSys::mParentS.y = transformInfo->mScale.y;
    J3DSys::mParentS.z = transformInfo->mScale.z;
}

static void dummy1(J3DJoint* joint, J3DAnmTransform* anmTransform) {
    // Fix the weak function order of J3DAnmTransform::getTransform.
    // There was most likely an unused function here that got stripped out.
    j3dSys.setCurrentMtxCalc(NULL);
    anmTransform->getTransform(0, &joint->getTransformInfo());
}

/* 8000DCF4-8000DD4C       .text isCurrentSolidHeap__Fv */
bool isCurrentSolidHeap() {
    if (JKRGetCurrentHeap()->getHeapType() != 'SLID') {
        OSReport_Error("ソリッドヒープちゃうがな！\n");
        return false;
    }
    return true;
}

/* 8000DD4C-8000DF24       .text initPlay__14mDoExt_baseAnmFsifssb */
int mDoExt_baseAnm::initPlay(s16 i_frameMax, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify) {
    JUT_ASSERT(VERSION_SELECT(412, 412, 421, 421), i_modify || isCurrentSolidHeap());
    if (!i_modify) {
        mFrameCtrl = new J3DFrameCtrl();
        if (!mFrameCtrl) {
            return 0;
        }
    }

    mFrameCtrl->setStart(i_startF);

    if (i_endF < 0) {
        mFrameCtrl->init(i_frameMax);
    } else {
        mFrameCtrl->init(i_endF);
    }
    mFrameCtrl->setAttribute(i_attribute);
    mFrameCtrl->setRate(i_rate);

    if (i_rate >= 0.0f) {
        mFrameCtrl->setFrame(i_startF);
    } else {
        mFrameCtrl->setFrame(mFrameCtrl->getEnd());
    }

    mFrameCtrl->setLoop(mFrameCtrl->getFrame());

    return 1;
}

/* 8000DF24-8000DFC4       .text play__14mDoExt_baseAnmFv */
BOOL mDoExt_baseAnm::play() {
    JUT_ASSERT(VERSION_SELECT(453, 453, 462, 462), mFrameCtrl != NULL);
    mFrameCtrl->update();
    return isStop();
}

/* 8000DFC4-8000DFF0       .text init__13mDoExt_bpkAnmFP12J3DModelDataP11J3DAnmColoriifssbi */
int mDoExt_bpkAnm::init(J3DModelData* i_modelData, J3DAnmColor* i_bpk, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    return init(&i_modelData->getMaterialTable(), i_bpk, i_anmPlay, i_attribute, i_rate, i_startF, i_endF, i_modify, i_entry);
}

/* 8000DFF0-8000E014       .text entry__13mDoExt_bpkAnmFP12J3DModelDataf */
void mDoExt_bpkAnm::entry(J3DModelData* i_modelData, f32 param_1) {
    entry(&i_modelData->getMaterialTable(), param_1);
}

/* 8000E014-8000E2A8       .text init__13mDoExt_bpkAnmFP16J3DMaterialTableP11J3DAnmColoriifssbi */
int mDoExt_bpkAnm::init(J3DMaterialTable* i_matTable, J3DAnmColor* i_bpk, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    JUT_ASSERT(VERSION_SELECT(522, 522, 531, 531), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(524, 524, 533, 533), i_matTable != NULL && i_bpk != NULL);
    mpAnm = i_bpk;
    mpAnm->searchUpdateMaterialID(i_matTable);

    u16 updateMaterialNum = mpAnm->getUpdateMaterialNum();
    if (!i_modify) {
        mUpdateMaterialNum = updateMaterialNum;
        JUT_ASSERT(VERSION_SELECT(532, 532, 541, 541), mUpdateMaterialNum);
        field_0xc = new J3DMatColorAnm[mUpdateMaterialNum];
        if (!field_0xc) {
            return 0;
        }
    }
    JUT_ASSERT(VERSION_SELECT(539, 539, 548, 548), updateMaterialNum <= mUpdateMaterialNum);
    J3DMatColorAnm* matColorAnm = field_0xc;
    for (u16 i = 0; i < updateMaterialNum; i++) {
        matColorAnm->setAnmColor(mpAnm);
        matColorAnm->setAnmIndex(i);
        matColorAnm++;
    }

    if (!i_modify && i_entry) {
        i_matTable->setMatColorAnimator(mpAnm, field_0xc);
    }

    if (i_anmPlay) {
        int attribute;
#if VERSION == VERSION_JPN
        if (i_attribute < 0) {
            attribute = mpAnm->getAttribute();
        } else {
            attribute = i_attribute;
        }
#else
        attribute = i_attribute;
#endif
        if (initPlay(mpAnm->getFrameMax(), attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000E2F4-8000E32C       .text entry__13mDoExt_bpkAnmFP16J3DMaterialTablef */
void mDoExt_bpkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) {
    mpAnm->setFrame(i_frame);
    i_matTable->setMatColorAnimator(mpAnm, field_0xc);
}

/* 8000E32C-8000E358       .text init__13mDoExt_btpAnmFP12J3DModelDataP16J3DAnmTexPatterniifssbi */
int mDoExt_btpAnm::init(J3DModelData* i_modelData, J3DAnmTexPattern* i_btp, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    return init(&i_modelData->getMaterialTable(), i_btp, i_anmPlay, i_attribute, i_rate, i_startF, i_endF, i_modify, i_entry);
}

/* 8000E358-8000E37C       .text entry__13mDoExt_btpAnmFP12J3DModelDatas */
void mDoExt_btpAnm::entry(J3DModelData* i_modelData, s16 i_frame) {
    entry(&i_modelData->getMaterialTable(), i_frame);
}

/* 8000E37C-8000E610       .text init__13mDoExt_btpAnmFP16J3DMaterialTableP16J3DAnmTexPatterniifssbi */
int mDoExt_btpAnm::init(J3DMaterialTable* i_matTable, J3DAnmTexPattern* i_btp, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    JUT_ASSERT(VERSION_SELECT(638, 638, 648, 648), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(640, 640, 650, 650), i_matTable != NULL && i_btp != NULL);
    mpAnm = i_btp;
    mpAnm->searchUpdateMaterialID(i_matTable);

    u16 updateMaterialNum = mpAnm->getUpdateMaterialNum();
    if (!i_modify) {
        mUpdateMaterialNum = updateMaterialNum;
        JUT_ASSERT(VERSION_SELECT(648, 648, 658, 658), mUpdateMaterialNum);
        field_0xc = new J3DTexNoAnm[mUpdateMaterialNum];
        if (!field_0xc) {
            return 0;
        }
    }
    JUT_ASSERT(VERSION_SELECT(655, 655, 665, 665), updateMaterialNum <= mUpdateMaterialNum);
    J3DTexNoAnm* texNoAnm = field_0xc;
    for (u16 i = 0; i < updateMaterialNum; i++) {
        texNoAnm->setAnmTexPattern(mpAnm);
        texNoAnm->setAnmIndex(i);
        texNoAnm++;
    }

    if (!i_modify && i_entry) {
        i_matTable->setTexNoAnimator(mpAnm, field_0xc);
    }

    if (i_anmPlay) {
        if (initPlay(mpAnm->getFrameMax(), i_attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000E674-8000E6CC       .text entry__13mDoExt_btpAnmFP16J3DMaterialTables */
void mDoExt_btpAnm::entry(J3DMaterialTable* i_matTable, s16 i_frame) {
    mpAnm->setFrame(i_frame);
    i_matTable->setTexNoAnimator(mpAnm, field_0xc);
}

/* 8000E6CC-8000E6F8       .text init__13mDoExt_btkAnmFP12J3DModelDataP19J3DAnmTextureSRTKeyiifssbi */
int mDoExt_btkAnm::init(J3DModelData* i_modelData, J3DAnmTextureSRTKey* i_btk, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    return init(&i_modelData->getMaterialTable(), i_btk, i_anmPlay, i_attribute, i_rate, i_startF, i_endF, i_modify, i_entry);
}

/* 8000E6F8-8000E71C       .text entry__13mDoExt_btkAnmFP12J3DModelDataf */
void mDoExt_btkAnm::entry(J3DModelData* i_modelData, f32 i_frame) {
    entry(&i_modelData->getMaterialTable(), i_frame);
}

/* 8000E71C-8000EAE4       .text init__13mDoExt_btkAnmFP16J3DMaterialTableP19J3DAnmTextureSRTKeyiifssbi */
int mDoExt_btkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTextureSRTKey* i_btk, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    JUT_ASSERT(VERSION_SELECT(770, 770, 781, 781), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(772, 772, 783, 783), i_matTable != NULL && i_btk != NULL);
    mpAnm = i_btk;
    mpAnm->searchUpdateMaterialID(i_matTable);

    u16 updateMaterialNum = mpAnm->getUpdateMaterialNum();
    if (!i_modify) {
        mUpdateMaterialNum = updateMaterialNum;
        JUT_ASSERT(VERSION_SELECT(780, 780, 791, 791), mUpdateMaterialNum);
        for (u16 i = 0; i < mUpdateMaterialNum; i++) {
            u16 materialId = mpAnm->getUpdateMaterialID(i);
            if (materialId != 0xFFFF) {
                J3DMaterial* material = i_matTable->getMaterialNodePointer(materialId);
                u8 texMtxId = mpAnm->getUpdateTexMtxID(i);
                if (texMtxId != 0xFF) {
                    J3DTexMtx* texMtx = material->getTexMtx(texMtxId);
                    if (!texMtx) {
                        texMtx = new J3DTexMtx();
                    }
                }
            }
        }
        mpTexMtxAnm = new J3DTexMtxAnm[mUpdateMaterialNum];
        if (!mpTexMtxAnm) {
            return 0;
        }
    }
    JUT_ASSERT(VERSION_SELECT(800, 800, 811, 811), updateMaterialNum <= mUpdateMaterialNum);
    J3DTexMtxAnm* texMtxAnm = mpTexMtxAnm;
    for (u16 i = 0; i < updateMaterialNum; i++) {
        texMtxAnm->setAnmTransform(mpAnm);
        texMtxAnm->setAnmIndex(i);
        texMtxAnm++;
    }

    if (!i_modify && i_entry) {
        i_matTable->setTexMtxAnimator(mpAnm, mpTexMtxAnm, NULL);
    }

    if (i_anmPlay) {
        int attribute;
#if VERSION == VERSION_JPN
        if (i_attribute < 0) {
            attribute = mpAnm->getAttribute();
        } else {
            attribute = i_attribute;
        }
#else
        attribute = i_attribute;
#endif
        if (initPlay(mpAnm->getFrameMax(), attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000EB38-8000EB74       .text entry__13mDoExt_btkAnmFP16J3DMaterialTablef */
void mDoExt_btkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) {
    mpAnm->setFrame(i_frame);
    i_matTable->setTexMtxAnimator(mpAnm, mpTexMtxAnm, NULL);
}

/* 8000EB74-8000EBA0       .text init__13mDoExt_brkAnmFP12J3DModelDataP15J3DAnmTevRegKeyiifssbi */
int mDoExt_brkAnm::init(J3DModelData* i_modelData, J3DAnmTevRegKey* i_brk, BOOL i_anmPlay,
                        int i_attribute, f32 i_rate, s16 i_start, s16 i_end, bool i_modify, BOOL i_entry) {
    return init(&i_modelData->getMaterialTable(), i_brk, i_anmPlay, i_attribute, i_rate,
                i_start, i_end, i_modify, i_entry);
}

/* 8000EBA0-8000EBC4       .text entry__13mDoExt_brkAnmFP12J3DModelDataf */
void mDoExt_brkAnm::entry(J3DModelData* i_modelData, f32 i_frame) {
    entry(&i_modelData->getMaterialTable(), i_frame);
}

/* 8000EBC4-8000EEE8       .text init__13mDoExt_brkAnmFP16J3DMaterialTableP15J3DAnmTevRegKeyiifssbi */
int mDoExt_brkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTevRegKey* i_brk, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    JUT_ASSERT(VERSION_SELECT(898, 898, 910, 910), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(900, 900, 912, 912), i_matTable != NULL && i_brk != NULL);
    mpAnm = i_brk;
    mpAnm->searchUpdateMaterialID(i_matTable);

    u16 CRegUpdateMaterialNum = mpAnm->getCRegUpdateMaterialNum();
    if (!i_modify) {
        mCRegUpdateMaterialNum = CRegUpdateMaterialNum;
        mpCRegAnm = new J3DTevColorAnm[mCRegUpdateMaterialNum];
        if (!mpCRegAnm) {
            return 0;
        }
    }
    JUT_ASSERT(VERSION_SELECT(914, 914, 926, 926), CRegUpdateMaterialNum <= mCRegUpdateMaterialNum);
    u16 KRegUpdateMaterialNum = mpAnm->getKRegUpdateMaterialNum();
    if (!i_modify) {
        mKRegUpdateMaterialNum = KRegUpdateMaterialNum;
        mpKRegAnm = new J3DTevKColorAnm[mKRegUpdateMaterialNum];
        if (!mpKRegAnm) {
            return 0;
        }
    }
    JUT_ASSERT(VERSION_SELECT(925, 925, 937, 937), KRegUpdateMaterialNum <= mKRegUpdateMaterialNum);

    J3DTevColorAnm* cRegAnm = mpCRegAnm;
    for (u16 i = 0; i < CRegUpdateMaterialNum; i++) {
        cRegAnm->setAnmIndex(i);
        cRegAnm->setAnmTevReg(mpAnm);
        cRegAnm++;
    }
    J3DTevKColorAnm* kRegAnm = mpKRegAnm;
    for (u16 i = 0; i < KRegUpdateMaterialNum; i++) {
        kRegAnm->setAnmIndex(i);
        kRegAnm->setAnmTevReg(mpAnm);
        kRegAnm++;
    }

    if (!i_modify && i_entry) {
        i_matTable->setTevRegAnimator(mpAnm, mpCRegAnm, mpKRegAnm);
    }

    if (i_anmPlay) {
        int attribute;
#if VERSION == VERSION_JPN
        if (i_attribute < 0) {
            attribute = mpAnm->getAttribute();
        } else {
            attribute = i_attribute;
        }
#else
        attribute = i_attribute;
#endif
        if (initPlay(mpAnm->getFrameMax(), attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000EF80-8000EFBC       .text entry__13mDoExt_brkAnmFP16J3DMaterialTablef */
void mDoExt_brkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) {
    mpAnm->setFrame(i_frame);
    i_matTable->setTevRegAnimator(mpAnm, mpCRegAnm, mpKRegAnm);
}

/* 8000EFBC-8000F178       .text init__13mDoExt_bvaAnmFP8J3DModelP20J3DAnmVisibilityFulliifssbi */
int mDoExt_bvaAnm::init(J3DModel* i_model, J3DAnmVisibilityFull* i_bva, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify, BOOL i_entry) {
    JUT_ASSERT(VERSION_SELECT(989, 989, 1002, 1002), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(991, 991, 1004, 1004), i_model != NULL && i_bva != NULL);
    mpAnm = i_bva;
    if (!i_modify) {
        field_0xc = new J3DVisibilityManager(mpAnm);
        if (!field_0xc) {
            return 0;
        }
        if (i_entry) {
            i_model->setVisibilityManager(field_0xc);
        }
    } else {
        field_0xc->mAnmVisibility = mpAnm;
    }
    if (i_anmPlay) {
        int attribute;
#if VERSION == VERSION_JPN
        if (i_attribute < 0) {
            attribute = mpAnm->getAttribute();
        } else {
            attribute = i_attribute;
        }
#else
        attribute = i_attribute;
#endif
        if (initPlay(mpAnm->getFrameMax(), attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000F178-8000F1B4       .text entry__13mDoExt_bvaAnmFP8J3DModels */
void mDoExt_bvaAnm::entry(J3DModel* i_model, s16 i_frame) {
    mpAnm->setFrame(i_frame);
    i_model->setVisibilityManager(field_0xc);
}

/* 8000F1B4-8000F408       .text init__13mDoExt_bckAnmFP12J3DModelDataP15J3DAnmTransformiifssb */
int mDoExt_bckAnm::init(J3DModelData* i_modelData, J3DAnmTransform* i_bck, BOOL i_anmPlay, int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF, bool i_modify) {
    JUT_ASSERT(VERSION_SELECT(1051, 1051, 1065, 1065), i_modify || isCurrentSolidHeap());
    JUT_ASSERT(VERSION_SELECT(1053, 1053, 1067, 1067), i_bck != NULL);
    mpAnm = i_bck;
    if (!i_modify) {
        mAnm = new J3DMtxCalcMayaAnm(mpAnm);
        if (!mAnm) {
            return 0;
        }
    } else {
        mAnm->setAnmTransform(mpAnm);
    }
    if (i_anmPlay) {
        int attribute;
#if VERSION == VERSION_JPN
        if (i_attribute < 0) {
            attribute = mpAnm->getAttribute();
        } else {
            attribute = i_attribute;
        }
#else
        attribute = i_attribute;
#endif
        if (initPlay(mpAnm->getFrameMax(), attribute, i_rate, i_startF, i_endF, i_modify) == 0) {
            return 0;
        }
    }
    return 1;
}

/* 8000F590-8000F610       .text changeBckOnly__13mDoExt_bckAnmFP15J3DAnmTransform */
void mDoExt_bckAnm::changeBckOnly(J3DAnmTransform* i_bck) {
    mpAnm = i_bck;
    JUT_ASSERT(VERSION_SELECT(1089, 1089, 1104, 1104), mAnm != NULL);
    mAnm->setAnmTransform(mpAnm);
}

/* 8000F610-8000F638       .text entry__13mDoExt_bckAnmFP12J3DModelDataf */
void mDoExt_bckAnm::entry(J3DModelData* i_modelData, f32 i_frame) {
    mpAnm->setFrame(i_frame);
    i_modelData->getJointNodePointer(0)->setMtxCalc(mAnm);
}

/* 8000F638-8000F6A0       .text mDoExt_changeMaterial__FP8J3DModel */
void mDoExt_changeMaterial(J3DModel* i_model) {
    J3DModelData* model_data = i_model->getModelData();

    for (u16 i = 0; i < model_data->getMaterialNum(); i++) {
        model_data->getMaterialNodePointer(i)->change();
    }
}

/* 8000F6A0-8000F758       .text mDoExt_modelTexturePatch__FP12J3DModelData */
void mDoExt_modelTexturePatch(J3DModelData* i_modelData) {
    j3dSys.setTexture(i_modelData->getTexture());

    for (u16 i = 0; i < i_modelData->getMaterialNum(); i++) {
        J3DMaterial* mat = i_modelData->getMaterialNodePointer(i);
        J3DTevBlock* tev = mat->getTevBlock();
        J3DDisplayListObj* dlObj = mat->getSharedDisplayListObj();

        BOOL ret = OSDisableInterrupts();
        GDInitGDLObj(&J3DDisplayListObj::sGDLObj, dlObj->getDisplayList(0),
                     dlObj->getDisplayListSize());
        GDSetCurrent(&J3DDisplayListObj::sGDLObj);
        tev->patchTexNoAndTexCoordScale();
        OSRestoreInterrupts(ret);
        GDSetCurrent(NULL);
    }
}

static void dummy(J3DTevBlock* tev, J3DColorBlock* color, J3DPEBlock* pe) {
    tev->patch();
    color->patchLight();
    pe->patch();
}

/* 8000F768-8000F7BC       .text mDoExt_modelDiff__FP8J3DModel */
void mDoExt_modelDiff(J3DModel* i_model) {
    i_model->calcMaterial();
    i_model->diff();
    i_model->entry();
}

/* 8000F7BC-8000F84C       .text mDoExt_modelUpdate__FP8J3DModel */
void mDoExt_modelUpdate(J3DModel* i_model) {
    J3DModelData* model_data = i_model->getModelData();

    if (model_data->getModelDataType() == 1 && !model_data->isLocked()) {
        i_model->calc();
        mDoExt_modelDiff(i_model);
    } else {
        i_model->update();
        i_model->lock();
    }

    i_model->viewCalc();
}

/* 8000F84C-8000F8F8       .text mDoExt_modelUpdateDL__FP8J3DModel */
void mDoExt_modelUpdateDL(J3DModel* i_model) {
    J3DModelData* model_data = i_model->getModelData();

    if (model_data->getModelDataType() == 1 && !model_data->isLocked()) {
        i_model->calc();
        mDoExt_modelDiff(i_model);
    } else {
        if (REG2_S(9) == 0) {
            i_model->unlock();
        }
        i_model->update();
        i_model->lock();
    }

    i_model->viewCalc();
}

/* 8000F8F8-8000F974       .text mDoExt_modelEntry__FP8J3DModel */
void mDoExt_modelEntry(J3DModel* i_model) {
    J3DModelData* model_data = i_model->getModelData();

    if (model_data->getModelDataType() == 1 && !model_data->isLocked()) {
        mDoExt_modelDiff(i_model);
    } else {
        i_model->entry();
        i_model->lock();
    }

    i_model->viewCalc();
}

/* 8000F974-8000FA0C       .text mDoExt_modelEntryDL__FP8J3DModel */
void mDoExt_modelEntryDL(J3DModel* i_model) {
    J3DModelData* model_data = i_model->getModelData();

    if (model_data->getModelDataType() == 1 && !model_data->isLocked()) {
        mDoExt_modelDiff(i_model);
    } else {
        if (REG2_S(9) == 0) {
            i_model->unlock();
        }
        i_model->entry();
        i_model->lock();
    }

    i_model->viewCalc();
}

/* 8000FA0C-800100F0       .text store__23mDoExt_backupMatBlock_cFP11J3DMaterial */
void mDoExt_backupMatBlock_c::store(J3DMaterial* i_material) {
    J3DColorBlock* colorBlock = i_material->getColorBlock();
    mColorChanNum = colorBlock->getColorChanNum();
    for (u32 i = 0; i < 2; i++) {
        mMatColor[i] = *colorBlock->getMatColor(i);
    }
    for (u32 i = 0; i < 4; i++) {
        mColorChan[i] = *colorBlock->getColorChan(i);
    }
    for (u32 i = 0; i < 2; i++) {
        mAmbColor[i] = *colorBlock->getAmbColor(i);
    }
    J3DTexGenBlock* texGenBlock = i_material->getTexGenBlock();
    mTexGenNum = texGenBlock->getTexGenNum();
    u32 texGenMax = 8;
    if (texGenBlock->getType() == 'TGB4') {
        texGenMax = 4;
    }
    for (u32 i = 0; i < texGenMax; i++) {
        mTexCoord[i] = *texGenBlock->getTexCoord(i);
    }
    for (u32 i = 0; i < texGenMax; i++) {
        if (texGenBlock->getTexMtx(i)) {
            memcpy(&mTexMtx[i], texGenBlock->getTexMtx(i), sizeof(J3DTexMtx));
            DCStoreRange(&mTexMtx[i], sizeof(J3DTexMtx));
        }
    }
    J3DTevBlock* tevBlock = i_material->getTevBlock();
    mTevStageNum = tevBlock->getTevStageNum();
    for (u32 i = 0; i < 4; i++) {
        mTevColor[i] = *tevBlock->getTevColor(i);
    }
    for (u32 i = 0; i < 4; i++) {
        mTevKColor[i] = *tevBlock->getTevKColor(i);
    }
    u32 texNoMax = 8;
    if (tevBlock->getType() == 'TVB4') {
        texNoMax = 4;
        for (u32 i = 0; i < 4; i++) {
            mTevOrder[i] = *tevBlock->getTevOrder(i);
            mTevKColorSel[i] = tevBlock->getTevKColorSel(i);
            mTevKAlphaSel[i] = tevBlock->getTevKAlphaSel(i);
        }
        for (u32 i = 0; i < 4; i++) {
            mTevSwapModeTable[i] = *tevBlock->getTevSwapModeTable(i);
        }
    }
    for (u32 i = 0; i < texNoMax; i++) {
        mTexNo[i] = tevBlock->getTexNo(i);
    }
    for (u32 i = 0; i < texNoMax; i++) {
        mTevStage[i] = *tevBlock->getTevStage(i);
        mIndTevStage[i] = *tevBlock->getIndTevStage(i);
    }
    J3DIndBlock* indBlock = i_material->getIndBlock();
    if (indBlock->getType() == 'IBLF') {
        mIndTexStageNum = indBlock->getIndTexStageNum();
        for (u32 i = 0; i < 4; i++) {
            mIndTexOrder[i] = *indBlock->getIndTexOrder(i);
        }
        for (u32 i = 0; i < 3; i++) {
            mIndTexMtx[i] = *indBlock->getIndTexMtx(i);
        }
        for (u32 i = 0; i < 4; i++) {
            mIndTexCoordScale[i] = *indBlock->getIndTexCoordScale(i);
        }
    }
    J3DPEBlock* peBlock = i_material->getPEBlock();
    memcpy(&mFog, peBlock->getFog(), sizeof(J3DFog));
    DCStoreRange(&mFog, sizeof(J3DFog));
    mAlphaComp = *peBlock->getAlphaComp();
    mBlend = *peBlock->getBlend();
    mZMode = *peBlock->getZMode();
    mZCompLoc = peBlock->getZCompLoc();
    mMaterialAnm = i_material->getMaterialAnm();
    mMaterialMode = i_material->getMaterialMode();
}

/* 800101BC-8001084C       .text restore__23mDoExt_backupMatBlock_cFP11J3DMaterial */
void mDoExt_backupMatBlock_c::restore(J3DMaterial* i_material) {
    /* Nonmatching - retail-only regalloc on indBlock */
    J3DColorBlock* colorBlock = i_material->getColorBlock();
    colorBlock->setColorChanNum(mColorChanNum);
    for (u32 i = 0; i < 2; i++) {
        colorBlock->setMatColor(i, mMatColor[i]);
    }
    for (u32 i = 0; i < 4; i++) {
        colorBlock->setColorChan(i, mColorChan[i]);
    }
    for (u32 i = 0; i < 2; i++) {
        colorBlock->setAmbColor(i, mAmbColor[i]);
    }
    J3DTexGenBlock* texGenBlock = i_material->getTexGenBlock();
    texGenBlock->setTexGenNum(mTexGenNum);
    u32 texGenMax = 8;
    if (texGenBlock->getType() == 'TGB4') {
        texGenMax = 4;
    }
    for (u32 i = 0; i < texGenMax; i++) {
        texGenBlock->setTexCoord(i, &mTexCoord[i]);
    }
    for (u32 i = 0; i < texGenMax; i++) {
        if (texGenBlock->getTexMtx(i)) {
            memcpy(texGenBlock->getTexMtx(i), &mTexMtx[i], sizeof(J3DTexMtx));
            DCStoreRange(texGenBlock->getTexMtx(i), sizeof(J3DTexMtx));
        }
    }
    J3DTevBlock* tevBlock = i_material->getTevBlock();
    tevBlock->setTevStageNum(mTevStageNum);
    for (u32 i = 0; i < 4; i++) {
        tevBlock->setTevColor(i, mTevColor[i]);
    }
    for (u32 i = 0; i < 4; i++) {
        tevBlock->setTevKColor(i, mTevKColor[i]);
    }
    u32 texNoMax = 8;
    if (tevBlock->getType() == 'TVB4') {
        texNoMax = 4;
        for (u32 i = 0; i < 4; i++) {
            tevBlock->setTevOrder(i, mTevOrder[i]);
            tevBlock->setTevKColorSel(i, mTevKColorSel[i]);
            tevBlock->setTevKAlphaSel(i, mTevKAlphaSel[i]);
        }
        for (u32 i = 0; i < 4; i++) {
            tevBlock->setTevSwapModeTable(i, mTevSwapModeTable[i]);
        }
    }
    for (u32 i = 0; i < texNoMax; i++) {
        tevBlock->setTexNo(i, mTexNo[i]);
    }
    for (u32 i = 0; i < texNoMax; i++) {
        tevBlock->setTevStage(i, mTevStage[i]);
        tevBlock->setIndTevStage(i, mIndTevStage[i]);
    }
    J3DIndBlock* indBlock = i_material->getIndBlock();
    if (indBlock->getType() == 'IBLF') {
        indBlock->setIndTexStageNum(mIndTexStageNum);
        for (u32 i = 0; i < 4; i++) {
            *indBlock->getIndTexOrder(i) = mIndTexOrder[i];
        }
        for (u32 i = 0; i < 3; i++) {
            indBlock->setIndTexMtx(i, mIndTexMtx[i]);
        }
        for (u32 i = 0; i < 4; i++) {
            indBlock->setIndTexCoordScale(i, mIndTexCoordScale[i]);
        }
    }
    J3DPEBlock* peBlock = i_material->getPEBlock();
    memcpy(peBlock->getFog(), &mFog, sizeof(J3DFog));
    DCStoreRange(peBlock->getFog(), sizeof(J3DFog));
    peBlock->setAlphaComp(mAlphaComp);
    peBlock->setBlend(mBlend);
    peBlock->setZMode(mZMode);
    peBlock->setZCompLoc(mZCompLoc);
    i_material->setMaterialAnm(mMaterialAnm);
    i_material->setMaterialMode(mMaterialMode);
}

/* 80010920-800109F4       .text create__23mDoExt_backupMaterial_cFP12J3DModelData */
bool mDoExt_backupMaterial_c::create(J3DModelData* i_modelData) {
    if (!mBackupMatBlock) {
        mBackupMatBlock = new mDoExt_backupMatBlock_c[i_modelData->getMaterialNum()];
        if (!mBackupMatBlock) {
            return false;
        }
    }
    for (u16 i = 0; i < i_modelData->getMaterialNum(); i++) {
        J3DMaterial* material = i_modelData->getMaterialNodePointer(i);
        mBackupMatBlock[i].store(material);
    }
    mTexture = i_modelData->getTexture();
    mTextureName = i_modelData->getTextureName();
    return true;
}

/* 800109F4-80010A88       .text __dt__23mDoExt_backupMatBlock_cFv */
mDoExt_backupMatBlock_c::~mDoExt_backupMatBlock_c() {}

/* 80010AC4-80010D44       .text __ct__23mDoExt_backupMatBlock_cFv */
mDoExt_backupMatBlock_c::mDoExt_backupMatBlock_c() {}

/* 80011294-80011300       .text create__23mDoExt_backupMaterial_cFUs */
bool mDoExt_backupMaterial_c::create(u16 param_0) {
    mBackupMatBlock = new mDoExt_backupMatBlock_c[param_0];
    return mBackupMatBlock != NULL;
}

/* 80011300-80011380       .text restore__23mDoExt_backupMaterial_cFP12J3DModelData */
void mDoExt_backupMaterial_c::restore(J3DModelData* i_modelData) {
    for (u16 i = 0; i < i_modelData->getMaterialNum(); i++) {
        J3DMaterial* material = i_modelData->getMaterialNodePointer(i);
        mBackupMatBlock[i].restore(material);
    }
    i_modelData->setTexture(mTexture);
    i_modelData->setTextureName(mTextureName);
}

/* 80011380-80011434       .text create__21mDoExt_invisibleModelFP8J3DModel */
BOOL mDoExt_invisibleModel::create(J3DModel* model) {
    J3DModelData* modelData = model->getModelData();

    mpPackets = new mDoExt_invJntPacket[modelData->getJointNum()];
    if (!mpPackets) {
        return false;
    }

    mModel = model;
    mDoExt_invJntPacket* packet = mpPackets;

    for (u16 i = 0; i < modelData->getJointNum(); i++) {
        packet->setJoint(mModel, i);
        packet++;
    }

    return true;
}

/* 80011504-800115AC       .text entry__21mDoExt_invisibleModelFv */
void mDoExt_invisibleModel::entry() {
    J3DModelData* modelData = mModel->getModelData();
    mDoExt_invJntPacket* packet = mpPackets;

    cXyz tmp;
    for (u16 i = 0; i < modelData->getJointNum(); i++) {
        MtxP anmMtx = mModel->getAnmMtx(i);
        tmp.set(anmMtx[0][3], anmMtx[1][3], anmMtx[2][3]);
        dComIfGd_entryZSortXluList(packet, tmp);
        packet++;
    }
}

/* 800115AC-80011654       .text entryMaskOff__21mDoExt_invisibleModelFv */
void mDoExt_invisibleModel::entryMaskOff() {
    J3DModelData* modelData = mModel->getModelData();
    mDoExt_invJntPacket* packet = mpPackets;

    cXyz tmp;
    for (u16 i = 0; i < modelData->getJointNum(); i++) {
        MtxP anmMtx = mModel->getAnmMtx(i);
        tmp.set(anmMtx[0][3], anmMtx[1][3], anmMtx[2][3]);
        dComIfGd_entryZSortXluListMaskOff(packet, tmp);
        packet++;
    }
}

/* 80011654-800116C4       .text updateDL__21mDoExt_invisibleModelFP8J3DModel */
void mDoExt_invisibleModel::updateDL(J3DModel* model) {
    J3DDrawBuffer* buffer0 = j3dSys.getDrawBuffer(0);
    J3DDrawBuffer* buffer1 = j3dSys.getDrawBuffer(1);
    dComIfGd_setList();
    mDoExt_modelUpdateDL(model);
    entry();
    j3dSys.setDrawBuffer(buffer0, 0);
    j3dSys.setDrawBuffer(buffer1, 1);
}

/* 800116C4-80011734       .text updateDL__21mDoExt_invisibleModelFP14mDoExt_McaMorf */
void mDoExt_invisibleModel::updateDL(mDoExt_McaMorf* param_0) {
    J3DDrawBuffer* buffer0 = j3dSys.getDrawBuffer(0);
    J3DDrawBuffer* buffer1 = j3dSys.getDrawBuffer(1);
    dComIfGd_setList();
    param_0->updateDL();
    entry();
    j3dSys.setDrawBuffer(buffer0, 0);
    j3dSys.setDrawBuffer(buffer1, 1);
}

JKRExpHeap* gameHeap;

/* 80011734-800117E4       .text mDoExt_createGameHeap__FUlP7JKRHeap */
JKRExpHeap* mDoExt_createGameHeap(u32 heapSize, JKRHeap* i_heap) {
    JUT_ASSERT(VERSION_SELECT(2036, 2035, 2050, 2050), gameHeap == NULL || heapSize == 0);
    gameHeap = JKRCreateExpHeap(heapSize, i_heap, true);
#if VERSION > VERSION_DEMO
    gameHeap->setAllocationMode(JKRExpHeap::ALLOC_MODE_1);
#endif
    return gameHeap;
}

/* 800117E4-800117EC       .text mDoExt_getGameHeap__Fv */
JKRExpHeap* mDoExt_getGameHeap() {
    return gameHeap;
}

#if VERSION > VERSION_DEMO
s32 safeGameHeapSize;

/* 800117EC-80011814       .text mDoExt_setSafeGameHeapSize__Fv */
void mDoExt_setSafeGameHeapSize() {
    safeGameHeapSize = mDoExt_getGameHeap()->getTotalFreeSize();
}

/* 80011814-8001181C       .text mDoExt_getSafeGameHeapSize__Fv */
s32 mDoExt_getSafeGameHeapSize() {
    return safeGameHeapSize;
}
#endif

JKRExpHeap* zeldaHeap;

/* 8001181C-800118C0       .text mDoExt_createZeldaHeap__FUlP7JKRHeap */
JKRExpHeap* mDoExt_createZeldaHeap(u32 heapSize, JKRHeap* i_heap) {
    JUT_ASSERT(VERSION_SELECT(2081, 2097, 2112, 2112), zeldaHeap == NULL || heapSize == 0);
    return zeldaHeap = JKRCreateExpHeap(heapSize, i_heap, true);
}

/* 800118C0-800118C8       .text mDoExt_getZeldaHeap__Fv */
JKRExpHeap* mDoExt_getZeldaHeap() {
    return zeldaHeap;
}

#if VERSION > VERSION_DEMO
s32 safeZeldaHeapSize;

/* 800118C8-800118F0       .text mDoExt_setSafeZeldaHeapSize__Fv */
void mDoExt_setSafeZeldaHeapSize() {
    safeZeldaHeapSize = mDoExt_getZeldaHeap()->getTotalFreeSize();
}

/* 800118F0-800118F8       .text mDoExt_getSafeZeldaHeapSize__Fv */
s32 mDoExt_getSafeZeldaHeapSize() {
    return safeZeldaHeapSize;
}
#endif

JKRExpHeap* commandHeap;

/* 800118F8-8001199C       .text mDoExt_createCommandHeap__FUlP7JKRHeap */
JKRExpHeap* mDoExt_createCommandHeap(u32 heapSize, JKRHeap* i_heap) {
    JUT_ASSERT(VERSION_SELECT(2126, 2158, 2173, 2173), commandHeap == NULL || heapSize == 0);
    return commandHeap = JKRCreateExpHeap(heapSize, i_heap, true);
}

/* 8001199C-800119A4       .text mDoExt_getCommandHeap__Fv */
JKRExpHeap* mDoExt_getCommandHeap() {
    return commandHeap;
}

#if VERSION > VERSION_DEMO
s32 safeCommandHeapSize;

/* 800119A4-800119CC       .text mDoExt_setSafeCommandHeapSize__Fv */
void mDoExt_setSafeCommandHeapSize() {
    safeCommandHeapSize = mDoExt_getCommandHeap()->getTotalFreeSize();
}

/* 800119CC-800119D4       .text mDoExt_getSafeCommandHeapSize__Fv */
s32 mDoExt_getSafeCommandHeapSize() {
    return safeCommandHeapSize;
}
#endif

JKRExpHeap* archiveHeap;

/* 800119D4-80011A84       .text mDoExt_createArchiveHeap__FUlP7JKRHeap */
JKRExpHeap* mDoExt_createArchiveHeap(u32 heapSize, JKRHeap* i_heap) {
    JUT_ASSERT(VERSION_SELECT(2173, 2222, 2237, 2237), archiveHeap == NULL || heapSize == 0);
    archiveHeap = JKRCreateExpHeap(heapSize, i_heap, true);
#if VERSION > VERSION_DEMO
    archiveHeap->setAllocationMode(JKRExpHeap::ALLOC_MODE_1);
#endif
    return archiveHeap;
}

#if VERSION > VERSION_DEMO
s32 safeArchiveHeapSize;

/* 80011A84-80011AAC       .text mDoExt_setSafeArchiveHeapSize__Fv */
void mDoExt_setSafeArchiveHeapSize() {
    safeArchiveHeapSize = mDoExt_getArchiveHeap()->getTotalFreeSize();
}

/* 80011AAC-80011AB4       .text mDoExt_getSafeArchiveHeapSize__Fv */
s32 mDoExt_getSafeArchiveHeapSize() {
    return safeArchiveHeapSize;
}
#endif

#if VERSION == VERSION_DEMO
static u8 archiveHeapGroupID;
#endif

JKRHeap* mDoExt_SaveCurrentHeap;

#if VERSION == VERSION_DEMO
static u8 SolidHeapGroupID;
#endif

/* 80011AB4-80011ABC       .text mDoExt_getArchiveHeap__Fv */
JKRExpHeap* mDoExt_getArchiveHeap() {
#if VERSION == VERSION_DEMO
    JKRExpHeap* heap = archiveHeap;
    heap->changeGroupID(archiveHeapGroupID++);
    if (archiveHeapGroupID >= 200) {
        archiveHeapGroupID = 0;
    }
    return heap;
#else
    return archiveHeap;
#endif
}

static void dummy() {
    OSReport("situationHeap == 0 || heapSize == 0");
    OSReport("situationHeapLocked == 0");
    OSReport("situationHeap");
    OSReport("situationHeapLocked");
    OSReport("heap == situationHeap");
}

/* 80011ABC-80011B54       .text mDoExt_createSolidHeap__FUlP7JKRHeapUl */
JKRSolidHeap* mDoExt_createSolidHeap(u32 i_size, JKRHeap* i_heap, u32 i_alignment) {
    if (i_heap == NULL) {
        i_heap = JKRHeap::getCurrentHeap();
    }

    u32 size;
    JKRSolidHeap* createdHeap;

#if VERSION == VERSION_DEMO
    u8 groupID = i_heap->changeGroupID(SolidHeapGroupID);
#endif

    if (i_size == 0 || i_size == -1) {
        createdHeap = JKRSolidHeap::create(-1, i_heap, false);
        size = i_size;
    } else {
        size = ALIGN_NEXT(i_size, 0x10);
        size += sizeof(JKRSolidHeap);

        if (0x10 < i_alignment) {
            size = (i_alignment - 0x10 + size);
        }
        createdHeap = JKRSolidHeap::create(size, i_heap, false);
    }

#if VERSION == VERSION_DEMO
    i_heap->changeGroupID(groupID);
#endif

    if (createdHeap != NULL) {
        createdHeap->setErrorFlag(true);
    }

#if VERSION == VERSION_DEMO
    if (createdHeap == NULL) {
        // "mDoExt_createMaxSolidHeap: Failed to allocate a %fK solid heap.  Contiguous free space=%fK  Remaining free space=%f\n"
        OSReport_Warning(
            "mDoExt_createMaxSolidHeap : ソリッドヒープ%fKの確保に失敗 連続空き容量=%fK 残り空き容量=%f\n",
            size / 1024.0f, i_heap->getFreeSize() / 1024.0f, i_heap->getTotalFreeSize() / 1024.0f
        );
        static BOOL displayed;
        if (!displayed) {
            displayed = TRUE;
            i_heap->dump_sort();
        }
        return createdHeap;
    } else {
        SolidHeapGroupID = SolidHeapGroupID < 199 ? (u8)(SolidHeapGroupID + 1) : 0;
    }
#endif

    return createdHeap;
}

/* 80011B54-80011B9C       .text mDoExt_createSolidHeapFromGame__FUlUl */
JKRSolidHeap* mDoExt_createSolidHeapFromGame(u32 i_size, u32 i_alignment) {
    return mDoExt_createSolidHeap(i_size, mDoExt_getGameHeap(), i_alignment);
}

/* 80011B9C-80011BE4       .text mDoExt_createSolidHeapFromSystem__FUlUl */
JKRSolidHeap* mDoExt_createSolidHeapFromSystem(u32 i_size, u32 i_alignment) {
    return mDoExt_createSolidHeap(i_size, mDoExt_getZeldaHeap(), i_alignment);
}

/* 80011BE4-80011CC0       .text mDoExt_createSolidHeapToCurrent__FUlP7JKRHeapUl */
JKRSolidHeap* mDoExt_createSolidHeapToCurrent(u32 i_size, JKRHeap* i_parent, u32 i_alignment) {
    JKRSolidHeap* resultHeap = mDoExt_createSolidHeap(i_size, i_parent, i_alignment);
    if (!resultHeap) {
        return NULL;
    }
#if VERSION > VERSION_DEMO
    JUT_ASSERT(VERSION_SELECT(0, 2530, 2545, 2545), OSGetCurrentThread() == &mainThread);
#endif
    JUT_ASSERT(VERSION_SELECT(2441, 2531, 2546, 2546), mDoExt_SaveCurrentHeap == NULL);
    mDoExt_SaveCurrentHeap = JKRGetCurrentHeap();
    mDoExt_setCurrentHeap(resultHeap);

    return resultHeap;
}

/* 80011CC0-80011D0C       .text mDoExt_createSolidHeapFromGameToCurrent__FUlUl */
JKRSolidHeap* mDoExt_createSolidHeapFromGameToCurrent(u32 i_size, u32 i_alignment) {
    mDoExt_getGameHeap();
    return mDoExt_createSolidHeapToCurrent(i_size, mDoExt_getGameHeap(), i_alignment);
}

/* 80011D0C-80011D48       .text mDoExt_adjustSolidHeap__FP12JKRSolidHeap */
s32 mDoExt_adjustSolidHeap(JKRSolidHeap* i_heap) {
    if (i_heap == NULL)
        return 0;

    s32 result = i_heap->adjustSize();
    u32 r0 = sizeof(JKRSolidHeap);
    if (result >= r0)
        result -= r0;

    return result;
}

/* 80011D48-80011D68       .text mDoExt_destroySolidHeap__FP12JKRSolidHeap */
void mDoExt_destroySolidHeap(JKRSolidHeap* i_heap) {
    i_heap->destroy();
}

/* 80011D68-80011DD4       .text mDoExt_setCurrentHeap__FP7JKRHeap */
JKRHeap* mDoExt_setCurrentHeap(JKRHeap* heap) {
    JUT_ASSERT(VERSION_SELECT(2578, 2669, 2684, 2684), heap != NULL);
    return heap->becomeCurrentHeap();
}

/* 80011DD4-80011DDC       .text mDoExt_getCurrentHeap__Fv */
JKRHeap* mDoExt_getCurrentHeap() {
    return JKRGetCurrentHeap();
}

/* 80011DDC-80011E98       .text mDoExt_restoreCurrentHeap__Fv */
void mDoExt_restoreCurrentHeap() {
#if VERSION > VERSION_DEMO
    JUT_ASSERT(VERSION_SELECT(0, 2739, 2754, 2754), OSGetCurrentThread() == &mainThread);
#endif
    JUT_ASSERT(VERSION_SELECT(2647, 2740, 2755, 2755), mDoExt_SaveCurrentHeap != NULL);
    mDoExt_SaveCurrentHeap->becomeCurrentHeap();
    mDoExt_SaveCurrentHeap = NULL;
}

/* 80011E98-80011EE4       .text mDoExt_resIDToIndex__FP10JKRArchiveUs */
s32 mDoExt_resIDToIndex(JKRArchive* p_archive, u16 id) {
    JKRArchive::SDIFileEntry* res = p_archive->findIdResource(id);

    if (res == NULL) {
        return -1;
    }

    return res - p_archive->mFiles;
}

/* 80011EE4-80012140       .text calc__25mDoExt_MtxCalcAnmBlendTblFUs */
void mDoExt_MtxCalcAnmBlendTbl::calc(u16 jnt_no) {
    j3dSys.setCurrentMtxCalc(this);
    if (mNum == 1) {
        J3DTransformInfo info1;
        mAnmRatio->getAnmTransform()->getTransform(jnt_no, &info1);
        calcTransform(jnt_no, info1);
        return;
    }
    J3DTransformInfo info2;
    Quaternion quat1;
    Quaternion quat2;
    Quaternion quat3;
    mAnmRatio->getAnmTransform()->getTransform(jnt_no, &info2);
    JMAEulerToQuat(info2.mRotation.x, info2.mRotation.y, info2.mRotation.z, &quat1);
    f32 f30 = mAnmRatio[0].getRatio();
    quat3 = quat1;
    for (int i = 1; i < mNum; i++) {
        J3DAnmTransform* transform = mAnmRatio[i].getAnmTransform();
        if (transform) {
            J3DTransformInfo info3;
            transform->getTransform(jnt_no, &info3);
            f32 ratio = mAnmRatio[i].getRatio();
            f30 = 1.0f - ratio;
            JMAEulerToQuat(info3.mRotation.x, info3.mRotation.y, info3.mRotation.z, &quat2);
            JMAQuatLerp(&quat1, &quat2, ratio, &quat3);
            quat1 = quat3;
            info2.mTranslate.x = info2.mTranslate.x * f30 + info3.mTranslate.x * ratio;
            info2.mTranslate.y = info2.mTranslate.y * f30 + info3.mTranslate.y * ratio;
            info2.mTranslate.z = info2.mTranslate.z * f30 + info3.mTranslate.z * ratio;
            info2.mScale.x = info2.mScale.x * f30 + info3.mScale.x * ratio;
            info2.mScale.y = info2.mScale.y * f30 + info3.mScale.y * ratio;
            info2.mScale.z = info2.mScale.z * f30 + info3.mScale.z * ratio;
        }
    }
    Mtx mtx;
    MTXQuat(mtx, &quat3);
    mDoExt_setJ3DData(mtx, &info2, jnt_no);
}

/* 80012140-80012548       .text calc__28mDoExt_MtxCalcAnmBlendTblOldFUs */
void mDoExt_MtxCalcAnmBlendTblOld::calc(u16 jnt_no) {
    j3dSys.setCurrentMtxCalc(this);
    J3DTransformInfo info1;
    Quaternion quat1;
    Quaternion quat2;
    Quaternion quat3;
    mAnmRatio->getAnmTransform()->getTransform(jnt_no, &info1);
    JMAEulerToQuat(info1.mRotation.x, info1.mRotation.y, info1.mRotation.z, &quat1);
    quat3 = quat1;
    for (int i = 1; i < mNum; i++) {
        if (mAnmRatio[i].getAnmTransform()) {
            J3DAnmTransform* transform = mAnmRatio[i].getAnmTransform();
            J3DTransformInfo info2;
            transform->getTransform(jnt_no, &info2);
            f32 ratio = mAnmRatio[i].getRatio();
            f32 f30 = 1.0f - ratio;
            JMAEulerToQuat(info2.mRotation.x, info2.mRotation.y, info2.mRotation.z, &quat2);
            JMAQuatLerp(&quat1, &quat2, ratio, &quat3);
            quat1 = quat3;
            info1.mTranslate.x = info1.mTranslate.x * f30 + info2.mTranslate.x * ratio;
            info1.mTranslate.y = info1.mTranslate.y * f30 + info2.mTranslate.y * ratio;
            info1.mTranslate.z = info1.mTranslate.z * f30 + info2.mTranslate.z * ratio;
            info1.mScale.x = info1.mScale.x * f30 + info2.mScale.x * ratio;
            info1.mScale.y = info1.mScale.y * f30 + info2.mScale.y * ratio;
            info1.mScale.z = info1.mScale.z * f30 + info2.mScale.z * ratio;
        }
    }

    J3DModel* model = j3dSys.getModel();
    J3DTransformInfo* oldTransInfo = mOldFrame->getOldFrameTransInfo(jnt_no);
    Quaternion* oldQuat = mOldFrame->getOldFrameQuaternion(jnt_no);
    if (mOldFrame->getOldFrameFlg()) {
        if (mOldFrame->getOldFrameRate() > 0.0f && mOldFrame->getOldFrameStartJoint() <= jnt_no && mOldFrame->getOldFrameEndJoint() > jnt_no) {
            f32 oldFrameRate = mOldFrame->getOldFrameRate();
            f32 f31 = 1.0f - oldFrameRate;
            JMAQuatLerp(oldQuat, &quat1, f31, &quat3);
            info1.mTranslate.x = info1.mTranslate.x * f31 + oldTransInfo->mTranslate.x * oldFrameRate;
            info1.mTranslate.y = info1.mTranslate.y * f31 + oldTransInfo->mTranslate.y * oldFrameRate;
            info1.mTranslate.z = info1.mTranslate.z * f31 + oldTransInfo->mTranslate.z * oldFrameRate;
            info1.mScale.x = info1.mScale.x * f31 + oldTransInfo->mScale.x * oldFrameRate;
            info1.mScale.y = info1.mScale.y * f31 + oldTransInfo->mScale.y * oldFrameRate;
            info1.mScale.z = info1.mScale.z * f31 + oldTransInfo->mScale.z * oldFrameRate;
        }
    } else if (jnt_no == model->getModelData()->getJointNum() - 1) {
        mOldFrame->onOldFrameFlg();
    }
    Mtx mtx;
    if (mBeforeCallback) {
        mBeforeCallback(mUserArea, jnt_no, &info1, &quat3);
    }
    mDoMtx_quat(mtx, &quat3);
    mDoExt_setJ3DData(mtx, &info1, jnt_no);
    if (mAfterCallback) {
        mAfterCallback(mUserArea, jnt_no, &info1, &quat3);
    }
    *oldQuat = quat3;
    *oldTransInfo = info1;
    if (jnt_no == model->getModelData()->getJointNum() - 1) {
        mOldFrame->decOldFrameMorfCounter();
    }
}

/* 80012548-800125CC       .text initOldFrameMorf__22mDoExt_MtxCalcOldFrameFfUsUs */
void mDoExt_MtxCalcOldFrame::initOldFrameMorf(f32 i_morf, u16 i_frameStartJoint, u16 i_frameEndJoint) {
    if (i_morf > 0.0f) {
        mOldFrameMorfCounter = i_morf;
        field_0x8 = 1.0f / i_morf;
        mOldFrameRate = 1.0f;
        field_0x10 = 1.0f;
        field_0x14 = 1.0f;
        decOldFrameMorfCounter();
    } else {
        mOldFrameMorfCounter = 0.0f;
        field_0x8 = 0.0f;
        mOldFrameRate = 0.0f;
        field_0x10 = 0.0f;
        field_0x14 = 0.0f;
    }
    mOldFrameStartJoint = i_frameStartJoint;
    mOldFrameEndJoint = i_frameEndJoint;
}

/* 800125CC-80012650       .text decOldFrameMorfCounter__22mDoExt_MtxCalcOldFrameFv */
void mDoExt_MtxCalcOldFrame::decOldFrameMorfCounter() {
    if (!(mOldFrameMorfCounter > 0.0f)) {
        return;
    }
    mOldFrameMorfCounter -= 1.0f;
    if (mOldFrameMorfCounter <= 0.0f) {
        mOldFrameMorfCounter = 0.0f;
        field_0x8 = 0.0f;
        mOldFrameRate = 0.0f;
    }
    field_0x14 = field_0x10;
    field_0x10 = mOldFrameMorfCounter * field_0x8;
    if (field_0x14 > 0.0f) {
        mOldFrameRate = 1.0f - (field_0x14 - field_0x10) / field_0x14;
        return;
    }
    mOldFrameRate = 0.0f;
}

/* 80012650-800129E4       .text __ct__14mDoExt_McaMorfFP12J3DModelDataP25mDoExt_McaMorfCallBack1_cP25mDoExt_McaMorfCallBack2_cP15J3DAnmTransformifiiiPvUlUl */
mDoExt_McaMorf::mDoExt_McaMorf(J3DModelData* modelData, mDoExt_McaMorfCallBack1_c* callback1,
                               mDoExt_McaMorfCallBack2_c* callback2, J3DAnmTransform* anmTransform,
                               int loopMode, f32 playSpeed, int startFrame, int endFrame, BOOL param_8,
                               void* basAnm, u32 modelFlag, u32 differedDlistFlag) {
    mpModel = NULL;
    mpSound = NULL;
    mpTransformInfo = NULL;
    mpQuat = NULL;
    if (!modelData) {
        return;
    }
    if (modelData->getModelDataType() == 1 && modelFlag == 0) {
        if (modelData->isLocked()) {
            modelFlag = 0x20000;
        } else {
            modelFlag = 0x80000;
        }
    }
    mpModel = mDoExt_J3DModel__create(modelData, modelFlag, differedDlistFlag);
    if (!mpModel) {
        return;
    }
    if (modelFlag != 0x80000) {
        mDoExt_changeMaterial(mpModel);
    }
    if (basAnm == NULL && anmTransform) {
        basAnm = ((mDoExt_transAnmBas*)anmTransform)->getBas();
        if (basAnm) {
            param_8 = TRUE;
        }
    }
    if (param_8) {
        mpSound = new mDoExt_zelAnime();
        if (!mpSound) {
            goto ERROR_EXIT;
        }
    }
    setAnm(anmTransform, loopMode, 0.0f, playSpeed, startFrame, endFrame, basAnm);
    mPrevMorf = -1.0f;
    mpTransformInfo = new J3DTransformInfo[modelData->getJointNum()];
    if (!mpTransformInfo) {
        goto ERROR_EXIT;
    }
    mpQuat = new Quaternion[modelData->getJointNum()];
    if (!mpQuat) {
        goto ERROR_EXIT;
    }

    {
        J3DTransformInfo* info = mpTransformInfo;
        Quaternion* quat = mpQuat;
        J3DModelData* r23 = mpModel->getModelData();
        int jointNum = r23->getJointNum();
        for (int i = 0; i < jointNum; i++) {
            *info = r23->getJointNodePointer(i)->getTransformInfo();
            JMAEulerToQuat(info->mRotation.x, info->mRotation.y, info->mRotation.z, quat);
            info++;
            quat++;
        }
        mpCallback1 = callback1;
        mpCallback2 = callback2;
        return;
    }
    
ERROR_EXIT:
    if (mpSound) {
        mpSound->stop();
        mpSound = NULL;
    }
    if (mpTransformInfo) {
        mpTransformInfo = NULL;
    }
    if (mpQuat) {
        mpQuat = NULL;
    }
    if (mpModel) {
        mpModel = NULL;
    }
}

/* 80012A2C-80012D78       .text calc__14mDoExt_McaMorfFUs */
void mDoExt_McaMorf::calc(u16 jnt_no) {
    if (!mpModel) {
        return;
    }
    j3dSys.setCurrentMtxCalc(this);
    J3DTransformInfo info1;
    J3DTransformInfo* infoPtr;
    if (mpTransformInfo == NULL) {
        infoPtr = &info1;
    } else {
        infoPtr = &mpTransformInfo[jnt_no];
    }
    Quaternion quat1;
    Quaternion* quatPtr;
    if (mpQuat == NULL) {
        quatPtr = &quat1;
    } else {
        quatPtr = &mpQuat[jnt_no];
    }
    if (!mpAnm) {
        *infoPtr = mpModel->getModelData()->getJointNodePointer(jnt_no)->getTransformInfo();
        if (mpCallback1) {
            mpCallback1->execute(jnt_no, infoPtr);
        }
        JMAEulerToQuat(infoPtr->mRotation.x, infoPtr->mRotation.y, infoPtr->mRotation.z, quatPtr);
        calcTransform(jnt_no, *infoPtr);
    } else if (mCurMorf >= 1.0f || !mpTransformInfo || !mpQuat) {
        mpAnm->getTransform(jnt_no, infoPtr);
        if (mpCallback1) {
            mpCallback1->execute(jnt_no, infoPtr);
        }
        JMAEulerToQuat(infoPtr->mRotation.x, infoPtr->mRotation.y, infoPtr->mRotation.z, quatPtr);
        calcTransform(jnt_no, *infoPtr);
    } else {
        f32 f31 = (mCurMorf - mPrevMorf) / (1.0f - mPrevMorf);
        f32 f30 = 1.0f - f31;
        J3DTransformInfo info2;
        Quaternion quat2;
        mpAnm->getTransform(jnt_no, &info2);
        if (mpCallback1) {
            mpCallback1->execute(jnt_no, &info2);
        }
        JMAEulerToQuat(info2.mRotation.x, info2.mRotation.y, info2.mRotation.z, &quat2);
        JMAQuatLerp(quatPtr, &quat2, f31, quatPtr);
        Mtx mtx;
        mDoMtx_quat(mtx, quatPtr);
        infoPtr->mTranslate.x = infoPtr->mTranslate.x * f30 + info2.mTranslate.x * f31;
        infoPtr->mTranslate.y = infoPtr->mTranslate.y * f30 + info2.mTranslate.y * f31;
        infoPtr->mTranslate.z = infoPtr->mTranslate.z * f30 + info2.mTranslate.z * f31;
        infoPtr->mScale.x = infoPtr->mScale.x * f30 + info2.mScale.x * f31;
        infoPtr->mScale.y = infoPtr->mScale.y * f30 + info2.mScale.y * f31;
        infoPtr->mScale.z = infoPtr->mScale.z * f30 + info2.mScale.z * f31;
        mDoExt_setJ3DData(mtx, infoPtr, jnt_no);
    }
    if (mpCallback2) {
        mpCallback2->execute(jnt_no);
    }
}

/* 80012D78-80012FC8       .text setAnm__14mDoExt_McaMorfFP15J3DAnmTransformiffffPv */
void mDoExt_McaMorf::setAnm(J3DAnmTransform* bckAnm, int loopMode, f32 morf, f32 playSpeed, f32 startFrame, f32 endFrame, void* basAnm) {
    mpAnm = bckAnm;
    setStartFrame(startFrame);
    if (endFrame < 0.0f) {
        if (!mpAnm) {
            mFrameCtrl.init(0);
        } else {
            mFrameCtrl.init(mpAnm->getFrameMax());
        }
    } else {
        mFrameCtrl.init(endFrame);
    }
    if (bckAnm && loopMode < 0) {
        loopMode = bckAnm->getAttribute();
    }
    setPlayMode(loopMode);
    setPlaySpeed(playSpeed);
    if (playSpeed >= 0.0f) {
        setFrame(startFrame);
    } else {
        setFrame(getEndFrame());
    }
    setLoopFrame(getFrame());
    setMorf(morf);
    if (mpSound) {
        if (basAnm == NULL && bckAnm) {
            basAnm = ((mDoExt_transAnmBas*)bckAnm)->getBas();
        }
        mpSound->mpBasAnm = basAnm;
        if (mpSound->mpBasAnm) {
            mpSound->initActorAnimSound(basAnm, getPlaySpeed() >= 0.0f ? 1 : -1, getLoopFrame());
        } else {
            mpSound->stop();
        }
    }
}

/* 80012FC8-8001300C       .text setMorf__14mDoExt_McaMorfFf */
void mDoExt_McaMorf::setMorf(f32 i_morf) {
    if (mPrevMorf < 0.0f || i_morf <= 0.0f) {
        mCurMorf = 1.0f;
    } else {
        mCurMorf = 0.0f;
        mMorfStep = 1.0f / i_morf;
    }
    mPrevMorf = mCurMorf;
}

/* 8001300C-800130D0       .text play__14mDoExt_McaMorfFP3VecUlSc */
BOOL mDoExt_McaMorf::play(Vec* pos, u32 mtrlSndId, s8 reverb) {
    if (mCurMorf < 1.0f) {
        mPrevMorf = mCurMorf;
        cLib_chaseF(&mCurMorf, 1.0f, mMorfStep);
    }
    mFrameCtrl.update();
    if (mpSound && mpSound->mpBasAnm && pos) {
        mpSound->setAnimSound(pos, getFrame(), getPlaySpeed(), mtrlSndId, reverb);
    }
    return isStop();
}

/* 800130D0-8001314C       .text update__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::update() {
    if (mpModel) {
        if (mpAnm) {
            mpAnm->setFrame(mFrameCtrl.getFrame());
        }
        mpModel->getModelData()->getJointNodePointer(0)->setMtxCalc(this);
        mDoExt_modelUpdate(mpModel);
        mPrevMorf = mCurMorf;
    }
}

/* 8001314C-800131C8       .text updateDL__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::updateDL() {
    if (mpModel) {
        if (mpAnm) {
            mpAnm->setFrame(mFrameCtrl.getFrame());
        }
        mpModel->getModelData()->getJointNodePointer(0)->setMtxCalc(this);
        mDoExt_modelUpdateDL(mpModel);
        mPrevMorf = mCurMorf;
    }
}

/* 800131C8-8001322C       .text updateDL__14mDoExt_McaMorfFP16J3DMaterialTable */
void mDoExt_McaMorf::updateDL(J3DMaterialTable* pMaterialTable) {
    if (mpModel) {
        J3DModelData* modelData = mpModel->getModelData();
        J3DTexture* origTexture = modelData->getTexture();
        JUTNameTab* origTextureName = modelData->getTextureName();
        modelData->setMaterialTable(pMaterialTable, J3DMatCopyFlag_Texture);
        updateDL();
        modelData->setTexture(origTexture);
        modelData->setTextureName(origTextureName);
    }
}

/* 8001322C-80013258       .text entry__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::entry() {
    if (mpModel) {
        mDoExt_modelEntry(mpModel);
    }
}

/* 80013258-80013284       .text entryDL__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::entryDL() {
    if (mpModel) {
        mDoExt_modelEntryDL(mpModel);
    }
}

/* 80013284-800132E8       .text entryDL__14mDoExt_McaMorfFP16J3DMaterialTable */
void mDoExt_McaMorf::entryDL(J3DMaterialTable* pMaterialTable) {
    if (mpModel) {
        J3DModelData* modelData = mpModel->getModelData();
        J3DTexture* origTexture = modelData->getTexture();
        JUTNameTab* origTextureName = modelData->getTextureName();
        modelData->setMaterialTable(pMaterialTable, J3DMatCopyFlag_Texture);
        entryDL();
        modelData->setTexture(origTexture);
        modelData->setTextureName(origTextureName);
    }
}

/* 800132E8-8001335C       .text calc__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::calc() {
    if (mpModel == NULL) {
        return;
    }
    if (mpAnm != NULL) {
        mpAnm->setFrame(getFrame());
    }
    mpModel->getModelData()->getJointNodePointer(0)->setMtxCalc(this);
    mpModel->calc();
}

/* 8001335C-80013388       .text stopZelAnime__14mDoExt_McaMorfFv */
void mDoExt_McaMorf::stopZelAnime() {
    if (mpSound) {
        mpSound->stop();
    }
}

/* 80013388-800136F4       .text __ct__15mDoExt_McaMorf2FP12J3DModelDataP25mDoExt_McaMorfCallBack1_cP25mDoExt_McaMorfCallBack2_cP15J3DAnmTransformP15J3DAnmTransformifiiiPvUlUl */
mDoExt_McaMorf2::mDoExt_McaMorf2(J3DModelData* modelData, mDoExt_McaMorfCallBack1_c* callback1,
                                 mDoExt_McaMorfCallBack2_c* callback2,
                                 J3DAnmTransform* anmTransform1, J3DAnmTransform* anmTransform2,
                                 int loopMode, f32 param_5, int param_6, int param_7, int param_8,
                                 void* basAnm, u32 modelFlag, u32 differedDlistFlag) {
    mpModel = NULL;
    mpSound = NULL;
    mpTransformInfo = NULL;
    mpQuat = NULL;
    if (!modelData) {
        return;
    }
    if (modelData->getModelDataType() == 1 && modelFlag == 0) {
        if (modelData->isLocked()) {
            modelFlag = 0x20000;
        } else {
            modelFlag = 0x80000;
        }
    }
    mpModel = mDoExt_J3DModel__create(modelData, modelFlag, differedDlistFlag);
    if (!mpModel) {
        return;
    }
    if (modelFlag != 0x80000) {
        mDoExt_changeMaterial(mpModel);
    }
    if (basAnm == NULL && anmTransform1) {
        basAnm = ((mDoExt_transAnmBas*)anmTransform1)->getBas();
        if (basAnm) {
            param_8 = 1;
        }
    }
    if (param_8) {
        mpSound = new mDoExt_zelAnime();
        if (!mpSound) {
            ERROR_EXIT();
            return;
        }
    }
    setAnm(anmTransform1, anmTransform2, 0.0f, loopMode, 0.0f, param_5, param_6, param_7, basAnm);
    mpTransformInfo = new J3DTransformInfo[modelData->getJointNum()];
    if (!mpTransformInfo) {
        ERROR_EXIT();
        return;
    }
    mpQuat = new Quaternion[modelData->getJointNum()];
    if (!mpQuat) {
        ERROR_EXIT();
        return;
    }

    J3DTransformInfo* info = mpTransformInfo;
    Quaternion* quat = mpQuat;
    J3DModelData* r23 = mpModel->getModelData();
    int jointNum = r23->getJointNum();
    for (int i = 0; i < jointNum; i++) {
        *info = r23->getJointNodePointer(i)->getTransformInfo();
        JMAEulerToQuat(info->mRotation.x, info->mRotation.y, info->mRotation.z, quat);
        info++;
        quat++;
    }
    mpCallback1 = callback1;
    mpCallback2 = callback2;
}

/* 800136F4-80013770       .text ERROR_EXIT__15mDoExt_McaMorf2Fv */
void mDoExt_McaMorf2::ERROR_EXIT() {
    if (mpSound) {
        mpSound->stop();
        mpSound = NULL;
    }
    if (mpTransformInfo) {
        mpTransformInfo = NULL;
    }
    if (mpQuat) {
        mpQuat = NULL;
    }
    if (mpModel) {
        mpModel = NULL;
    }
}

/* 80013770-80013E50       .text calc__15mDoExt_McaMorf2FUs */
void mDoExt_McaMorf2::calc(u16 jnt_no) {
    if (!mpModel) {
        return;
    }
    j3dSys.setCurrentMtxCalc(this);
    J3DTransformInfo spD8[2];
    J3DTransformInfo sp88;
    J3DTransformInfo sp68;
    J3DTransformInfo* infoPtr;
    if (mpTransformInfo == NULL) {
        infoPtr = &sp88;
    } else {
        infoPtr = &mpTransformInfo[jnt_no];
    }
    Quaternion sp48[2];
    Quaternion sp28[2];
    Quaternion sp18;
    Quaternion sp08;
    Quaternion* quatPtr;
    if (mpQuat == NULL) {
        quatPtr = &sp18;
    } else {
        quatPtr = &mpQuat[jnt_no];
    }
    Mtx mtx;
    f32 f30_f31_1[2];
    f32 f30_f31_2[2];
    f32 f30;
    f32 f31;
    if (!mpAnm1) {
        *infoPtr = mpModel->getModelData()->getJointNodePointer(jnt_no)->getTransformInfo();
        if (mpCallback1) {
            mpCallback1->execute(jnt_no, infoPtr);
        }
        JMAEulerToQuat(infoPtr->mRotation.x, infoPtr->mRotation.y, infoPtr->mRotation.z, quatPtr);
        calcTransform(jnt_no, *infoPtr);
    } else if (mCurMorf >= 1.0f || !mpTransformInfo || !mpQuat) {
        mpAnm1->getTransform(jnt_no, &spD8[0]);
        if (!mpAnm2) {
            if (mpCallback1) {
                mpCallback1->execute(jnt_no, &spD8[0]);
            }
            JMAEulerToQuat(spD8[0].mRotation.x, spD8[0].mRotation.y, spD8[0].mRotation.z, quatPtr);
            calcTransform(jnt_no, spD8[0]);
            *infoPtr = spD8[0];
        } else {
            mpAnm2->getTransform(jnt_no, &spD8[1]);
            f30_f31_1[1] = 1.0f - mAnmRate;
            f30_f31_1[0] = mAnmRate;
            infoPtr->mScale.x = spD8[0].mScale.x * f30_f31_1[1] + spD8[1].mScale.x * f30_f31_1[0];
            infoPtr->mScale.y = spD8[0].mScale.y * f30_f31_1[1] + spD8[1].mScale.y * f30_f31_1[0];
            infoPtr->mScale.z = spD8[0].mScale.z * f30_f31_1[1] + spD8[1].mScale.z * f30_f31_1[0];
            infoPtr->mTranslate.x = spD8[0].mTranslate.x * f30_f31_1[1] + spD8[1].mTranslate.x * f30_f31_1[0];
            infoPtr->mTranslate.y = spD8[0].mTranslate.y * f30_f31_1[1] + spD8[1].mTranslate.y * f30_f31_1[0];
            infoPtr->mTranslate.z = spD8[0].mTranslate.z * f30_f31_1[1] + spD8[1].mTranslate.z * f30_f31_1[0];
            for (int i = 0; i < 2; i++) {
                JMAEulerToQuat(spD8[i].mRotation.x, spD8[i].mRotation.y, spD8[i].mRotation.z, &sp48[i]);
            }
            f32 f1 = f30_f31_1[0] / (f30_f31_1[1] + f30_f31_1[0]);
            JMAQuatLerp(&sp48[0], &sp48[1], f1, quatPtr);
            mDoMtx_quat(mtx, quatPtr);
            mDoExt_setJ3DData(mtx, infoPtr, jnt_no);
        }
    } else if (!mpAnm2) {
        f30 = (mCurMorf - mPrevMorf) / (1.0f - mPrevMorf);
        f31 = 1.0f - f30;
        mpAnm1->getTransform(jnt_no, &sp68);
        if (mpCallback1) {
            mpCallback1->execute(jnt_no, &sp68);
        }
        JMAEulerToQuat(sp68.mRotation.x, sp68.mRotation.y, sp68.mRotation.z, &sp08);
        JMAQuatLerp(quatPtr, &sp08, f30, quatPtr);
        mDoMtx_quat(mtx, quatPtr);
        infoPtr->mTranslate.x = infoPtr->mTranslate.x * f31 + sp68.mTranslate.x * f30;
        infoPtr->mTranslate.y = infoPtr->mTranslate.y * f31 + sp68.mTranslate.y * f30;
        infoPtr->mTranslate.z = infoPtr->mTranslate.z * f31 + sp68.mTranslate.z * f30;
        infoPtr->mScale.x = infoPtr->mScale.x * f31 + sp68.mScale.x * f30;
        infoPtr->mScale.y = infoPtr->mScale.y * f31 + sp68.mScale.y * f30;
        infoPtr->mScale.z = infoPtr->mScale.z * f31 + sp68.mScale.z * f30;
        mDoExt_setJ3DData(mtx, infoPtr, jnt_no);
    } else {
        mpAnm1->getTransform(jnt_no, &spD8[0]);
        mpAnm2->getTransform(jnt_no, &spD8[1]);
        f30_f31_2[1] = 1.0f - mAnmRate;
        f30_f31_2[0] = mAnmRate;
        sp68.mScale.x = spD8[0].mScale.x * f30_f31_2[1] + spD8[1].mScale.x * f30_f31_2[0];
        sp68.mScale.y = spD8[0].mScale.y * f30_f31_2[1] + spD8[1].mScale.y * f30_f31_2[0];
        sp68.mScale.z = spD8[0].mScale.z * f30_f31_2[1] + spD8[1].mScale.z * f30_f31_2[0];
        sp68.mTranslate.x = spD8[0].mTranslate.x * f30_f31_2[1] + spD8[1].mTranslate.x * f30_f31_2[0];
        sp68.mTranslate.y = spD8[0].mTranslate.y * f30_f31_2[1] + spD8[1].mTranslate.y * f30_f31_2[0];
        sp68.mTranslate.z = spD8[0].mTranslate.z * f30_f31_2[1] + spD8[1].mTranslate.z * f30_f31_2[0];
        for (int i = 0; i < 2; i++) {
            JMAEulerToQuat(spD8[i].mRotation.x, spD8[i].mRotation.y, spD8[i].mRotation.z, &sp28[i]);
        }
        f32 f1 = (f30_f31_2[1] + f30_f31_2[0]);
        f1 = f30_f31_2[0] / f1;
        JMAQuatLerp(&sp28[0], &sp28[1], f1, &sp08);
        f30 = (mCurMorf - mPrevMorf) / (1.0f - mPrevMorf);
        f31 = 1.0f - f30;
        JMAQuatLerp(quatPtr, &sp08, f30, quatPtr);
        infoPtr->mTranslate.x = infoPtr->mTranslate.x * f31 + sp68.mTranslate.x * f30;
        infoPtr->mTranslate.y = infoPtr->mTranslate.y * f31 + sp68.mTranslate.y * f30;
        infoPtr->mTranslate.z = infoPtr->mTranslate.z * f31 + sp68.mTranslate.z * f30;
        infoPtr->mScale.x = infoPtr->mScale.x * f31 + sp68.mScale.x * f30;
        infoPtr->mScale.y = infoPtr->mScale.y * f31 + sp68.mScale.y * f30;
        infoPtr->mScale.z = infoPtr->mScale.z * f31 + sp68.mScale.z * f30;
        mDoMtx_quat(mtx, quatPtr);
        mDoExt_setJ3DData(mtx, infoPtr, jnt_no);
    }
    if (mpCallback2) {
        mpCallback2->execute(jnt_no);
    }
}

/* 80013E50-800140A0       .text setAnm__15mDoExt_McaMorf2FP15J3DAnmTransformP15J3DAnmTransformfiffffPv */
void mDoExt_McaMorf2::setAnm(J3DAnmTransform* bckAnm1, J3DAnmTransform* bckAnm2, f32 f1,
                             int loopMode, f32 morf, f32 playSpeed, f32 startFrame, f32 endFrame,
                             void* basAnm) {
    mpAnm1 = bckAnm1;
    mpAnm2 = bckAnm2;
    mAnmRate = f1;
    setStartFrame(startFrame);
    if (endFrame < 0.0f) {
        if (!mpAnm1) {
            mFrameCtrl.init(0);
        } else {
            mFrameCtrl.init(mpAnm1->getFrameMax());
        }
    } else {
        mFrameCtrl.init(endFrame);
    }
    if (loopMode < 0) {
        loopMode = bckAnm1->getAttribute();
    }
    setPlayMode(loopMode);
    setPlaySpeed(playSpeed);
    if (playSpeed >= 0.0f) {
        setFrame(startFrame);
    } else {
        setFrame(getEndFrame());
    }
    setLoopFrame(getFrame());
    setMorf(morf);
    if (mpSound) {
        if (basAnm == NULL && bckAnm1) {
            basAnm = ((mDoExt_transAnmBas*)bckAnm1)->getBas();
        }
        mpSound->mpBasAnm = basAnm;
        if (mpSound->mpBasAnm) {
            mpSound->initActorAnimSound(basAnm, getPlaySpeed() >= 0.0f ? 1 : -1, getLoopFrame());
        } else {
            mpSound->stop();
        }
    }
}

/* 800140A0-800140D8       .text setMorf__15mDoExt_McaMorf2Ff */
void mDoExt_McaMorf2::setMorf(f32 morf) {
    if (morf <= 0.0f) {
        mCurMorf = 1.0f;
    } else {
        mCurMorf = 0.0f;
        mMorfStep = 1.0f / morf;
    }
    mPrevMorf = mCurMorf;
}

/* 800140D8-8001419C       .text play__15mDoExt_McaMorf2FP3VecUlSc */
BOOL mDoExt_McaMorf2::play(Vec* pos, u32 mtrlSndId, s8 reverb) {
    if (mCurMorf < 1.0f) {
        mPrevMorf = mCurMorf;
        cLib_chaseF(&mCurMorf, 1.0f, mMorfStep);
    }
    mFrameCtrl.update();
    if (mpSound && mpSound->mpBasAnm && pos) {
        mpSound->setAnimSound(pos, getFrame(), getPlaySpeed(), mtrlSndId, reverb);
    }
    return isStop();
}

/* 8001419C-800141C8       .text entryDL__15mDoExt_McaMorf2Fv */
void mDoExt_McaMorf2::entryDL() {
    if (mpModel) {
        mDoExt_modelEntryDL(mpModel);
    }
}

/* 800141C8-80014250       .text calc__15mDoExt_McaMorf2Fv */
void mDoExt_McaMorf2::calc() {
    if (mpModel == NULL) {
        return;
    }
    if (mpAnm1 != NULL) {
        mpAnm1->setFrame(getFrame());
    }
    if (mpAnm2 != NULL) {
        mpAnm2->setFrame(getFrame());
    }
    mpModel->getModelData()->getJointNodePointer(0)->setMtxCalc(this);
    mpModel->calc();
}

/* 80014250-8001427C       .text stopZelAnime__15mDoExt_McaMorf2Fv */
void mDoExt_McaMorf2::stopZelAnime() {
    if (mpSound) {
        mpSound->stop();
    }
}

/* 8001427C-800142B8       .text draw__24mDoExt_offCupOnAupPacketFv */
void mDoExt_offCupOnAupPacket::draw() {
    GFSetBlendModeEtc(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR, 0, 1, 1);
}

/* 800142B8-800142F4       .text draw__24mDoExt_onCupOffAupPacketFv */
void mDoExt_onCupOffAupPacket::draw() {
    GFSetBlendModeEtc(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR, 1, 0, 1);
}

/* 800142F4-800143B8       .text draw__19mDoExt_invJntPacketFv */
void mDoExt_invJntPacket::draw() {
    #include "assets/l_invisibleMat__draw__19mDoExt_invJntPacketFv.h"
    
    GXCallDisplayList(l_invisibleMat, 0x80);
    J3DModelData* modelData = mModel->getModelData();
    J3DJoint* joint = modelData->getJointNodePointer(mJntNum);
    J3DMaterial* material = joint->getMesh();
    J3DShape::resetVcdVatCache();
    modelData->getShapeNodePointer(0x00)->loadPreDrawSetting();
    while (material) {
        u16 shapeIdx = material->getShape()->getIndex();
        mModel->getShapePacket(shapeIdx)->drawFast();
        material = material->getNext();
    };
    J3DShape::resetVcdVatCache();
    GFSetBlendModeEtc(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR, 1, 0, 1);
}

#include "assets/l_matDL__m_Do_ext.h"
#include "assets/l_toonMatDL.h"
#include "assets/l_mat1DL.h"
#include "assets/l_toonMat1DL.h"

/* 800143B8-80014580       .text init__15mDoExt_3Dline_cFUsii */
BOOL mDoExt_3Dline_c::init(u16 numSegments, BOOL hasSize, BOOL hasTex) {
    mpSegments = new cXyz[numSegments];
    if (mpSegments == NULL)
        return FALSE;

    if (hasSize) {
        mpSize = new u8[numSegments];
        if (mpSize == NULL)
            return FALSE;
    } else {
        mpSize = NULL;
    }

    u32 numArr = numSegments * 2;
    mPosArr[0] = new cXyz[numArr];
    if (mPosArr[0] == NULL)
        return FALSE;

    mPosArr[1] = new cXyz[numArr];
    if (mPosArr[1] == NULL)
        return FALSE;

    if (hasTex) {
        mTexArr[0] = new cXy[numArr];
        if (mTexArr[0] == NULL)
            return FALSE;

        mTexArr[1] = new cXy[numArr];
        if (mTexArr[1] == NULL)
            return FALSE;

        cXy* tex0 = mTexArr[0];
        cXy* tex1 = mTexArr[1];
        for (s32 i = 0; i < numSegments; i++) {
            tex0[0].x = 0.0f;
            tex1[0].x = 0.0f;
            tex0[1].x = 1.0f;
            tex1[1].x = 1.0f;

            tex0 += 2;
            tex1 += 2;
        }
    }

    return TRUE;
}

/* 80014584-80014664       .text init__19mDoExt_3DlineMat0_cFUsUsi */
BOOL mDoExt_3DlineMat0_c::init(u16 numLines, u16 numSegments, BOOL hasSize) {
    mNumLines = numLines;
    mMaxSegments = numSegments;
    mpLines = new mDoExt_3Dline_c[numLines];
    if (mpLines == NULL)
        return FALSE;

    for (s32 i = 0; i < numLines; i++)
        if (!mpLines[i].init(numSegments, hasSize, FALSE))
            return FALSE;

    mpNextLineMat = NULL;
    mCurArr = 0;
    return TRUE;
}

/* 80014664-800146A0       .text __dt__15mDoExt_3Dline_cFv */
mDoExt_3Dline_c::~mDoExt_3Dline_c() {}

/* 800146A0-800146A4       .text __ct__15mDoExt_3Dline_cFv */
mDoExt_3Dline_c::mDoExt_3Dline_c() {}

/* 800146A4-80014798       .text setMaterial__19mDoExt_3DlineMat0_cFv */
void mDoExt_3DlineMat0_c::setMaterial() {
    static u8 l_normal[][3] = {
        {0x40, 0x00, 0x00},
        {0xC0, 0x00, 0x00},
    };
    j3dSys.reinitGX();
#if VERSION > VERSION_JPN
    GXSetNumIndStages(0);
#endif
    dKy_setLight_again();

    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
    GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);

    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_S8, 6);

    GXSetArray(GX_VA_NRM, l_normal, sizeof(*l_normal));

    if (mpTevStr) {
        dKy_GxFog_tevstr_set(mpTevStr);
        GXCallDisplayList(l_toonMatDL, 0x80);
    } else {
        dKy_GxFog_set();
        GXCallDisplayList(l_matDL, 0x80);
    }

    GXLoadPosMtxImm(j3dSys.getViewMtx(), GX_PNMTX0);
    GXLoadNrmMtxImm(cMtx_getIdentity(), GX_PNMTX0);
}

/* 80014798-800148B4       .text draw__19mDoExt_3DlineMat0_cFv */
void mDoExt_3DlineMat0_c::draw() {
    GXSetTevColor(GX_TEVREG2, mColor);
    if (mpTevStr != NULL) {
        GXSetTevColorS10(GX_TEVREG0, mpTevStr->mColorC0);
        GXSetTevColor(GX_TEVREG1, mpTevStr->mColorK0);
    }

    mDoExt_3Dline_c* line = mpLines;
    u16 numTriStrip = mNumSegments * 2;
    for (s32 i = 0; i < mNumLines; i++) {
        GXSetArray(GX_VA_POS, line->mPosArr[mCurArr], sizeof(cXyz));
        GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, numTriStrip);
        for (u16 j = 0; j < numTriStrip; j += 2) {
            GXPosition1x16(j);
            GXNormal1x8(0);

            GXPosition1x16(j+1);
            GXNormal1x8(1);
        }
        GXEnd();
        line++;
    }

    mCurArr ^= 1;
}

/* 800148B4-80014E04       .text update__19mDoExt_3DlineMat0_cFUsfR8_GXColorUsP12dKy_tevstr_c */
void mDoExt_3DlineMat0_c::update(u16 i_segs, f32 i_size, GXColor& i_color, u16 i_space, dKy_tevstr_c* i_tevStr) {
    cXyz eyeDelta;
    cXyz delta;
    cXyz nextP0;
    cXyz nextP1;

    mDoExt_3Dline_c* line;
    u32 posArrSize;
    cXyz* pos;
    cXyz* r_dstPos;
    cXyz* dstPos;

    mColor = i_color;
    mpTevStr = i_tevStr;
    mNumSegments = i_segs;
    if (mNumSegments > mMaxSegments)
        mNumSegments = mMaxSegments;

    view_class* view = dComIfGd_getView();
    line = mpLines;

    f32 spacing;
    if (i_space != 0) {
        spacing = i_size / i_space;
    } else {
        spacing = 0.0f;
    }

    posArrSize = mNumSegments * 2 * sizeof(cXyz);

    for (s32 i = 0; i < mNumLines; i++) {
        pos = line->mpSegments;
        dstPos = line->mPosArr[mCurArr];
        f32 r_size = i_size;

        delta = pos[1] - pos[0];

        eyeDelta = pos[0] - view->mLookat.mEye;
        delta = delta.outprod(eyeDelta);
        f32 scale = delta.abs();
        if (scale != 0.0f) {
            scale = r_size / scale;
            delta *= scale;
        }

        dstPos[0] = pos[0] + delta;
        dstPos[1] = pos[0] - delta;

        r_dstPos = dstPos;
        r_dstPos += 2;

        pos++;
        nextP0 = pos[0] + delta;
        nextP1 = pos[0] - delta;

        for (s32 j = mNumSegments - 2; j > 0; j--) {
            if (j < i_space)
                r_size -= spacing;

            delta = pos[1] - pos[0];

            eyeDelta = pos[0] - view->mLookat.mEye;
            delta = delta.outprod(eyeDelta);
            scale = delta.abs();
            if (scale != 0.0f)
                scale = r_size / scale;

            delta *= scale;
            nextP0 += pos[0] + delta;
            nextP1 += pos[0] - delta;

            r_dstPos[0] = nextP0 * 0.5f;
            r_dstPos[1] = nextP1 * 0.5f;
            r_dstPos += 2;

            pos++;

            nextP0 = pos[0] + delta;
            nextP1 = pos[0] - delta;
        }

        if (i_space != 0) {
            r_dstPos[0] = pos[0];
            r_dstPos[1] = pos[0];
        } else {
            r_dstPos[0] = nextP0;
            r_dstPos[1] = nextP1;
        }

        DCStoreRangeNoSync(dstPos, posArrSize);
        line++;
    }
}

/* 80014E04-80015328       .text update__19mDoExt_3DlineMat0_cFUsR8_GXColorP12dKy_tevstr_c */
void mDoExt_3DlineMat0_c::update(u16 i_segs, GXColor& i_color, dKy_tevstr_c* i_tevStr) {
    cXyz eyeDelta;
    cXyz delta;
    cXyz nextP0;
    cXyz nextP1;

    mDoExt_3Dline_c* line;
    u32 posArrSize;
    cXyz* pos;
    cXyz* r_dstPos;
    cXyz* dstPos;
    u8* size_p;

    mColor = i_color;
    mpTevStr = i_tevStr;
    mNumSegments = i_segs;
    if (mNumSegments > mMaxSegments)
        mNumSegments = mMaxSegments;

    view_class* view = dComIfGd_getView();
    line = mpLines;

    posArrSize = mNumSegments * 2 * sizeof(cXyz);

    for (s32 i = 0; i < mNumLines; i++) {
        pos = line->mpSegments;

        size_p = line->mpSize;
        JUT_ASSERT(VERSION_SELECT(4629, 4722, 4738, 4738), size_p != NULL);

        dstPos = line->mPosArr[mCurArr];

        delta = pos[1] - pos[0];

        eyeDelta = pos[0] - view->mLookat.mEye;
        delta = delta.outprod(eyeDelta);
        f32 scale = delta.abs();
        if (scale != 0.0f) {
            scale = *size_p / scale;
            delta *= scale;
        }

        dstPos[0] = pos[0] + delta;
        dstPos[1] = pos[0] - delta;

        r_dstPos = dstPos;
        r_dstPos += 2;

        pos++;
        size_p++;
        nextP0 = pos[0] + delta;
        nextP1 = pos[0] - delta;

        for (s32 j = mNumSegments - 2; j > 0; j--) {
            delta = pos[1] - pos[0];

            eyeDelta = pos[0] - view->mLookat.mEye;
            delta = delta.outprod(eyeDelta);
            scale = delta.abs();
            if (scale != 0.0f)
                scale = *size_p / scale;

            delta *= scale;
            nextP0 += pos[0] + delta;
            nextP1 += pos[0] - delta;

            r_dstPos[0] = nextP0 * 0.5f;
            r_dstPos[1] = nextP1 * 0.5f;
            r_dstPos += 2;

            pos++;
            size_p++;

            nextP0 = pos[0] + delta;
            nextP1 = pos[0] - delta;
        }

        r_dstPos[0] = nextP0;
        r_dstPos[1] = nextP1;

        DCStoreRangeNoSync(dstPos, posArrSize);
        line++;
    }
}

/* 80015328-800154C4       .text init__19mDoExt_3DlineMat1_cFUsUsP7ResTIMGi */
BOOL mDoExt_3DlineMat1_c::init(u16 numLines, u16 numSegments, ResTIMG* i_img, BOOL hasSize) {
    mNumLines = numLines;
    mMaxSegments = numSegments;
    mpLines = new mDoExt_3Dline_c[numLines];
    if (mpLines == NULL)
        return FALSE;

    for (s32 i = 0; i < numLines; i++)
        if (!mpLines[i].init(numSegments, hasSize, TRUE))
            return FALSE;

    mpNextLineMat = NULL;
    mCurArr = 0;
    GXInitTexObj(&mTexObj, (&i_img->format + i_img->imageOffset), i_img->width, i_img->height,
                 (GXTexFmt)i_img->format, (GXTexWrapMode)i_img->wrapS, (GXTexWrapMode)i_img->wrapT,
                 (GXBool)(i_img->mipmapCount > 1));
    GXInitTexObjLOD(&mTexObj, (GXTexFilter)i_img->minFilter, (GXTexFilter)i_img->magFilter,
                    i_img->minLOD * 0.125f, i_img->maxLOD * 0.125f, i_img->LODBias * 0.01f,
                    (GXBool)i_img->biasClamp, (GXBool)i_img->doEdgeLOD,
                    (GXAnisotropy)i_img->maxAnisotropy);

    return TRUE;
}

/* 800154C4-800155DC       .text setMaterial__19mDoExt_3DlineMat1_cFv */
void mDoExt_3DlineMat1_c::setMaterial() {
    static u8 l_normal[][3] = {
        {0x40, 0x00, 0x00},
        {0xC0, 0x00, 0x00},
    };
    j3dSys.reinitGX();
#if VERSION > VERSION_JPN
    GXSetNumIndStages(0);
#endif
    dKy_setLight_again();

    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
    GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
    GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16);

    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_S8, 6);
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);

    GXSetArray(GX_VA_NRM, l_normal, sizeof(*l_normal));

    if (mpTevStr) {
        dKy_GxFog_tevstr_set(mpTevStr);
        GXCallDisplayList(l_toonMat1DL, 0xA0);
    } else {
        dKy_GxFog_set();
        GXCallDisplayList(l_mat1DL, 0x80);
    }

    GXLoadPosMtxImm(j3dSys.getViewMtx(), GX_PNMTX0);
    GXLoadNrmMtxImm(cMtx_getIdentity(), GX_PNMTX0);
}

/* 800155DC-80015764       .text draw__19mDoExt_3DlineMat1_cFv */
void mDoExt_3DlineMat1_c::draw() {
    GXLoadTexObj(&mTexObj, GX_TEXMAP0);
    u16 h = GXGetTexObjHeight(&mTexObj);
    u16 w = GXGetTexObjWidth(&mTexObj);
    GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, w, h);
    GXSetTevColor(GX_TEVREG2, mColor);
    if (mpTevStr != NULL) {
        GXSetTevColorS10(GX_TEVREG0, mpTevStr->mColorC0);
        GXSetTevColor(GX_TEVREG1, mpTevStr->mColorK0);
    }

    mDoExt_3Dline_c* line = mpLines;
    u16 numTriStrip = mNumSegments * 2;
    for (s32 i = 0; i < mNumLines; i++) {
        GXSetArray(GX_VA_POS, line->mPosArr[mCurArr], sizeof(cXyz));
        GXSetArray(GX_VA_TEX0, line->mTexArr[mCurArr], sizeof(cXy));
        GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, numTriStrip);
        for (u16 j = 0; j < numTriStrip;) {
            GXPosition1x16(j);
            GXNormal1x8(0);
            GXTexCoord1x16(j++);

            GXPosition1x16(j);
            GXNormal1x8(1);
            GXTexCoord1x16(j++);
        }
        GXEnd();
        line++;
    }

    GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_FALSE, 0, 0);
    mCurArr ^= 1;
}

/* 80015764-80015E54       .text update__19mDoExt_3DlineMat1_cFUsfR8_GXColorUsP12dKy_tevstr_c */
void mDoExt_3DlineMat1_c::update(u16 i_segs, f32 i_size, GXColor& i_color, u16 i_space, dKy_tevstr_c* i_tevStr) {
    cXyz eyeDelta;
    cXyz delta;
    cXyz nextP0;
    cXyz nextP1;

    mDoExt_3Dline_c* line;
    u32 posArrSize;
    u32 texArrSize;
    cXyz* pos;
    cXyz* r_dstPos;
    cXyz* dstPos;
    cXy* r_dstTex;
    cXy* dstTex;

    mColor = i_color;
    mpTevStr = i_tevStr;
    mNumSegments = i_segs;
    if (mNumSegments > mMaxSegments)
        mNumSegments = mMaxSegments;

    view_class* view = dComIfGd_getView();
    line = mpLines;

    f32 spacing;
    if (i_space != 0) {
        spacing = i_size / i_space;
    } else {
        spacing = 0.0f;
    }

    posArrSize = mNumSegments * 2 * sizeof(cXyz);
    texArrSize = mNumSegments * 2 * sizeof(cXy);

    f32 r_size;
    f32 dist = 0.0f;
    for (s32 i = 0; i < mNumLines; i++) {
        pos = line->mpSegments;

        dstPos = line->mPosArr[mCurArr];
        dstTex = line->mTexArr[mCurArr];
        r_size = i_size;

        dstTex[0].y = dist;
        dstTex[1].y = dist;

        r_dstTex = dstTex;
        r_dstTex += 2;

        delta = pos[1] - pos[0];
        f32 mag = delta.abs();

        dist += mag * 0.1f;
        eyeDelta = pos[0] - view->mLookat.mEye;
        delta = delta.outprod(eyeDelta);
        f32 scale = delta.abs();
        if (scale != 0.0f) {
            scale = r_size / scale;
            delta *= scale;
        }

        dstPos[0] = pos[0] + delta;
        dstPos[1] = pos[0] - delta;

        r_dstPos = dstPos;
        r_dstPos += 2;

        pos++;
        nextP0 = pos[0] + delta;
        nextP1 = pos[0] - delta;

        for (s32 j = mNumSegments - 2; j > 0; j--) {
            if (j < i_space)
                r_size -= spacing;

            r_dstTex[0].y = dist;
            r_dstTex[1].y = dist;
            r_dstTex += 2;

            delta = pos[1] - pos[0];
            f32 mag = delta.abs();

            dist += mag * 0.1f;
            eyeDelta = pos[0] - view->mLookat.mEye;
            delta = delta.outprod(eyeDelta);
            scale = delta.abs();
            if (scale != 0.0f)
                scale = r_size / scale;

            delta *= scale;
            nextP0 += pos[0] + delta;
            nextP1 += pos[0] - delta;

            r_dstPos[0] = nextP0 * 0.5f;
            r_dstPos[1] = nextP1 * 0.5f;
            r_dstPos += 2;

            pos++;

            nextP0 = pos[0] + delta;
            nextP1 = pos[0] - delta;
        }

        r_dstTex[0].y = dist;
        r_dstTex[1].y = dist;

        if (i_space != 0) {
            r_dstPos[0] = pos[0];
            r_dstPos[1] = pos[0];
        } else {
            r_dstPos[0] = nextP0;
            r_dstPos[1] = nextP1;
        }

        DCStoreRangeNoSync(dstPos, posArrSize);
        DCStoreRangeNoSync(dstTex, texArrSize);
        line++;
    }
}

/* 80015E54-80016518       .text update__19mDoExt_3DlineMat1_cFUsR8_GXColorP12dKy_tevstr_c */
void mDoExt_3DlineMat1_c::update(u16 i_segs, GXColor& i_color, dKy_tevstr_c* i_tevStr) {
    cXyz eyeDelta;
    cXyz delta;
    cXyz nextP0;
    cXyz nextP1;

    mDoExt_3Dline_c* line;
    u32 posArrSize;
    u32 texArrSize;
    cXyz* pos;
    cXyz* r_dstPos;
    cXyz* dstPos;
    cXy* r_dstTex;
    cXy* dstTex;
    u8* size_p;

    mColor = i_color;
    mpTevStr = i_tevStr;
    mNumSegments = i_segs;
    if (mNumSegments > mMaxSegments)
        mNumSegments = mMaxSegments;

    view_class* view = dComIfGd_getView();
    line = mpLines;

    posArrSize = mNumSegments * 2 * sizeof(cXyz);
    texArrSize = mNumSegments * 2 * sizeof(cXy);

    f32 dist = 0.0f;
    for (s32 i = 0; i < mNumLines; i++) {
        pos = line->mpSegments;

        size_p = line->mpSize;
        JUT_ASSERT(VERSION_SELECT(5133, 5226, 5243, 5243), size_p != NULL);

        dstPos = line->mPosArr[mCurArr];
        dstTex = line->mTexArr[mCurArr];

        dstTex[0].y = dist;
        dstTex[1].y = dist;

        r_dstTex = dstTex;
        r_dstTex += 2;

        delta = pos[1] - pos[0];
        f32 mag = delta.abs();

        dist += mag * 0.1f;
        eyeDelta = pos[0] - view->mLookat.mEye;
        delta = delta.outprod(eyeDelta);
        f32 scale = delta.abs();
        if (scale != 0.0f) {
            scale = *size_p / scale;
            delta *= scale;
        }

        dstPos[0] = pos[0] + delta;
        dstPos[1] = pos[0] - delta;

        r_dstPos = dstPos;
        r_dstPos += 2;
        size_p++;

        pos++;
        nextP0 = pos[0] + delta;
        nextP1 = pos[0] - delta;

        for (s32 j = mNumSegments - 2; j > 0; j--) {
            r_dstTex[0].y = dist;
            r_dstTex[1].y = dist;
            r_dstTex += 2;

            delta = pos[1] - pos[0];
            f32 mag = delta.abs();

            dist += mag * 0.1f;
            eyeDelta = pos[0] - view->mLookat.mEye;
            delta = delta.outprod(eyeDelta);
            scale = delta.abs();
            if (scale != 0.0f)
                scale = *size_p / scale;

            delta *= scale;
            nextP0 += pos[0] + delta;
            nextP1 += pos[0] - delta;

            r_dstPos[0] = nextP0 * 0.5f;
            r_dstPos[1] = nextP1 * 0.5f;
            r_dstPos += 2;

            pos++;
            size_p++;

            nextP0 = pos[0] + delta;
            nextP1 = pos[0] - delta;
        }

        r_dstTex[0].y = dist;
        r_dstTex[1].y = dist;

        r_dstPos[0] = nextP0;
        r_dstPos[1] = nextP1;

        DCStoreRangeNoSync(dstPos, posArrSize);
        DCStoreRangeNoSync(dstTex, texArrSize);
        line++;
    }
}

/* 80016518-8001657C       .text setMat__26mDoExt_3DlineMatSortPacketFP18mDoExt_3DlineMat_c */
void mDoExt_3DlineMatSortPacket::setMat(mDoExt_3DlineMat_c* i_3DlineMat) {
    if (mp3DlineMat == NULL) {
        j3dSys.getDrawBuffer(0)->entryImm(this, 0);
    }
    i_3DlineMat->mpNextLineMat = mp3DlineMat;
    mp3DlineMat = i_3DlineMat;
}

/* 8001657C-800165E4       .text draw__26mDoExt_3DlineMatSortPacketFv */
void mDoExt_3DlineMatSortPacket::draw() {
    mp3DlineMat->setMaterial();
    mDoExt_3DlineMat_c* lineMat = mp3DlineMat;
    do {
        lineMat->draw();
        lineMat = lineMat->mpNextLineMat;
    } while (lineMat);
#if VERSION > VERSION_JPN
    J3DShape::resetVcdVatCache();
#endif
}

#if DEBUG
mDoExt_cube8pPacket::mDoExt_cube8pPacket(cXyz* i_points, const GXColor& i_color) {
    cXyz* pnt_array = mPoints;

    for (int i = 0; i < 8; i++) {
        *(pnt_array)++ = *(i_points)++;
    }

    DCStoreRangeNoSync(mPoints, sizeof(cXyz) * 8);
    mColor = i_color;
}

void drawCube(MtxP mtx, cXyz* pos, const GXColor& color) {
    GXSetArray(GX_VA_POS, pos, sizeof(cXyz));
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP,
                  GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, color);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_BACK);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXLoadPosMtxImm(mtx, 0);
    GXSetCurrentMtx(0);

    GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 14);
    GXPosition1x8(4);
    GXPosition1x8(6);
    GXPosition1x8(5);
    GXPosition1x8(7);
    GXPosition1x8(3);
    GXPosition1x8(6);
    GXPosition1x8(2);
    GXPosition1x8(4);
    GXPosition1x8(0);
    GXPosition1x8(5);
    GXPosition1x8(1);
    GXPosition1x8(3);
    GXPosition1x8(0);
    GXPosition1x8(2);
    GXEnd();
}

void mDoExt_cube8pPacket::draw() {
    drawCube(j3dSys.getViewMtx(), mPoints, mColor);
}

mDoExt_cubePacket::mDoExt_cubePacket(cXyz& i_position, cXyz& i_size, csXyz& i_angle, const GXColor& i_color) {
    mPosition = i_position;
    mSize = i_size;
    mAngle = i_angle;
    mColor = i_color;
}

void mDoExt_cubePacket::draw() {
    static cXyz l_pos[8] = {
        cXyz(-1.0f, 1.0f, -1.0f), cXyz(1.0f, 1.0f, -1.0f),   cXyz(-1.0f, 1.0f, 1.0f),
        cXyz(1.0f, 1.0f, 1.0f),   cXyz(-1.0f, -1.0f, -1.0f), cXyz(1.0f, -1.0f, -1.0f),
        cXyz(-1.0f, -1.0f, 1.0f), cXyz(1.0f, -1.0f, 1.0f),
    };

    mDoMtx_stack_c::transS(mPosition.x, mPosition.y, mPosition.z);
    mDoMtx_stack_c::XYZrotM(mAngle.x, mAngle.y, mAngle.z);
    mDoMtx_stack_c::scaleM(mSize.x, mSize.y, mSize.z);
    mDoMtx_stack_c::revConcat(j3dSys.getViewMtx());
    drawCube(mDoMtx_stack_c::get(), l_pos, mColor);
}

mDoExt_quadPacket::mDoExt_quadPacket(cXyz* i_points, const GXColor& i_color, u8 i_clipZ) {
    cXyz* pnt_array = mPoints;

    for (int i = 0; i < 4; i++) {
        *(pnt_array)++ = *(i_points)++;
    }

    DCStoreRangeNoSync(mPoints, sizeof(cXyz) * 4);
    mColor = i_color;
    mClipZ = i_clipZ;
}

void mDoExt_quadPacket::draw() {
    GXSetArray(GX_VA_POS, mPoints, sizeof(cXyz));
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP,
                  GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_BACK);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
    GXSetCurrentMtx(0);

    GXBegin(GX_QUADS, GX_VTXFMT0, 4);
    GXPosition1x8(0);
    GXPosition1x8(1);
    GXPosition1x8(2);
    GXPosition1x8(3);
    GXEnd();
}

mDoExt_trianglePacket::mDoExt_trianglePacket(cXyz* i_points, const GXColor& i_color, u8 i_clipZ) {
    cXyz* pnt_array = mPoints;

    for (int i = 0; i < 3; i++) {
        *(pnt_array)++ = *(i_points)++;
    }

    DCStoreRangeNoSync(mPoints, sizeof(cXyz) * 3);
    mColor = i_color;
    mClipZ = i_clipZ;
}

void mDoExt_trianglePacket::draw() {
    j3dSys.reinitGX();

    GXSetArray(GX_VA_POS, mPoints, sizeof(cXyz));
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
    GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
    GXSetCurrentMtx(0);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetZCompLoc(GX_ENABLE);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetFog(GX_FOG_NONE, 0.0f, 0.0f, 0.0f, 0.0f, g_clearColor);
    GXSetFogRangeAdj(GX_DISABLE, 0, NULL);
    GXSetCullMode(GX_CULL_NONE);
    GXSetDither(GX_ENABLE);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXSetNumIndStages(0);

    GXBegin(GX_TRIANGLES, GX_VTXFMT0, 3);
    GXPosition1x8(0);
    GXPosition1x8(1);
    GXPosition1x8(2);
    GXEnd();

    J3DShape::resetVcdVatCache();
}

mDoExt_linePacket::mDoExt_linePacket(cXyz& i_start, cXyz& i_end, const GXColor& i_color, u8 i_clipZ, u8 i_width) {
    mStart = i_start;
    mEnd = i_end;
    mColor = i_color;
    mClipZ = i_clipZ;
    mWidth = i_width;
}

void mDoExt_linePacket::draw() {
    j3dSys.reinitGX();

    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
    GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
    GXSetCurrentMtx(0);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetZCompLoc(GX_ENABLE);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetFog(GX_FOG_NONE, 0.0f, 0.0f, 0.0f, 0.0f, g_clearColor);
    GXSetFogRangeAdj(GX_DISABLE, 0, NULL);
    GXSetCullMode(GX_CULL_NONE);
    GXSetDither(GX_ENABLE);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXSetNumIndStages(0);
    GXSetLineWidth(mWidth, GX_TO_ZERO);

    GXBegin(GX_LINES, GX_VTXFMT0, 2);
    GXPosition3f32(mStart.x, mStart.y, mStart.z);
    GXPosition3f32(mEnd.x, mEnd.y, mEnd.z);
    GXEnd();

    J3DShape::resetVcdVatCache();
}

mDoExt_ArrowPacket::mDoExt_ArrowPacket(cXyz& i_position, cXyz& param_1, const GXColor& i_color, u8 i_clipZ, u8 i_lineWidth) {
    mStart = i_position;
    mEnd = param_1;
    mColor = i_color;
    mClipZ = i_clipZ;
    mLineWidth = i_lineWidth;
}

void mDoExt_ArrowPacket::draw() {
    Mtx sp28;
    cXyz sp18;

    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_NONE);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXSetLineWidth(mLineWidth, GX_TO_ZERO);

    sp18 = mEnd - mStart;
    MtxTrans(mStart.x, mStart.y, mStart.z, 0);
    cMtx_YrotM(*calc_mtx, sp18.atan2sX_Z());
    cMtx_XrotM(*calc_mtx, cM_atan2s(JMAFastSqrt(SQUARE(sp18.x) + SQUARE(sp18.z)), sp18.y));
    cMtx_concat(j3dSys.getViewMtx(), *calc_mtx, sp28);

    GXLoadPosMtxImm(sp28, 0);
    GXSetCurrentMtx(0);

    GXBegin(GX_LINES, GX_VTXFMT0, 2);
    GXPosition3f32(0.0f, 0.0f, 0.0f);
    GXPosition3f32(0.0f, sp18.abs(), 0.0f);
    GXEnd();

    f32 var_f29 = sp18.abs();
    f32 var_f31 = var_f29 * 0.1f;
    f32 var_f30 = var_f29 * 0.8f;

    GXBegin(GX_TRIANGLEFAN, GX_VTXFMT0, 6);
    GXPosition3f32(0.0f, var_f29, 0.0f);
    GXPosition3f32(0.0f, var_f30, var_f31);
    GXPosition3f32(var_f31, var_f30, 0.0f);
    GXPosition3f32(0.0f, var_f30, -var_f31);
    GXPosition3f32(-var_f31, var_f30, 0.0f);
    GXPosition3f32(0.0f, var_f30, var_f31);
    GXEnd();
}

mDoExt_pointPacket::mDoExt_pointPacket(cXyz& i_position, const GXColor& i_color, u8 i_clipZ, u8 i_lineWidth) {
    mPosition = i_position;
    mColor = i_color;
    mClipZ = i_clipZ;
    mLineWidth = i_lineWidth;
}

void mDoExt_pointPacket::draw() {
    j3dSys.reinitGX();

    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_NONE);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXSetPointSize(mLineWidth, GX_TO_ZERO);

    GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
    GXSetCurrentMtx(0);

    GXBegin(GX_POINTS, GX_VTXFMT0, 1);
    GXPosition3f32(mPosition.x, mPosition.y, mPosition.z);
    GXEnd();

    j3dSys.reinitGX();
    J3DShape::resetVcdVatCache();
}

mDoExt_circlePacket::mDoExt_circlePacket(cXyz& i_position, f32 i_radius, const GXColor& i_color, u8 i_clipZ, u8 i_lineWidth) {
    mPosition = i_position;
    mRadius = i_radius;
    mColor = i_color;
    mClipZ = i_clipZ;
    mLineWidth = i_lineWidth;
}

void mDoExt_circlePacket::draw() {
    GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
    GXClearVtxDesc();
    GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_NONE);
    GXSetClipMode(GX_CLIP_ENABLE);
    GXSetLineWidth(mLineWidth, GX_TO_ZERO);
    GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
    GXSetCurrentMtx(0);

    cXyz sp38;
    cXyz sp44;
    int numEdges = 36;
    sp38.y = sp44.y = mPosition.y;
    
    GXBegin(GX_LINES, GX_VTXFMT0, numEdges * 2);
    for (int i = 0; i < numEdges; i++) {
        sp38.x = cM_fcos((i * 6.2831855f) / numEdges) * mRadius;
        sp38.z = cM_fsin((i * 6.2831855f) / numEdges) * mRadius;

        sp44.x = cM_fcos(((i + 1) * 6.2831855f) / numEdges) * mRadius;
        sp44.z = cM_fsin(((i + 1) * 6.2831855f) / numEdges) * mRadius;

        sp38.x += mPosition.x;
        sp38.z += mPosition.z;
        sp44.x += mPosition.x;
        sp44.z += mPosition.z;
        GXPosition3f32(sp38.x, sp38.y, sp38.z);
        GXPosition3f32(sp44.x, sp44.y, sp44.z);
    }
    GXEnd();
}

mDoExt_spherePacket::mDoExt_spherePacket(cXyz& i_position, f32 i_size, const GXColor& i_color, u8 i_clipZ) {
    mPosition = i_position;
    mSize = i_size;
    mColor = i_color;
    mClipZ = i_clipZ;
}

void mDoExt_spherePacket::draw() {
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_C0, GX_CC_ZERO);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_BACK);
    GXSetClipMode(GX_CLIP_ENABLE);

    mDoMtx_stack_c::copy(j3dSys.getViewMtx());
    mDoMtx_stack_c::transM(mPosition.x, mPosition.y, mPosition.z);
    mDoMtx_stack_c::scaleM(mSize, mSize, mSize);

    GXLoadPosMtxImm(mDoMtx_stack_c::get(), 0);
    mDoMtx_stack_c::inverseTranspose();

    GXLoadNrmMtxImm(mDoMtx_stack_c::get(), 0);
    GXSetCurrentMtx(0);

    GXDrawSphere(8, 8);
}

mDoExt_cylinderPacket::mDoExt_cylinderPacket(cXyz& i_position, f32 i_radius, f32 i_height, const GXColor& i_color, u8 i_clipZ) {
    mPosition = i_position;
    mRadius = i_radius;
    mHeight = i_height;
    mColor = i_color;
    mClipZ = i_clipZ;
}

void mDoExt_cylinderPacket::draw() {
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, 1, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_C0, GX_CC_ZERO);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_BACK);
    GXSetClipMode(GX_CLIP_ENABLE);

    f32 var_f31 = mHeight * 0.5f;

    mDoMtx_stack_c::copy(j3dSys.getViewMtx());
    mDoMtx_stack_c::transM(mPosition.x, mPosition.y + var_f31, mPosition.z);
    mDoMtx_stack_c::scaleM(mRadius, var_f31, mRadius);
    mDoMtx_stack_c::XrotM(0x4000);

    GXLoadPosMtxImm(mDoMtx_stack_c::get(), 0);
    mDoMtx_stack_c::inverseTranspose();

    GXLoadNrmMtxImm(mDoMtx_stack_c::get(), 0);
    GXSetCurrentMtx(0);
    GXDrawCylinder(8);
}

mDoExt_cylinderMPacket::mDoExt_cylinderMPacket(Mtx i_mtx, const GXColor& i_color, u8 i_clipZ) {
    cMtx_copy(i_mtx, mMatrix);
    mColor = i_color;
    mClipZ = i_clipZ;
}

void mDoExt_cylinderMPacket::draw() {
    GXSetNumChans(1);
    GXSetChanCtrl(GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_NONE);
    GXSetNumTexGens(0);
    GXSetNumTevStages(1);
    GXSetTevColor(GX_TEVREG0, mColor);
    GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
    GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_C0, GX_CC_ZERO);
    GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);
    GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_A0);
    GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV);

    if (mClipZ) {
        GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
    } else {
        GXSetZMode(GX_DISABLE, GX_LEQUAL, GX_DISABLE);
    }

    GXSetBlendMode(GX_BM_BLEND, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
    GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
    GXSetCullMode(GX_CULL_BACK);
    GXSetClipMode(GX_CLIP_ENABLE);

    cMtx_concat(j3dSys.getViewMtx(), mMatrix, mMatrix);

    GXLoadPosMtxImm(mMatrix, 0);
    cMtx_inverseTranspose(mMatrix, mMatrix);

    GXLoadNrmMtxImm(mMatrix, 0);
    GXSetCurrentMtx(0);

    GXDrawCylinder(8);
}
#endif

/* 800165E4-8001683C       .text mDoExt_initFontCommon__FPP7JUTFontPP7ResFONTP7JKRHeapPCcP10JKRArchiveUcUlUl */
void mDoExt_initFontCommon(JUTFont** p_font, ResFONT** p_resfont, JKRHeap* p_heap, const char* param_4,
                           JKRArchive* p_archive, u8 param_6, u32 param_7, u32 param_8) {
    JUTFont* mDoExt_font = *p_font;
    JUT_ASSERT(VERSION_SELECT(6541, 6634, 6648, 6648), mDoExt_font == NULL);
    ResFONT* mDoExt_resfont = *p_resfont;
    JUT_ASSERT(VERSION_SELECT(6542, 6635, 6649, 6649), mDoExt_resfont == NULL);
    
    *p_resfont = (ResFONT*)p_archive->getGlbResource('ROOT', param_4, p_archive);
    mDoExt_resfont = *p_resfont;
    JUT_ASSERT(VERSION_SELECT(6544, 6637, 6651, 6651), mDoExt_resfont != NULL);
    
    if (param_6 == 0) {
#if VERSION <= VERSION_JPN
        u32 temp = (param_8 + 0x40) * param_7;
#else
        u32 temp = (((param_8+0x1F) & ~0x1F) + 0x40) * param_7;
#endif
        JUTCacheFont* cacheFont = new(p_heap, 0) JUTCacheFont(*p_resfont, temp, p_heap);
        if (cacheFont->isValid()) {
            *p_font = cacheFont;
        }
        JKRFileLoader::removeResource(*p_resfont, NULL);
        *p_resfont = NULL;
    } else {
        JUTResFont* resFont = new JUTResFont(*p_resfont, p_heap);
        *p_font = resFont;
    }
    
    if (*p_font && !(*p_font)->isValid()) {
        // "\nFailed to create cache font class\n"
        OSReport_FatalError("\nキャッシュフォントクラス作成に失敗しました\n");
        delete *p_font;
        *p_font = NULL;
    }
    
    mDoExt_font = *p_font;
    JUT_ASSERT(VERSION_SELECT(6575, 6668, 6685, 6685), mDoExt_font != NULL);
}

#if VERSION == VERSION_DEMO
JUTFont* mDoExt_font0;
JUTFont* mDoExt_font1;
s32 mDoExt_font0_getCount;
s32 mDoExt_font1_getCount;
ResFONT* mDoExt_resfont0;
ResFONT* mDoExt_resfont1;
#else
JUTFont* mDoExt_font0;
s32 mDoExt_font0_getCount;
ResFONT* mDoExt_resfont0;
JUTFont* mDoExt_font1;
s32 mDoExt_font1_getCount;
ResFONT* mDoExt_resfont1;
#endif

#if VERSION <= VERSION_JPN
void mDoExt_initFont0() {
    static const char* const fontdata[] = {
        "rock_24_20_4i1.bfn",
        "rock_e_24_20_4i.bfn",
    };
    const u8 r30 = g_msgDHIO.field_0x08;
    mDoExt_initFontCommon(&mDoExt_font0, &mDoExt_resfont0, mDoExt_getZeldaHeap(), fontdata[r30], dComIfGp_getFontArchive(), r30, 0xB4, 0x800);
}
#else
/* 80016884-800168E0       .text mDoExt_initFont0__Fv */
void mDoExt_initFont0() {
    static const char fontdata[] = "rock_24_20_4i_usa.bfn";
    mDoExt_initFontCommon(&mDoExt_font0, &mDoExt_resfont0, mDoExt_getZeldaHeap(), fontdata, dComIfGp_getFontArchive(), 1, 0, 0);
}
#endif

#if VERSION <= VERSION_JPN
void mDoExt_initFont1() {
    mDoExt_initFontCommon(&mDoExt_font1, &mDoExt_resfont1, mDoExt_getZeldaHeap(), "rodb_16_11_4i.bfn", dComIfGp_getRubyArchive(), 1, 1, 0x8000);
}
#endif

/* 800168E0-8001691C       .text mDoExt_getMesgFont__Fv */
JUTFont* mDoExt_getMesgFont() {
    if (!mDoExt_font0) {
        mDoExt_initFont0();
    }
    mDoExt_font0_getCount++;
    return mDoExt_font0;
}

#if VERSION <= VERSION_JPN
JUTFont* mDoExt_getRubyFont() {
    if (!mDoExt_font1) {
        mDoExt_initFont1();
    }
    mDoExt_font1_getCount++;
    return mDoExt_font1;
}
#endif

/* 8001691C-80016A1C       .text mDoExt_removeMesgFont__Fv */
void mDoExt_removeMesgFont() {
    JUT_ASSERT(VERSION_SELECT(6632, 6725, 6736, 6736), mDoExt_font0_getCount > 0);
    
    if (mDoExt_font0_getCount > 0) {
        mDoExt_font0_getCount--;
        JUT_ASSERT(VERSION_SELECT(6635, 6728, 6739, 6739), mDoExt_font0_getCount > 0);
        
        if (mDoExt_font0_getCount == 0) {
            delete mDoExt_font0;
            mDoExt_font0 = NULL;
            
            if (mDoExt_resfont0) {
#if VERSION <= VERSION_JPN
                if (g_msgDHIO.field_0x08 == 0) {
                    JKRFileLoader::removeResource(mDoExt_resfont0, NULL);
                } else
#endif
                {
                    JKRHeap::free(mDoExt_resfont0, NULL);
                }
                mDoExt_resfont0 = NULL;
            }
        }
    }
}

#if VERSION > VERSION_JPN
/* 80016A1C-80016A7C       .text mDoExt_initFont1__Fv */
void mDoExt_initFont1() {
#if VERSION <= VERSION_JPN
    mDoExt_initFontCommon(&mDoExt_font1, &mDoExt_resfont1, mDoExt_getZeldaHeap(), "rodb_16_11_4i.bfn", dComIfGp_getRubyArchive(), 1, 1, 0x8000);
#else
    static const char fontdata[] = "hyrule.bfn";
    mDoExt_initFontCommon(&mDoExt_font1, &mDoExt_resfont1, mDoExt_getZeldaHeap(), fontdata, dComIfGp_getRubyArchive(), 1, 1, 0x8000);
#endif
}
#endif

#if VERSION > VERSION_JPN
/* 80016A7C-80016AB8       .text mDoExt_getRubyFont__Fv */
JUTFont* mDoExt_getRubyFont() {
    if (!mDoExt_font1) {
        mDoExt_initFont1();
    }
    mDoExt_font1_getCount++;
    return mDoExt_font1;
}
#endif

/* 80016AB8-80016BB8       .text mDoExt_removeRubyFont__Fv */
void mDoExt_removeRubyFont() {
    JUT_ASSERT(VERSION_SELECT(6655, 6748, 6790, 6790), mDoExt_font1_getCount > 0);
    
    if (mDoExt_font1_getCount > 0) {
        mDoExt_font1_getCount--;
        JUT_ASSERT(VERSION_SELECT(6658, 6751, 6793, 6793), mDoExt_font1_getCount > 0);
        
        if (mDoExt_font1_getCount == 0) {
            delete mDoExt_font1;
            mDoExt_font1 = NULL;
            
            if (mDoExt_resfont1) {
                JKRHeap::free(mDoExt_resfont1, NULL);
                mDoExt_resfont1 = NULL;
            }
        }
    }
}

/* 80016BB8-80016C98       .text mDoExt_J3DModel__create__FP12J3DModelDataUlUl */
J3DModel* mDoExt_J3DModel__create(J3DModelData* i_modelData, u32 i_modelFlag, u32 i_differedDlistFlag) {
    J3DModel* model = new J3DModel();
    if (model) {
        BOOL isDisplayList = i_modelData->getModelDataType() == 1;
        if (isDisplayList && i_modelFlag == 0) {
            if (i_modelData->isLocked()) {
                i_modelFlag = 0x20000;
            } else {
                i_modelFlag = 0x80000;
            }
        }
        
        int ret = model->entryModelData(i_modelData, i_modelFlag, 1);
        if (ret == J3DErrType_Success) {
            if (i_modelFlag == 0x80000) {
                if (i_differedDlistFlag & 0x2) {
                    i_differedDlistFlag |= 0x20;
                }
                
                ret = model->newDifferedDisplayList(i_differedDlistFlag);
                if (ret != J3DErrType_Success) {
                    return NULL;
                }
            }
            
            return model;
        }
    }
    return NULL;
}
