Files
ss/src/m/m3d/m_shadow.cpp
T
2026-05-07 19:53:30 +02:00

642 lines
20 KiB
C++

#include "m/m3d/m_shadow.h"
#include "c/c_math.h"
#include "m/m_mtx.h"
#include "m/m_quat.h"
#include "m/m_vec.h"
#include "nw4r/g3d/g3d_calcview.h"
#include "nw4r/g3d/g3d_draw.h"
#include "nw4r/g3d/g3d_draw1mat1shp.h"
#include "nw4r/g3d/g3d_scnmdl.h"
#include "nw4r/g3d/g3d_scnmdlsmpl.h"
#include "nw4r/g3d/g3d_state.h"
#include "nw4r/g3d/res/g3d_resmat.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "nw4r/g3d/res/g3d_resshp.h"
// All of this is completely made up, as we don't have symbols for this TU
// (contrary to the rest of m3d and most of nw4r::g3d)
#define FRM_HEAP_STATE 'tag0'
namespace m3d {
mShadow_c *mShadow_c::sInstance;
GXTexObj *mShadow_c::sTexObj;
nw4r::g3d::ResShp mShadow_c::sResShp;
mShadow_c::~mShadow_c() {
remove();
}
void mShadow_c::drawOpa() {
if (field_0x66) {
beforeDraw();
mShadowChild_c *child = static_cast<mShadowChild_c *>(nw4r::ut::List_GetFirst(&mList));
while (child != nullptr) {
child->draw();
child = static_cast<mShadowChild_c *>(nw4r::ut::List_GetNext(&mList, child));
}
afterDraw();
}
}
void mShadow_c::create(
int count, u8 unk1, int unk2, u16 texSize, u32 drawOpaPriority, nw4r::g3d::ResMdl mdl, u32 heapSize
) {
// Regswaps
mAllocator.attach(mpHeap, 0x20);
proc_c::create(&mAllocator, nullptr);
u32 bufSize = GXGetTexBufferSize(texSize, texSize, GX_TF_RGB565, false, 0);
mTexBufferSize = bufSize;
u32 numTexBuffers = (unk2 + 2) / 3;
mpTexBuf = mpHeap->alloc(bufSize * numTexBuffers, 0x20);
// Maybe an Inline?
EGG::FrmHeap **heap = mpFrmHeaps;
for (int i = 0; i < 2; i++) {
heap[0] = mHeap::createFrmHeap(heapSize, mpHeap, "ShadowTmp", 0x4, mHeap::OPT_NONE);
heap[0]->recordState(FRM_HEAP_STATE);
heap++;
}
swapHeaps();
mShadowChild_c *childs = new (mpHeap, 0x04) mShadowChild_c[count];
mpChilds = childs;
for (int i = 0; i < count; i++) {
childs->create(unk1, mpHeap);
childs++;
}
setPriorityDraw(drawOpaPriority, 0);
setOption(/* DISABLE_DRAW_XLU */ 0x07, 1);
mChildCount = count;
mFreeChildIdx = 0;
mNumTexBuffers = numTexBuffers * 3;
mFreeTexIdx = 0;
mTexSize = texSize;
nw4r::g3d::ResMat mat = mdl.GetResMat(0);
sResShp = mdl.GetResShp(0);
sTexObj = mat.GetResTexObj().GetTexObj(GX_TEXMAP0);
}
void mShadow_c::remove() {
if (mpHeap != nullptr) {
if (mpChilds != nullptr) {
delete[] mpChilds;
mpChilds = nullptr;
}
EGG::FrmHeap **heap = mpFrmHeaps;
for (int i = 0; i < 2; i++) {
if (heap[i] != nullptr) {
mHeap::destroyFrmHeap(heap[i]);
heap[i] = nullptr;
}
}
if (mpTexBuf != nullptr) {
mpHeap->free(mpTexBuf);
mpTexBuf = nullptr;
}
scnLeaf_c::remove();
mpHeap = nullptr;
}
}
void mShadow_c::reset() {
mShadowChild_c *iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetFirst(&mList));
while (iter != nullptr) {
iter->mNumLeaves = 0;
mShadowCircle_c *circle = iter->mpCircle;
iter->mpCircle = nullptr;
circle->mpChild = nullptr;
iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetNext(&mList, iter));
}
mFreeChildIdx = 0;
mFreeTexIdx = 0;
nw4r::ut::List_Init(&mList, 0);
swapHeaps();
}
bool mShadow_c::addCircle(mShadowCircle_c *circle, u32 priority, u32 isMdl) {
if (circle->mpChild != nullptr) {
// Already linked, OK
return true;
}
mShadowChild_c *childPtr;
if (mFreeChildIdx < mChildCount && (!isMdl || mFreeTexIdx < mNumTexBuffers)) {
// There are free entries in our buffer, so just add a new child
childPtr = &mpChilds[mFreeChildIdx];
if (mFreeChildIdx++ == 0) {
entry();
}
if (isMdl) {
mFreeTexIdx++;
}
} else {
// There are no free entries in our buffer, so replace an existing entry?
childPtr = static_cast<mShadowChild_c *>(nw4r::ut::List_GetLast(&mList));
if (priority >= childPtr->mPriorityMaybe) {
return false;
}
if (isMdl) {
if (mFreeTexIdx >= mNumTexBuffers) {
while (childPtr->mNumLeaves == 0) {
childPtr = static_cast<mShadowChild_c *>(nw4r::ut::List_GetPrev(&mList, childPtr));
if (priority >= childPtr->mPriorityMaybe) {
return false;
}
}
} else {
mFreeTexIdx++;
}
}
childPtr->mNumLeaves = 0;
childPtr->mpCircle->mpChild = nullptr;
nw4r::ut::List_Remove(&mList, childPtr);
}
circle->mpChild = childPtr;
childPtr->mpCircle = circle;
childPtr->mPriorityMaybe = priority;
mShadowChild_c *iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetFirst(&mList));
if (iter == nullptr) {
nw4r::ut::List_Append(&mList, childPtr);
return true;
} else {
do {
if (childPtr->mPriorityMaybe < iter->mPriorityMaybe) {
nw4r::ut::List_Insert(&mList, iter, childPtr);
return true;
}
iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetNext(&mList, iter));
} while (iter != nullptr);
nw4r::ut::List_Append(&mList, childPtr);
}
return true;
}
bool mShadow_c::drawMdl(
mShadowCircle_c *circle, u32 priority, scnLeaf_c &mdl, const mQuat_c &quat, mVec3_c &pos, mColor color, u32 param9,
f32 dist
) {
if (!addCircle(circle, priority, 1)) {
return false;
}
mShadowChild_c *child = circle->mpChild;
child->set(pos, dist, color);
child->set0x154(param9);
return child->addMdl(mdl, quat);
}
bool mShadow_c::addMdlToCircle(mShadowCircle_c *circle, scnLeaf_c &mdl, const mQuat_c &quat) {
if (circle->mpChild == nullptr) {
return false;
}
return circle->mpChild->addMdl(mdl, quat);
}
void mShadow_c::removeCircle(mShadowCircle_c *circle) {
mShadowChild_c *child = circle->mpChild;
if (child == nullptr) {
return;
}
circle->mpChild = nullptr;
child->mpCircle = nullptr;
nw4r::ut::List_Remove(&mList, child);
}
static f32 sTexMtx[2][4] = {
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f}
};
static u32 STEP = 0x2492;
static GXColor sColors[] = {
{0xFF, 0x00, 0x00, 0x00},
{0x00, 0xFF, 0x00, 0x00},
{0x00, 0x00, 0xFF, 0x00},
{0x00, 0x00, 0x00, 0x00},
};
bool mShadow_c::drawTexObj(
mShadowCircle_c *circle, u32 priority, const GXTexObj *texObj, const mMtx_c &mtx, const mQuat_c &quat, mVec3_c &pos,
mColor color, u32 param9, f32 dist
) {
if (!addCircle(circle, priority, 0)) {
return false;
}
mShadowChild_c *child = circle->mpChild;
child->set(pos, dist, color);
child->set0x154(param9);
return child->setGeom(texObj, mtx, quat);
}
static void drawSub2(void *data, u8 i) {
s16 ang;
u32 wid = i * 2;
GXSetTexCopySrc(0, 0, wid, wid);
GXSetTexCopyDst(i, i, GX_TF_RGB565, 1);
GXCopyTex(data, false);
GXPixModeSync();
GXInvalidateTexAll();
GXTexObj obj;
GXInitTexObj(&obj, data, i, i, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, 0);
GXInitTexObjLOD(&obj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
GXLoadTexObj(&obj, GX_TEXMAP0);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBX8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0);
GXSetNumChans(0);
GXSetNumTexGens(8);
GXSetNumTevStages(8);
GXSetTevColor(GX_TEVREG1, nw4r::ut::Color(0, 0, 0, 0x20));
ang = 0;
for (int id = GX_TEXCOORD0, idx = GX_TEXMTX0; id < GX_MAX_TEXCOORD;
id += 1, idx += (GX_TEXMTX1 - GX_TEXMTX0), ang += STEP) {
GXSetTexCoordGen2((GXTexCoordID)id, GX_TG_MTX2x4, GX_TG_TEX0, idx, FALSE, GX_DUALMTX_IDENT);
sTexMtx[0][3] = 0.01f * nw4r::math::CosIdx(ang);
sTexMtx[1][3] = 0.01f * nw4r::math::SinIdx(ang);
GXLoadTexMtxImm(sTexMtx, idx, GX_MTX2x4);
}
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A0, GX_CC_ZERO);
for (int id = GX_TEVSTAGE1; id < GX_TEVSTAGE8; id++) {
GXSetTevSwapMode((GXTevStageID)id, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevOrder((GXTevStageID)id, (GXTexCoordID)id, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn((GXTevStageID)id, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, GX_CC_CPREV);
GXSetTevColorOp((GXTevStageID)id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV);
GXSetTevAlphaIn((GXTevStageID)id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp((GXTevStageID)id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV);
}
GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_SET);
GXLoadPosMtxImm(mMtx_c::Identity, 0);
GXSetCurrentMtx(0);
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition2u16(0, 0);
GXPosition2u8(0, 0);
GXPosition2u16(wid, 0);
GXPosition2u8(1, 0);
GXPosition2u16(wid, wid);
GXPosition2u8(1, 1);
GXPosition2u16(0, wid);
GXPosition2u8(0, 1);
// GXEnd();
}
static void drawSub1(void *data, u8 i) {
Mtx44 mtx;
u16 wid = i * 2;
f32 wid2 = i * 2;
C_MTXOrtho(mtx, 0.0f, wid2, 0.0f, wid2, 0.0f, 1.0f);
GXSetProjection(mtx, GX_ORTHOGRAPHIC);
drawSub2(data, i);
GXSetNumChans(1);
GXSetNumTexGens(0);
GXSetNumTevStages(1);
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_ZERO);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXBegin(GX_LINESTRIP, GX_VTXFMT0, 5);
GXPosition2u16(0, 0);
GXPosition2u16(wid, 0);
GXPosition2u16(wid, wid);
GXPosition2u16(0, wid);
GXPosition2u16(0, 0);
// GXEnd();
GXSetZMode(true, GX_ALWAYS, true);
GXSetTexCopySrc(0, 0, wid, wid);
GXSetTexCopyDst(i, i, GX_TF_RGB565, 1);
GXCopyTex(data, true);
GXPixModeSync();
GXInvalidateTexAll();
}
void mShadow_c::drawAllShadows() {
mShadowChild_c *iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetFirst(&mList));
if (iter != nullptr) {
f32 wid = mTexSize * 2;
u16 wid2 = mTexSize * 2;
GXSetViewport(0.0f, 0.0f, wid, wid, 0.0f, 1.0f);
GXSetScissor(0, 0, wid2, wid2);
GXSetScissorBoxOffset(0, 0);
GXLoadTexObj(mShadow_c::sTexObj, GX_TEXMAP1);
GXSetNumChans(1);
GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
GXSetNumTexGens(0);
GXSetNumTevStages(1);
GXSetNumIndStages(0);
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_ZERO);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV);
GXSetZCompLoc(1);
GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_SET);
GXSetZMode(false, GX_ALWAYS, false);
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
GXColor clr = {0};
GXSetFog(GX_FOG_NONE, clr, 0.0f, 0.0f, 0.0f, 0.0f);
GXSetFogRangeAdj(0, 0, 0);
GXSetCullMode(GX_CULL_BACK);
GXSetDither(0);
GXSetClipMode(GX_CLIP_DISABLE);
GXLoadPosMtxImm(mMtx_c::Identity, 0);
GXSetCurrentMtx(0);
Mtx44 mtx;
C_MTXOrtho(mtx, 0.0f, wid, 0.0f, wid, 0.0f, 1.0f);
GXSetProjection(mtx, GX_ORTHOGRAPHIC);
GXSetLineWidth(0x18, 0);
int i = 0;
void *imgData = mpTexBuf;
do {
iter->updateMtx();
if (iter->mNumLeaves != 0) {
if (i == 0) {
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_U16, 0);
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition2u16(0, 0);
GXPosition2u16(wid2, 0);
GXPosition2u16(wid2, wid2);
GXPosition2u16(0, wid2);
// GXEnd();
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
GXSetBlendMode(GX_BM_LOGIC, GX_BL_ONE, GX_BL_ONE, GX_LO_OR);
}
iter->mColorChanIdx = i;
GXInitTexObj(&iter->mTexObj, imgData, mTexSize, mTexSize, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, false);
GXInitTexObjLOD(&iter->mTexObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
iter->drawMdl();
i = (i + 1) % 3;
if (i == 0) {
drawSub1(imgData, mTexSize);
imgData = (void *)((u8 *)imgData + mTexBufferSize);
}
}
iter = static_cast<mShadowChild_c *>(nw4r::ut::List_GetNext(&mList, iter));
} while (iter != nullptr);
if (i != 0) {
drawSub1(imgData, mTexSize);
}
GXSetClipMode(GX_CLIP_ENABLE);
GXSetDither(true);
nw4r::g3d::G3DState::Invalidate(0x7FF);
}
}
void mShadow_c::create(const mShadowCircleConfig *config, nw4r::g3d::ResMdl mdl, EGG::Heap *heap) {
mShadow_c::sInstance = new (heap, 0x04) mShadow_c(heap);
mShadow_c::GetInstance()->create(
config->count, config->unk1, config->unk2, config->texBufferSize, config->drawOpaPriority, mdl, config->heapSize
);
}
void mShadow_c::beforeDraw() {
if (mpCallback != nullptr) {
mpCallback->beforeDraw();
}
}
void mShadow_c::draw(const mMtx_c &mtx, u32 unk) {
if (mpCallback != nullptr) {
mpCallback->draw(mtx, unk);
}
}
void mShadow_c::afterDraw() {
if (mpCallback != nullptr) {
mpCallback->afterDraw();
}
}
void mShadow_c::swapHeaps() {
changeHeap(mCurrentHeapIdx + 1);
mpCurrentHeap->freeByState(FRM_HEAP_STATE);
mpCurrentHeap->recordState(FRM_HEAP_STATE);
}
void mShadow_c::destroy() {
if (mShadow_c::sInstance != nullptr) {
mShadow_c::GetInstance()->remove();
delete mShadow_c::sInstance;
mShadow_c::sInstance = nullptr;
}
}
mShadowChild_c::~mShadowChild_c() {
if (mpCircle != nullptr) {
mpCircle->mpChild = nullptr;
mpCircle = nullptr;
}
if (mpLeaves != nullptr) {
mpHeap->free(mpLeaves);
mpLeaves = nullptr;
}
}
bool mShadowChild_c::create(u8 maxNum, EGG::Heap *heap) {
if ((mpLeaves = static_cast<scnLeaf_c **>(heap->alloc(maxNum * sizeof(scnLeaf_c *), 0x04))) == nullptr) {
return false;
}
mpHeap = heap;
mMaxNumLeaves = maxNum;
return true;
}
void mShadowChild_c::set(const mVec3_c &pos, f32 dist, mColor color) {
mPositionMaybe = pos;
mOffsetMaybe = dist;
mShadowColor = color;
}
bool mShadowChild_c::addMdl(scnLeaf_c &mdl, const mQuat_c &quat) {
if (!(mNumLeaves < mMaxNumLeaves)) {
return false;
}
mMtx_c mtx;
if (mdl.getType() == 0) {
mdl.getLocalMtx(mtx);
} else {
mtx.copyFrom(static_cast<mCustomShadow_c &>(mdl).mMtx);
}
mQuat_c q = quat;
mtx.applyQuat(q);
if (mNumLeaves == 0) {
mQuat = q;
} else {
mQuat.fn_802F2780(q);
}
mpLeaves[mNumLeaves++] = &mdl;
return true;
}
bool mShadowChild_c::setGeom(const GXTexObj *texObj, const mMtx_c &mtx, const mQuat_c &quat) {
mQuat = quat;
MTXMultVec(mtx.m, mQuat.v, mQuat.v);
if (texObj == nullptr) {
mTexObj = *mShadow_c::sTexObj;
} else {
mTexObj = *texObj;
}
return true;
}
void mShadowChild_c::updateMtx() {
// NONMATCHING
field_0x13C = mQuat.w;
mVec3_c a(mQuat.v.x, mQuat.v.y, mQuat.v.z);
a += mPositionMaybe * GetOffset();
mVec3_c b(mQuat.v.x, mQuat.v.y, mQuat.v.z);
b -= mPositionMaybe * field_0x13C;
const mVec3_c *up;
if (cM::isZero((a - b).squareMagXZ())) {
up = &mVec3_c::Ez;
} else {
up = &mVec3_c::Ey;
}
mMtx_c mtx;
C_MTXLookAt(mtx.m, a, *up, b);
f32 f = field_0x13C;
mFrustum.set(f, -f, -f, f, f, f + GetOffset(), mtx, true);
}
void mShadowChild_c::drawMdl() {
using namespace nw4r;
Mtx44 mtx;
GXSetTevColor(GX_TEVREG0, sColors[mColorChanIdx]);
C_MTXOrtho(mtx, field_0x13C, -field_0x13C, -field_0x13C, field_0x13C, 0.0f, 100.0f + (-mFrustum.mFar));
GXSetProjection(mtx, GX_ORTHOGRAPHIC);
g3d::G3DState::Invalidate(0x7FF);
mMtx_c &viewMtx = mFrustum.mView;
for (scnLeaf_c **leaf = &mpLeaves[mNumLeaves - 1]; leaf >= &mpLeaves[0]; leaf--) {
if ((*leaf)->getType() == 0 /* Model */) {
g3d::ScnMdlSimple *mdl = g3d::G3dObj::DynamicCast<g3d::ScnMdlSimple>((*leaf)->getG3dObject());
u32 bufSize = mdl->GetNumViewMtx() * sizeof(math::MTX34);
math::MTX34 *viewPosArray =
static_cast<math::MTX34 *>(mShadow_c::GetInstance()->mpCurrentHeap->alloc(bufSize, 0x20));
g3d::ResMdl resMdl = mdl->GetResMdl();
g3d::CalcView(
viewPosArray, nullptr, mdl->GetWldMtxArray(), mdl->GetWldMtxAttribArray(), mdl->GetNumViewMtx(),
viewMtx, resMdl, nullptr
);
DCStoreRange(viewPosArray, bufSize);
g3d::ScnMdl *mdl2 = g3d::G3dObj::DynamicCast<g3d::ScnMdl>((*leaf)->getG3dObject());
g3d::DrawResMdlReplacement *pRep = mdl2 ? &mdl2->GetDrawResMdlReplacement() : nullptr;
g3d::DrawResMdlDirectly(
resMdl, viewPosArray, nullptr, nullptr, mdl->GetByteCode(g3d::ScnMdlSimple::BYTE_CODE_DRAW_OPA),
nullptr, pRep, g3d::RESMDL_DRAWMODE_FORCE_LIGHTOFF | g3d::RESMDL_DRAWMODE_IGNORE_MATERIAL
);
GXInvalidateVtxCache();
} else {
// this happens with bomb bag, and goes to 0x802EDC90 (mCustomShadow_c::draw)
static_cast<mCustomShadow_c *>(*leaf)->draw(viewMtx);
}
}
}
static GXTevColorChan sChans[] = {GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA};
void mShadowChild_c::draw() {
if (mNumLeaves != 0) {
GXTevColorChan chan = sChans[mColorChanIdx];
GXSetTevSwapModeTable(GX_TEV_SWAP0, chan, chan, chan, chan);
} else {
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
}
GXLoadTexObj(&mTexObj, GX_TEXMAP0);
GXSetTevColor(GX_TEVREG0, mShadowColor);
Mtx mtx;
C_MTXLightOrtho(mtx, field_0x13C, -field_0x13C, -field_0x13C, field_0x13C, 0.5f, -0.5f, 0.5f, 0.5f);
MTXConcat(mtx, mFrustum.mView.m, mtx);
GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX3x4);
mShadow_c::GetInstance()->draw(mFrustum.mView, field_0x154);
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
}
mShadowCircle_c::~mShadowCircle_c() {
mShadow_c::GetInstance()->removeCircle(this);
}
mCustomShadow_c::~mCustomShadow_c() {}
int mCustomShadow_c::getType() const {
return 0x2;
}
void mCustomShadow_c::draw(const mMtx_c &arg) {
nw4r::g3d::G3DState::Invalidate(0x7FF);
GXSetNumTexGens(1);
GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C, false, 0x7D);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_C0, GX_CC_TEXC, GX_CC_ZERO);
mMtx_c result;
calc(arg, result);
static nw4r::g3d::ResMat nullMat(nullptr);
nw4r::g3d::Draw1Mat1ShpDirectly(nullMat, mShadow_c::sResShp, result, result, 0x18, nullptr, nullptr);
GXSetNumTexGens(0);
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);
}
void mCustomShadow_c::calc(mMtx_c mtx, mMtx_c &mtx2) const {
mVec3_c trans;
mtx2.copyFrom(mMtx);
mVec3_c offset(0.0f, field_0x48, 0.0f);
MTXMultVec(mtx2, offset, trans);
MTXMultVec(mtx, trans, trans);
MTXTrans(mtx2, trans.x, trans.y, trans.z);
mMtx_c scaleMtx;
MTXScale(scaleMtx, field_0x4C, field_0x4C, field_0x4C);
MTXConcat(mtx2, scaleMtx, mtx2);
}
} // namespace m3d