mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-31 00:45:24 -04:00
230868af3c
Resolves #627
886 lines
34 KiB
C++
886 lines
34 KiB
C++
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
|
|
|
#include "JSystem/J3DGraphAnimator/J3DAnimation.h"
|
|
#include "JSystem/J3DGraphAnimator/J3DJoint.h"
|
|
#include "JSystem/J3DGraphAnimator/J3DJointTree.h"
|
|
#include "JSystem/J3DGraphAnimator/J3DModelData.h"
|
|
#include "JSystem/J3DGraphAnimator/J3DShapeTable.h"
|
|
#include "JSystem/J3DGraphBase/J3DMaterial.h"
|
|
#include "JSystem/J3DGraphLoader/J3DJointFactory.h"
|
|
#include "JSystem/J3DGraphLoader/J3DMaterialFactory.h"
|
|
#include "JSystem/J3DGraphLoader/J3DMaterialFactory_v21.h"
|
|
#include "JSystem/J3DGraphLoader/J3DModelLoader.h"
|
|
#include "JSystem/J3DGraphLoader/J3DShapeFactory.h"
|
|
#include "JSystem/JKernel/JKRHeap.h"
|
|
#include "JSystem/JSupport/JSupport.h"
|
|
#include "JSystem/JUtility/JUTNameTab.h"
|
|
#include "SSystem/SComponent/c_xyz.h"
|
|
#include <utility>
|
|
|
|
#if TARGET_PC
|
|
static void AssignMaterialNames(const J3DModelLoader& loader) {
|
|
auto table = loader.mpMaterialTable;
|
|
auto materialName = table->getMaterialName();
|
|
for (int i = 0; i < table->getMaterialNum(); i++) {
|
|
auto mat = table->getMaterialNodePointer(i);
|
|
mat->mMaterialName = materialName->getName(i);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
J3DModelLoader::J3DModelLoader() :
|
|
mpModelData(NULL),
|
|
mpMaterialTable(NULL),
|
|
mpShapeBlock(NULL),
|
|
mpMaterialBlock(NULL),
|
|
mpModelHierarchy(NULL),
|
|
field_0x18(0),
|
|
mEnvelopeSize(0) {
|
|
/* empty function */
|
|
}
|
|
|
|
J3DModelData* J3DModelLoaderDataBase::load(void const* i_data, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(52, i_data);
|
|
const J3DModelFileData* header = (const J3DModelFileData*)i_data;
|
|
if (i_data == NULL) {
|
|
return NULL;
|
|
}
|
|
if (header->mMagic1 == 'J3D1' && header->mMagic2 == 'bmd1') {
|
|
JUT_PANIC(64, "Error : version error.");
|
|
return NULL;
|
|
}
|
|
if (header->mMagic1 == 'J3D2' && header->mMagic2 == 'bmd2') {
|
|
J3DModelLoader_v21 loader;
|
|
return loader.load(i_data, i_flags);
|
|
}
|
|
if (header->mMagic1 == 'J3D2' && header->mMagic2 == 'bmd3') {
|
|
J3DModelLoader_v26 loader;
|
|
return loader.load(i_data, i_flags);
|
|
}
|
|
JUT_PANIC(89, "Error : version error.");
|
|
return NULL;
|
|
}
|
|
|
|
J3DModelData* J3DModelLoaderDataBase::loadBinaryDisplayList(const void* i_data, u32 flags) {
|
|
J3D_ASSERT_NULLPTR(138, i_data);
|
|
const J3DModelFileData* header = (const J3DModelFileData*)i_data;
|
|
if (!i_data) {
|
|
return NULL;
|
|
}
|
|
if (header->mMagic1 == 'J3D2' && (header->mMagic2 == 'bdl3' || header->mMagic2 == 'bdl4')) {
|
|
J3DModelLoader_v26 loader;
|
|
return loader.loadBinaryDisplayList(i_data, flags);
|
|
}
|
|
JUT_PANIC(157, "Error : version error.");
|
|
return NULL;
|
|
}
|
|
|
|
J3DModelData* J3DModelLoader::load(void const* i_data, u32 i_flags) {
|
|
s32 freeSize = JKRGetCurrentHeap()->getTotalFreeSize();
|
|
mpModelData = JKR_NEW J3DModelData();
|
|
J3D_ASSERT_ALLOCMEM(177, mpModelData);
|
|
mpModelData->clear();
|
|
mpModelData->mpRawData = i_data;
|
|
mpModelData->setModelDataType(0);
|
|
mpMaterialTable = &mpModelData->mMaterialTable;
|
|
J3DModelFileData const* data = (J3DModelFileData*)i_data;
|
|
J3DModelBlock const* block = data->mBlocks;
|
|
for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) {
|
|
switch (block->mBlockType) {
|
|
case 'INF1':
|
|
readInformation((J3DModelInfoBlock*)block, (s32)i_flags);
|
|
break;
|
|
case 'VTX1':
|
|
readVertex((J3DVertexBlock*)block);
|
|
break;
|
|
case 'EVP1':
|
|
readEnvelop((J3DEnvelopeBlock*)block);
|
|
break;
|
|
case 'DRW1':
|
|
readDraw((J3DDrawBlock*)block);
|
|
break;
|
|
case 'JNT1':
|
|
readJoint((J3DJointBlock*)block);
|
|
break;
|
|
case 'MAT3':
|
|
readMaterial((J3DMaterialBlock*)block, (s32)i_flags);
|
|
break;
|
|
case 'MAT2':
|
|
readMaterial_v21((J3DMaterialBlock_v21*)block, (s32)i_flags);
|
|
break;
|
|
case 'SHP1':
|
|
readShape((J3DShapeBlock*)block, (s32)i_flags);
|
|
break;
|
|
case 'TEX1':
|
|
readTexture((J3DTextureBlock*)block);
|
|
break;
|
|
default:
|
|
OSReport("Unknown data block\n");
|
|
break;
|
|
}
|
|
block = (J3DModelBlock*)((uintptr_t)block + block->mBlockSize);
|
|
}
|
|
J3DModelHierarchy const* hierarchy = mpModelData->getHierarchy();
|
|
mpModelData->makeHierarchy(NULL, &hierarchy);
|
|
mpModelData->getShapeTable()->sortVcdVatCmd();
|
|
mpModelData->getJointTree().findImportantMtxIndex();
|
|
setupBBoardInfo();
|
|
if (mpModelData->getFlag() & 0x100) {
|
|
for (u16 shape_no = 0; shape_no < mpModelData->getShapeNum(); shape_no++) {
|
|
mpModelData->getShapeNodePointer(shape_no)->onFlag(0x200);
|
|
}
|
|
}
|
|
#if TARGET_PC
|
|
AssignMaterialNames(*this);
|
|
#endif
|
|
return mpModelData;
|
|
}
|
|
|
|
|
|
J3DMaterialTable* J3DModelLoader::loadMaterialTable(void const* i_data) {
|
|
int flags = 0x51100000;
|
|
mpMaterialTable = JKR_NEW J3DMaterialTable();
|
|
J3D_ASSERT_ALLOCMEM(279, mpMaterialTable);
|
|
mpMaterialTable->clear();
|
|
J3DModelFileData const* data = (J3DModelFileData*)i_data;
|
|
J3DModelBlock const* block = data->mBlocks;
|
|
for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) {
|
|
switch (block->mBlockType) {
|
|
case 'MAT3':
|
|
readMaterialTable((J3DMaterialBlock*)block, flags);
|
|
break;
|
|
case 'MAT2':
|
|
readMaterialTable_v21((J3DMaterialBlock_v21*)block, flags);
|
|
break;
|
|
case 'TEX1':
|
|
readTextureTable((J3DTextureBlock*)block);
|
|
break;
|
|
default:
|
|
OSReport("Unknown data block\n");
|
|
break;
|
|
}
|
|
block = (J3DModelBlock*)((uintptr_t)block + block->mBlockSize);
|
|
}
|
|
if (mpMaterialTable->mTexture == NULL) {
|
|
mpMaterialTable->mTexture = JKR_NEW J3DTexture(0, NULL);
|
|
J3D_ASSERT_ALLOCMEM(319, mpMaterialTable->mTexture);
|
|
}
|
|
return mpMaterialTable;
|
|
}
|
|
|
|
inline u32 getBdlFlag_MaterialType(u32 flags) {
|
|
return flags & (J3DMLF_13 | J3DMLF_DoBdlMaterialCalc);
|
|
}
|
|
|
|
J3DModelData* J3DModelLoader::loadBinaryDisplayList(void const* i_data, u32 i_flags) {
|
|
mpModelData = JKR_NEW J3DModelData();
|
|
J3D_ASSERT_ALLOCMEM(338, mpModelData);
|
|
mpModelData->clear();
|
|
mpModelData->mpRawData = i_data;
|
|
mpModelData->setModelDataType(1);
|
|
mpMaterialTable = &mpModelData->mMaterialTable;
|
|
J3DModelFileData const* data = (J3DModelFileData*)i_data;
|
|
J3DModelBlock const* block = data->mBlocks;
|
|
for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) {
|
|
s32 flags;
|
|
u32 materialType;
|
|
switch (block->mBlockType) {
|
|
case 'INF1':
|
|
flags = i_flags;
|
|
readInformation((J3DModelInfoBlock*)block, flags);
|
|
break;
|
|
case 'VTX1':
|
|
readVertex((J3DVertexBlock*)block);
|
|
break;
|
|
case 'EVP1':
|
|
readEnvelop((J3DEnvelopeBlock*)block);
|
|
break;
|
|
case 'DRW1':
|
|
readDraw((J3DDrawBlock*)block);
|
|
break;
|
|
case 'JNT1':
|
|
readJoint((J3DJointBlock*)block);
|
|
break;
|
|
case 'SHP1':
|
|
readShape((J3DShapeBlock*)block, i_flags);
|
|
break;
|
|
case 'TEX1':
|
|
readTexture((J3DTextureBlock*)block);
|
|
break;
|
|
case 'MDL3':
|
|
readMaterialDL((J3DMaterialDLBlock*)block, i_flags);
|
|
modifyMaterial(i_flags);
|
|
break;
|
|
case 'MAT3':
|
|
flags = 0x50100000;
|
|
flags |= (i_flags & 0x3000000);
|
|
mpMaterialBlock = (J3DMaterialBlock*)block;
|
|
materialType = getBdlFlag_MaterialType(i_flags);
|
|
if (materialType == 0) {
|
|
readMaterial((J3DMaterialBlock*)block, flags);
|
|
} else if (materialType == 0x2000) {
|
|
readPatchedMaterial((J3DMaterialBlock*)block, flags);
|
|
}
|
|
break;
|
|
default:
|
|
OSReport("Unknown data block\n");
|
|
break;
|
|
}
|
|
block = (J3DModelBlock*)((uintptr_t)block + block->mBlockSize);
|
|
}
|
|
J3DModelHierarchy const* hierarchy = mpModelData->getHierarchy();
|
|
mpModelData->makeHierarchy(NULL, &hierarchy);
|
|
mpModelData->getShapeTable()->sortVcdVatCmd();
|
|
mpModelData->getJointTree().findImportantMtxIndex();
|
|
setupBBoardInfo();
|
|
mpModelData->indexToPtr();
|
|
return mpModelData;
|
|
}
|
|
|
|
void J3DModelLoader::setupBBoardInfo() {
|
|
for (u16 i = 0; i < mpModelData->getJointNum(); i++) {
|
|
J3DMaterial* mesh = mpModelData->getJointNodePointer(i)->getMesh();
|
|
if (mesh != NULL) {
|
|
u32 shape_index = mesh->getShape()->getIndex();
|
|
BE(u16)* index_table = JSUConvertOffsetToPtr<BE(u16)>(mpShapeBlock,
|
|
(uintptr_t)mpShapeBlock->mpIndexTable);
|
|
J3DShapeInitData* shape_init_data =
|
|
JSUConvertOffsetToPtr<J3DShapeInitData>(mpShapeBlock,
|
|
(uintptr_t)mpShapeBlock->mpShapeInitData);
|
|
J3DShapeInitData* r26 = &shape_init_data[index_table[shape_index]];
|
|
switch (r26->mShapeMtxType) {
|
|
case 0:
|
|
mpModelData->getJointNodePointer(i)->setMtxType(0);
|
|
break;
|
|
case 1:
|
|
mpModelData->getJointNodePointer(i)->setMtxType(1);
|
|
mpModelData->mbHasBillboard = true;
|
|
break;
|
|
case 2:
|
|
mpModelData->getJointNodePointer(i)->setMtxType(2);
|
|
mpModelData->mbHasBillboard = true;
|
|
break;
|
|
case 3:
|
|
mpModelData->getJointNodePointer(i)->setMtxType(0);
|
|
break;
|
|
default:
|
|
OSReport("WRONG SHAPE MATRIX TYPE (%d)\n", r26->mShapeMtxType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readInformation(J3DModelInfoBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(506, i_block);
|
|
mpModelData->mFlags = i_flags | i_block->mFlags;
|
|
mpModelData->getJointTree().setFlag(mpModelData->mFlags);
|
|
J3DMtxCalc* mtx_calc = NULL;
|
|
switch (mpModelData->mFlags & 0xf) {
|
|
case 0:
|
|
mtx_calc = JKR_NEW J3DMtxCalcNoAnm<J3DMtxCalcCalcTransformBasic,J3DMtxCalcJ3DSysInitBasic>();
|
|
break;
|
|
case 1:
|
|
mtx_calc = JKR_NEW J3DMtxCalcNoAnm<J3DMtxCalcCalcTransformSoftimage,J3DMtxCalcJ3DSysInitSoftimage>();
|
|
break;
|
|
case 2:
|
|
mtx_calc = JKR_NEW J3DMtxCalcNoAnm<J3DMtxCalcCalcTransformMaya,J3DMtxCalcJ3DSysInitMaya>();
|
|
break;
|
|
default:
|
|
JUT_PANIC(529, "Error : Invalid MtxCalcType.");
|
|
break;
|
|
}
|
|
J3D_ASSERT_ALLOCMEM(532, mtx_calc);
|
|
mpModelData->setBasicMtxCalc(mtx_calc);
|
|
mpModelData->getVertexData().mPacketNum = i_block->mPacketNum;
|
|
mpModelData->getVertexData().mVtxNum = i_block->mVtxNum;
|
|
mpModelData->setHierarchy(JSUConvertOffsetToPtr<J3DModelHierarchy>(i_block, i_block->mpHierarchy));
|
|
|
|
#if TARGET_PC
|
|
mpModelData->getVertexData().mHasReadInformation = true;
|
|
#endif
|
|
}
|
|
|
|
#if TARGET_PC
|
|
static GXVtxAttrFmtList getFmt(GXVtxAttrFmtList* i_fmtList, GXAttr i_attr) {
|
|
for (; i_fmtList->attr != GX_VA_NULL; i_fmtList++) {
|
|
if (i_fmtList->attr == i_attr) {
|
|
return *i_fmtList;
|
|
}
|
|
}
|
|
|
|
OSPanic(__FILE__, __LINE__, "Unable to find vertex attribute format!");
|
|
}
|
|
#endif
|
|
|
|
static GXCompType getFmtType(GXVtxAttrFmtList* i_fmtList, GXAttr i_attr) {
|
|
for (; i_fmtList->attr != GX_VA_NULL; i_fmtList++) {
|
|
if (i_fmtList->attr == i_attr) {
|
|
return i_fmtList->type;
|
|
}
|
|
}
|
|
return GX_F32;
|
|
}
|
|
|
|
void J3DModelLoader::readVertex(J3DVertexBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(577, i_block);
|
|
J3DVertexData& vertex_data = mpModelData->getVertexData();
|
|
vertex_data.mVtxAttrFmtList =
|
|
JSUConvertOffsetToPtr<GXVtxAttrFmtList>(i_block, i_block->mpVtxAttrFmtList);
|
|
vertex_data.mVtxPosArray = JSUConvertOffsetToPtr<void>(i_block, i_block->mpVtxPosArray);
|
|
vertex_data.mVtxNrmArray = JSUConvertOffsetToPtr<void>(i_block, i_block->mpVtxNrmArray);
|
|
vertex_data.mVtxNBTArray = JSUConvertOffsetToPtr<void>(i_block, i_block->mpVtxNBTArray);
|
|
for (int i = 0; i < 2; i++) {
|
|
vertex_data.mVtxColorArray[i] =
|
|
(GXColor*)JSUConvertOffsetToPtr<void>(i_block, i_block->mpVtxColorArray[i]);
|
|
}
|
|
for (int i = 0; i < 8; i++) {
|
|
vertex_data.mVtxTexCoordArray[i] =
|
|
JSUConvertOffsetToPtr<void>(i_block, i_block->mpVtxTexCoordArray[i]);
|
|
}
|
|
|
|
#if TARGET_LITTLE_ENDIAN
|
|
for (GXVtxAttrFmtList* attrFmt = vertex_data.mVtxAttrFmtList;; attrFmt++) {
|
|
*attrFmt = BE<GXVtxAttrFmtList>::swap(*attrFmt);
|
|
|
|
if (attrFmt->attr == GX_VA_NULL) {
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
u32 nrm_size = 12;
|
|
if (getFmtType(vertex_data.mVtxAttrFmtList, GX_VA_NRM) == GX_F32) {
|
|
nrm_size = 12;
|
|
} else {
|
|
nrm_size = 6;
|
|
}
|
|
|
|
void* nrm_end = NULL;
|
|
if (vertex_data.mVtxNBTArray != NULL) {
|
|
nrm_end = vertex_data.mVtxNBTArray;
|
|
} else if (vertex_data.mVtxColorArray[0] != NULL) {
|
|
nrm_end = vertex_data.mVtxColorArray[0];
|
|
} else if (vertex_data.mVtxTexCoordArray[0] != NULL) {
|
|
nrm_end = vertex_data.mVtxTexCoordArray[0];
|
|
}
|
|
|
|
if (vertex_data.mVtxNrmArray == NULL) {
|
|
vertex_data.mNrmNum = 0;
|
|
} else if (nrm_end != NULL) {
|
|
vertex_data.mNrmNum =
|
|
((uintptr_t)nrm_end - (uintptr_t)vertex_data.mVtxNrmArray) / nrm_size + 1;
|
|
} else {
|
|
vertex_data.mNrmNum =
|
|
(i_block->mBlockSize - (uintptr_t)i_block->mpVtxNrmArray) / nrm_size + 1;
|
|
}
|
|
|
|
void* color0_end = NULL;
|
|
if (vertex_data.mVtxColorArray[1] != NULL) {
|
|
color0_end = vertex_data.mVtxColorArray[1];
|
|
} else if (vertex_data.mVtxTexCoordArray[0] != NULL) {
|
|
color0_end = vertex_data.mVtxTexCoordArray[0];
|
|
}
|
|
|
|
if (vertex_data.mVtxColorArray[0] == NULL) {
|
|
vertex_data.mColNum = 0;
|
|
} else if (color0_end != NULL) {
|
|
vertex_data.mColNum =
|
|
((uintptr_t)color0_end - (uintptr_t)vertex_data.mVtxColorArray[0]) / 4 + 1;
|
|
} else {
|
|
vertex_data.mColNum =
|
|
(i_block->mBlockSize - (uintptr_t)i_block->mpVtxColorArray[0]) / 4 + 1;
|
|
}
|
|
|
|
int local_28 = 0;
|
|
if (vertex_data.mVtxTexCoordArray[1]) {
|
|
color0_end = vertex_data.mVtxTexCoordArray[1];
|
|
}
|
|
|
|
if (vertex_data.mVtxTexCoordArray[0] == NULL) {
|
|
vertex_data.mTexCoordNum = 0;
|
|
} else {
|
|
if (local_28) {
|
|
vertex_data.mTexCoordNum = (local_28 - (uintptr_t)vertex_data.mVtxTexCoordArray[0]) / 8 + 1;
|
|
} else {
|
|
vertex_data.mTexCoordNum =
|
|
(i_block->mBlockSize - (uintptr_t)i_block->mpVtxTexCoordArray[0]) / 8 + 1;
|
|
}
|
|
}
|
|
|
|
#if TARGET_PC
|
|
readVertexData(*i_block, vertex_data);
|
|
#endif
|
|
}
|
|
|
|
#if TARGET_PC
|
|
|
|
// Approach taken from here:
|
|
// https://github.com/zeldaret/tp/blob/6c72b91f8e477ee94ccdc56b94605140e9f2abd6/libs/JSystem/src/J3DGraphBase/J3DShape.cpp#L156-L211
|
|
|
|
template <typename T>
|
|
static void FixArrayEndian(void* arrayStart, void* arrayEnd) {
|
|
#if TARGET_LITTLE_ENDIAN
|
|
u32 itemCount = ((u8*)arrayEnd - (u8*)arrayStart) / sizeof(T);
|
|
be_swap((T*)arrayStart, itemCount);
|
|
#endif
|
|
}
|
|
|
|
static void FixArrayEndian_24(void* arrayStart, void* arrayEnd) {
|
|
#if TARGET_LITTLE_ENDIAN
|
|
for (u8* work = (u8*)arrayStart; work != (u8*)arrayEnd; work += 3)
|
|
std::swap(work[0], work[2]);
|
|
#endif
|
|
}
|
|
|
|
static void FixArrayEndian(void* arrayStart, void* arrayEnd, u32 stride) {
|
|
switch (stride) {
|
|
case 1:
|
|
// Nothing needs to happen here!
|
|
break;
|
|
case 2:
|
|
FixArrayEndian<u16>(arrayStart, arrayEnd);
|
|
break;
|
|
case 3:
|
|
FixArrayEndian_24(arrayStart, arrayEnd);
|
|
break;
|
|
case 4:
|
|
FixArrayEndian<u32>(arrayStart, arrayEnd);
|
|
break;
|
|
default:
|
|
OSPanic(__FILE__, __LINE__, "Unknown component type?");
|
|
}
|
|
}
|
|
|
|
static GXAttr VertexBlockAttrOrder[13] = {
|
|
GX_VA_POS,
|
|
GX_VA_NRM,
|
|
GX_VA_NBT,
|
|
GX_VA_CLR0,
|
|
GX_VA_CLR1,
|
|
GX_VA_TEX0,
|
|
GX_VA_TEX1,
|
|
GX_VA_TEX2,
|
|
GX_VA_TEX3,
|
|
GX_VA_TEX4,
|
|
GX_VA_TEX5,
|
|
GX_VA_TEX6,
|
|
GX_VA_TEX7,
|
|
};
|
|
|
|
static void* GetDataEnd(const J3DVertexBlock& block, int start) {
|
|
const BE(u32)* attrPtrBase = &block.mpVtxPosArray;
|
|
|
|
for (int i = start + 1; i < ARRAY_SIZEU(VertexBlockAttrOrder); i++) {
|
|
if (attrPtrBase[i] != 0) {
|
|
return JSUConvertOffsetToPtr<void>(&block, attrPtrBase[i]);
|
|
}
|
|
}
|
|
|
|
return JSUConvertOffsetToPtr<void>(&block, block.mBlockSize);
|
|
}
|
|
|
|
auto StrideForData(GXAttr attr, GXCompType type, GXCompCnt cnt) -> std::pair<u32, u32> {
|
|
auto CompTypeStrideRaw = [&] {
|
|
if (type == GX_F32)
|
|
return 4;
|
|
else if (type == GX_U16 || type == GX_S16)
|
|
return 2;
|
|
else
|
|
return 1;
|
|
};
|
|
|
|
auto HandleColor = [&]() -> std::pair<u32, u32> {
|
|
if (type == GX_RGB565)
|
|
return {1, 2}; // u16[1]
|
|
else if (type == GX_RGB8)
|
|
return {3, 1}; // u8[3]
|
|
else if (type == GX_RGBX8)
|
|
return {4, 1}; // u8[4]
|
|
else if (type == GX_RGBA4)
|
|
return {1, 2}; // u16[1]
|
|
else if (type == GX_RGBA6)
|
|
return {3, 1}; // u8[3]
|
|
else if (type == GX_RGBA8)
|
|
return {4, 1}; // u8[4]
|
|
};
|
|
|
|
auto CompCnt = [&] {
|
|
if (attr == GX_VA_POS) {
|
|
return cnt == GX_POS_XY ? 2 : 3;
|
|
} else if (attr == GX_VA_NRM) {
|
|
return cnt == GX_NRM_XYZ ? 3 : 9; // NBT3 is lies
|
|
} else if (attr >= GX_VA_CLR0 && attr <= GX_VA_CLR1) {
|
|
return cnt == GX_CLR_RGB ? 3 : 4; // clr is special anyway
|
|
} else if (attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7) {
|
|
return cnt == GX_TEX_S ? 1 : 2;
|
|
} else {
|
|
JUT_ASSERT(1234, false);
|
|
}
|
|
};
|
|
|
|
if (attr >= GX_VA_CLR0 && attr <= GX_VA_CLR1) {
|
|
return HandleColor();
|
|
} else {
|
|
int compCnt = CompCnt();
|
|
int compStride = CompTypeStrideRaw();
|
|
return {compCnt, compStride};
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readVertexData(const J3DVertexBlock& block, J3DVertexData& data) {
|
|
if (!data.mHasReadInformation) {
|
|
OSPanic(__FILE__, __LINE__, "Model has VTX1 before INF1?");
|
|
}
|
|
|
|
const BE(u32)* attrPtrBase = &block.mpVtxPosArray;
|
|
for (int i = 0; i < ARRAY_SIZEU(VertexBlockAttrOrder); i++) {
|
|
GXAttr attr = VertexBlockAttrOrder[i];
|
|
|
|
if (attrPtrBase[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
GXVtxAttrFmtList fmt = getFmt(data.mVtxAttrFmtList, attr);
|
|
|
|
void* startAddr = JSUConvertOffsetToPtr<void>(&block, attrPtrBase[i]);
|
|
void* endAddr = GetDataEnd(block, i);
|
|
auto [compCnt, compStride] = StrideForData(attr, fmt.type, fmt.cnt);
|
|
u32 vertStride = compStride * compCnt;
|
|
data.mVtxArrStride[attr - GX_VA_POS] = vertStride;
|
|
|
|
u32 addrDiff = u32((u8*)endAddr - (u8*)startAddr);
|
|
u32 num = addrDiff / vertStride;
|
|
data.mVtxArrNum[attr - GX_VA_POS] = num;
|
|
FixArrayEndian(startAddr, endAddr, compStride);
|
|
|
|
if (attr == GX_VA_POS) {
|
|
// can be a little off due to 0x20 alignment, account for that
|
|
// u32 expect = ((data.mVtxNum * vertStride) + 0x1F) & ~0x1F;
|
|
// JUT_ASSERT(1234, expect == addrDiff);
|
|
} else if (attr == GX_VA_NRM) {
|
|
data.mNrmNum = num;
|
|
} else if (attr == GX_VA_CLR0) {
|
|
data.mColNum = num;
|
|
} else if (attr == GX_VA_TEX0) {
|
|
data.mTexCoordNum = num;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void J3DModelLoader::readEnvelop(J3DEnvelopeBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(724, i_block);
|
|
mpModelData->getJointTree().mWEvlpMtxNum = i_block->mWEvlpMtxNum;
|
|
mpModelData->getJointTree().mWEvlpMixMtxNum =
|
|
JSUConvertOffsetToPtr<u8>(i_block, i_block->mpWEvlpMixMtxNum);
|
|
mpModelData->getJointTree().mWEvlpMixMtxIndex =
|
|
JSUConvertOffsetToPtr<BE(u16)>(i_block, i_block->mpWEvlpMixIndex);
|
|
mpModelData->getJointTree().mWEvlpMixWeight =
|
|
JSUConvertOffsetToPtr<BE(f32)>(i_block, i_block->mpWEvlpMixWeight);
|
|
mpModelData->getJointTree().mInvJointMtx =
|
|
JSUConvertOffsetToPtr<BE(Mtx)>(i_block, i_block->mpInvJointMtx);
|
|
}
|
|
|
|
void J3DModelLoader::readDraw(J3DDrawBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(747, i_block);
|
|
J3DDrawMtxData* drawMtxData = mpModelData->getDrawMtxData();
|
|
drawMtxData->mEntryNum = i_block->mMtxNum - mpModelData->getWEvlpMtxNum();
|
|
drawMtxData->mDrawMtxFlag = JSUConvertOffsetToPtr<u8>(i_block, i_block->mpDrawMtxFlag);
|
|
drawMtxData->mDrawMtxIndex = JSUConvertOffsetToPtr<BE(u16)>(i_block, i_block->mpDrawMtxIndex);
|
|
u16 i;
|
|
for (i = 0; i < drawMtxData->mEntryNum; i++) {
|
|
if (drawMtxData->mDrawMtxFlag[i] == 1) {
|
|
break;
|
|
}
|
|
}
|
|
drawMtxData->mDrawFullWgtMtxNum = i;
|
|
mpModelData->getJointTree().mWEvlpImportantMtxIdx = JKR_NEW_ARRAY(u16, drawMtxData->mEntryNum);
|
|
J3D_ASSERT_ALLOCMEM(767, mpModelData->getJointTree().mWEvlpImportantMtxIdx);
|
|
}
|
|
|
|
void J3DModelLoader::readJoint(J3DJointBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(781, i_block);
|
|
J3DJointFactory factory(*i_block);
|
|
mpModelData->getJointTree().mJointNum = i_block->mJointNum;
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpModelData->getJointTree().mJointName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(791, mpModelData->getJointTree().mJointName);
|
|
} else {
|
|
mpModelData->getJointTree().mJointName = NULL;
|
|
}
|
|
mpModelData->getJointTree().mJointNodePointer =
|
|
JKR_NEW_ARRAY(J3DJoint*, mpModelData->getJointTree().mJointNum);
|
|
J3D_ASSERT_ALLOCMEM(797, mpModelData->getJointTree().mJointNodePointer);
|
|
for (u16 i = 0; i < mpModelData->getJointNum(); i++) {
|
|
mpModelData->getJointTree().mJointNodePointer[i] = factory.create(i);
|
|
}
|
|
}
|
|
|
|
#if TARGET_PC
|
|
#define MATERIAL_ID(ptr, offset) (((uintptr_t((ptr)) >> 4) & 0x3FFFFFFF) + (offset))
|
|
#else
|
|
#define MATERIAL_ID(ptr, offset) (((uintptr_t((ptr)) >> 4) + (offset)))
|
|
#endif
|
|
|
|
void J3DModelLoader_v26::readMaterial(J3DMaterialBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(817, i_block);
|
|
J3DMaterialFactory factory(*i_block);
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
mpMaterialTable->mUniqueMatNum = factory.countUniqueMaterials();
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(832, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(841, mpMaterialTable->mMaterialNodePointer);
|
|
if (i_flags & 0x200000) {
|
|
mpMaterialTable->mMaterial = JKR_NEW_ARRAY_ARGS(J3DMaterial, mpMaterialTable->mUniqueMatNum, 0x20);
|
|
J3D_ASSERT_ALLOCMEM(846, mpMaterialTable->mMaterial);
|
|
} else {
|
|
mpMaterialTable->mMaterial = NULL;
|
|
}
|
|
if (i_flags & 0x200000) {
|
|
for (u16 i = 0; i < mpMaterialTable->mUniqueMatNum; i++) {
|
|
factory.create(&mpMaterialTable->mMaterial[i],
|
|
J3DMaterialFactory::MATERIAL_TYPE_NORMAL, i, i_flags);
|
|
mpMaterialTable->mMaterial[i].mMaterialID = MATERIAL_ID(&mpMaterialTable->mMaterial[i], 0);
|
|
}
|
|
}
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(NULL, J3DMaterialFactory::MATERIAL_TYPE_NORMAL, i, i_flags);
|
|
}
|
|
if (i_flags & 0x200000) {
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(&mpMaterialTable->mMaterial[factory.getMaterialID(i)], 0);
|
|
mpMaterialTable->mMaterialNodePointer[i]->mpOrigMaterial =
|
|
&mpMaterialTable->mMaterial[factory.getMaterialID(i)];
|
|
}
|
|
} else {
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(mpMaterialTable->mMaterialNodePointer, factory.getMaterialID(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader_v21::readMaterial_v21(J3DMaterialBlock_v21 const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(913, i_block);
|
|
J3DMaterialFactory_v21 factory(*i_block);
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
mpMaterialTable->mUniqueMatNum = factory.countUniqueMaterials();
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(930, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(940, mpMaterialTable->mMaterialNodePointer);
|
|
if (i_flags & 0x200000) {
|
|
mpMaterialTable->mMaterial = JKR_NEW_ARRAY_ARGS(J3DMaterial, mpMaterialTable->mUniqueMatNum, 0x20);
|
|
J3D_ASSERT_ALLOCMEM(945, mpMaterialTable->mMaterial);
|
|
} else {
|
|
mpMaterialTable->mMaterial = NULL;
|
|
}
|
|
if (i_flags & 0x200000) {
|
|
for (u16 i = 0; i < mpMaterialTable->mUniqueMatNum; i++) {
|
|
factory.create(&mpMaterialTable->mMaterial[i], i, i_flags);
|
|
mpMaterialTable->mMaterial[i].mMaterialID = MATERIAL_ID(&mpMaterialTable->mMaterial[i], 0);
|
|
}
|
|
}
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i] = factory.create(NULL, i, i_flags);
|
|
}
|
|
if (i_flags & 0x200000) {
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(&mpMaterialTable->mMaterial[factory.getMaterialID(i)], 0);
|
|
mpMaterialTable->mMaterialNodePointer[i]->mpOrigMaterial =
|
|
&mpMaterialTable->mMaterial[factory.getMaterialID(i)];
|
|
}
|
|
} else {
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID = 0xC0000000;
|
|
}
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readShape(J3DShapeBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(1009, i_block);
|
|
mpShapeBlock = i_block;
|
|
J3DShapeTable* shape_table = mpModelData->getShapeTable();
|
|
J3DShapeFactory factory(*i_block);
|
|
shape_table->mShapeNum = i_block->mShapeNum;
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
shape_table->mShapeName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1026, shape_table->mShapeName);
|
|
} else {
|
|
shape_table->mShapeName = NULL;
|
|
}
|
|
shape_table->mShapeNodePointer = JKR_NEW_ARRAY(J3DShape*, shape_table->mShapeNum);
|
|
J3D_ASSERT_ALLOCMEM(1034, shape_table->mShapeNodePointer);
|
|
factory.allocVcdVatCmdBuffer(shape_table->mShapeNum);
|
|
J3DModelHierarchy const* hierarchy_entry = mpModelData->getHierarchy();
|
|
GXVtxDescList* vtx_desc_list = NULL;
|
|
for (; hierarchy_entry->mType != 0; hierarchy_entry++) {
|
|
if (hierarchy_entry->mType == 0x12) {
|
|
shape_table->mShapeNodePointer[hierarchy_entry->mValue] =
|
|
factory.create(hierarchy_entry->mValue, i_flags, vtx_desc_list);
|
|
vtx_desc_list = factory.getVtxDescList(hierarchy_entry->mValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readTexture(J3DTextureBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(1067, i_block);
|
|
u16 texture_num = i_block->mTextureNum;
|
|
ResTIMG* texture_res = JSUConvertOffsetToPtr<ResTIMG>(i_block, i_block->mpTextureRes);
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mTextureName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1077, mpMaterialTable->mTextureName);
|
|
} else {
|
|
mpMaterialTable->mTextureName = NULL;
|
|
}
|
|
mpMaterialTable->mTexture = JKR_NEW J3DTexture(texture_num, texture_res);
|
|
J3D_ASSERT_ALLOCMEM(1084, mpMaterialTable->mTexture);
|
|
}
|
|
|
|
void J3DModelLoader_v26::readMaterialTable(J3DMaterialBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(1101, i_block);
|
|
J3DMaterialFactory factory(*i_block);
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1114, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(1121, mpMaterialTable->mMaterialNodePointer);
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(NULL, J3DMaterialFactory::MATERIAL_TYPE_NORMAL, i, i_flags);
|
|
}
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(mpMaterialTable->mMaterialNodePointer, factory.getMaterialID(i));
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader_v21::readMaterialTable_v21(J3DMaterialBlock_v21 const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(1152, i_block);
|
|
J3DMaterialFactory_v21 factory(*i_block);
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1165, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(1172, mpMaterialTable->mMaterialNodePointer);
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(NULL, i, i_flags);
|
|
}
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(mpMaterialTable->mMaterialNodePointer, factory.getMaterialID(i));
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readTextureTable(J3DTextureBlock const* i_block) {
|
|
J3D_ASSERT_NULLPTR(1200, i_block);
|
|
u16 texture_num = i_block->mTextureNum;
|
|
ResTIMG* texture_res = JSUConvertOffsetToPtr<ResTIMG>(i_block, i_block->mpTextureRes);
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mTextureName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1211, mpMaterialTable->mTextureName);
|
|
} else {
|
|
mpMaterialTable->mTextureName = NULL;
|
|
}
|
|
mpMaterialTable->mTexture = JKR_NEW J3DTexture(texture_num, texture_res);
|
|
J3D_ASSERT_ALLOCMEM(1218, mpMaterialTable->mTexture);
|
|
}
|
|
|
|
void J3DModelLoader::readPatchedMaterial(J3DMaterialBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(1234, i_block);
|
|
J3DMaterialFactory factory(*i_block);
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
mpMaterialTable->mUniqueMatNum = factory.countUniqueMaterials();
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1251, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(1260, mpMaterialTable->mMaterialNodePointer);
|
|
mpMaterialTable->mMaterial = NULL;
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(NULL, J3DMaterialFactory::MATERIAL_TYPE_PATCHED, i, i_flags);
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID =
|
|
MATERIAL_ID(mpMaterialTable->mMaterialNodePointer, factory.getMaterialID(i));
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::readMaterialDL(J3DMaterialDLBlock const* i_block, u32 i_flags) {
|
|
J3D_ASSERT_NULLPTR(1290, i_block);
|
|
J3DMaterialFactory factory(*i_block);
|
|
s32 flags;
|
|
if (mpMaterialTable->mMaterialNum == 0) {
|
|
mpMaterialTable->field_0x1c = 1;
|
|
mpMaterialTable->mMaterialNum = i_block->mMaterialNum;
|
|
mpMaterialTable->mUniqueMatNum = i_block->mMaterialNum;
|
|
if (i_block->mpNameTable != (uintptr_t)NULL) {
|
|
mpMaterialTable->mMaterialName =
|
|
JKR_NEW JUTNameTab(JSUConvertOffsetToPtr<ResNTAB>(i_block, i_block->mpNameTable));
|
|
J3D_ASSERT_ALLOCMEM(1312, mpMaterialTable->mMaterialName);
|
|
} else {
|
|
mpMaterialTable->mMaterialName = NULL;
|
|
}
|
|
mpMaterialTable->mMaterialNodePointer = JKR_NEW_ARRAY(J3DMaterial*, mpMaterialTable->mMaterialNum);
|
|
J3D_ASSERT_ALLOCMEM(1320, mpMaterialTable->mMaterialNodePointer);
|
|
mpMaterialTable->mMaterial = NULL;
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
flags = i_flags;
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(NULL, J3DMaterialFactory::MATERIAL_TYPE_LOCKED, i, flags);
|
|
}
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
mpMaterialTable->mMaterialNodePointer[i]->mMaterialID = 0xC0000000;
|
|
}
|
|
} else {
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
flags = i_flags;
|
|
mpMaterialTable->mMaterialNodePointer[i] =
|
|
factory.create(mpMaterialTable->mMaterialNodePointer[i],
|
|
J3DMaterialFactory::MATERIAL_TYPE_LOCKED, i, flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
void J3DModelLoader::modifyMaterial(u32 i_flags) {
|
|
if (i_flags & 0x2000) {
|
|
J3DMaterialFactory factory(*mpMaterialBlock);
|
|
for (u16 i = 0; i < mpMaterialTable->mMaterialNum; i++) {
|
|
factory.modifyPatchedCurrentMtx(mpMaterialTable->mMaterialNodePointer[i], i);
|
|
}
|
|
}
|
|
}
|