mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-04-16 10:04:42 +03:00
1543 lines
45 KiB
C++
1543 lines
45 KiB
C++
#include "model/CM2Model.hpp"
|
|
#include "async/AsyncFileRead.hpp"
|
|
#include "math/Types.hpp"
|
|
#include "model/CM2Scene.hpp"
|
|
#include "model/CM2Shared.hpp"
|
|
#include "model/M2Animate.hpp"
|
|
#include "model/M2Data.hpp"
|
|
#include "model/M2Model.hpp"
|
|
#include <cmath>
|
|
#include <new>
|
|
#include <common/DataMgr.hpp>
|
|
#include <common/ObjectAlloc.hpp>
|
|
#include <tempest/Math.hpp>
|
|
|
|
uint32_t CM2Model::s_loadingSequence = 0xFFFFFFFF;
|
|
uint8_t* CM2Model::s_sequenceBase;
|
|
uint32_t CM2Model::s_sequenceBaseSize;
|
|
uint32_t CM2Model::s_skinProfileBoneCountMax[] = { 256, 64, 53, 21 };
|
|
|
|
CM2Model* CM2Model::AllocModel(uint32_t* heapId) {
|
|
uint32_t memHandle;
|
|
void* object = nullptr;
|
|
|
|
if (ObjectAlloc(*heapId, &memHandle, &object, 0)) {
|
|
CM2Model* model = new (object) CM2Model();
|
|
|
|
// TODO
|
|
// model->uint2E8 = memHandle;
|
|
|
|
return model;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool CM2Model::Sub825E00(M2Data* data, uint32_t a2) {
|
|
if (data->sequenceIdxHashById.Count() == 0) {
|
|
for (int32_t i = 0; i < data->sequences.Count(); i++) {
|
|
auto& sequence = data->sequences[i];
|
|
|
|
if (sequence.id == a2) {
|
|
return i < data->sequences.Count();
|
|
}
|
|
}
|
|
|
|
return data->sequences.Count() > 0xFFFF;
|
|
}
|
|
|
|
uint32_t v8 = a2 % data->sequenceIdxHashById.Count();
|
|
uint16_t v5 = data->sequenceIdxHashById[v8];
|
|
if (v5 == 0xFFFF) {
|
|
return data->sequences.Count() > 0xFFFF;
|
|
}
|
|
if (data->sequences[v5].id == a2) {
|
|
return v5 < data->sequences.Count();
|
|
}
|
|
|
|
int32_t v10 = 1;
|
|
while (1) {
|
|
v8 = (v8 + v10 * v10) % data->sequenceIdxHashById.Count();
|
|
v5 = data->sequenceIdxHashById[v8];
|
|
if (v5 == 0xFFFF) {
|
|
return data->sequences.Count() > 0xFFFF;
|
|
}
|
|
|
|
++v10;
|
|
|
|
if (data->sequences[v5].id == a2) {
|
|
return v5 < data->sequences.Count();
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16_t CM2Model::Sub8260C0(M2Data* data, uint32_t sequenceId, int32_t a3) {
|
|
// TODO
|
|
return -1;
|
|
}
|
|
|
|
void CM2Model::Animate() {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::AnimateCamerasST() {
|
|
for (int32_t i = 0; i < this->m_shared->m_data->cameras.Count(); i++) {
|
|
auto& camera = this->m_shared->m_data->cameras[i];
|
|
auto& modelCamera = this->m_cameras[i];
|
|
|
|
C3Vector v56 = modelCamera.positionTrack.currentValue + camera.positionPivot;
|
|
C3Vector cameraPos = (v56 * this->matrixF4) * this->m_scene->m_viewInv;
|
|
DataMgrSetCoord(modelCamera.m_camera, 7, cameraPos, 0x0);
|
|
|
|
C3Vector v57 = modelCamera.targetTrack.currentValue + camera.targetPivot;
|
|
C3Vector targetPos = (v57 * this->matrixF4) * this->m_scene->m_viewInv;
|
|
DataMgrSetCoord(modelCamera.m_camera, 8, targetPos, 0x0);
|
|
|
|
DataMgrSetFloat(modelCamera.m_camera, 5, modelCamera.rollTrack.currentValue);
|
|
}
|
|
}
|
|
|
|
void CM2Model::AnimateMT(const C44Matrix* view, const C3Vector& a3, const C3Vector& a4, float a5, float a6) {
|
|
if (!this->m_loaded /* TODO other conditionals */) {
|
|
return;
|
|
}
|
|
|
|
// TODO
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->loops.Count(); i++) {
|
|
auto loopLength = this->m_shared->m_data->loops[i].length;
|
|
this->m_loops[i] = loopLength ? (this->m_scene->m_time - this->uint74) % loopLength : 0;
|
|
}
|
|
|
|
this->matrixF4 = this->matrixB4 * *view;
|
|
|
|
this->float88 = !this->m_attachParent || this->m_attachParent->m_flags & 0x1
|
|
? this->matrixF4.d2 * this->matrixF4.d2 + this->matrixF4.d1 * this->matrixF4.d1 + this->matrixF4.d0 * this->matrixF4.d0
|
|
: this->m_attachParent->float88;
|
|
|
|
C44Matrix v237;
|
|
C44Matrix v224;
|
|
C3Vector v236;
|
|
|
|
// TODO
|
|
|
|
uint32_t elapsedTime = 0;
|
|
if (this->m_time && this->m_scene->m_time) {
|
|
elapsedTime = this->m_scene->m_time - this->m_time;
|
|
this->m_time = this->m_scene->m_time;
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->bones.Count(); i++) {
|
|
auto& bone = this->m_shared->m_data->bones[i];
|
|
auto& modelBone = this->m_bones[i];
|
|
|
|
if (modelBone.sequence.uint8 == 0xFFFF) {
|
|
if (bone.parentIndex >= this->m_shared->m_data->bones.Count()) {
|
|
if (i != 0) {
|
|
modelBone.sequence.uint0 = this->m_bones[0].sequence.uint0;
|
|
modelBone.sequence.uint4 = this->m_bones[0].sequence.uint4;
|
|
modelBone.sequence.uint6 = this->m_bones[0].sequence.uint6;
|
|
}
|
|
} else {
|
|
modelBone.sequence.uint0 = this->m_bones[bone.parentIndex].sequence.uint0;
|
|
modelBone.sequence.uint4 = this->m_bones[bone.parentIndex].sequence.uint4;
|
|
modelBone.sequence.uint6 = this->m_bones[bone.parentIndex].sequence.uint6;
|
|
}
|
|
} else {
|
|
if (this->m_time) {
|
|
modelBone.sequence.uintC += elapsedTime;
|
|
modelBone.sequence.uint10 += elapsedTime;
|
|
}
|
|
|
|
auto v45 = this->m_scene->m_time;
|
|
auto& v46 = this->m_shared->m_data->sequences[modelBone.sequence.uint8];
|
|
uint32_t v47 = 0;
|
|
|
|
if (v46.flags & 0x1) {
|
|
if (modelBone.sequence.uint10 - v45 <= 0) {
|
|
auto v234 = modelBone.sequence.uint10 - modelBone.sequence.uintC;
|
|
auto v235 = CMath::fuint(v234 * modelBone.sequence.float14);
|
|
v47 = modelBone.sequence.uint1C + v235;
|
|
v47 = std::min(v47, v46.duration);
|
|
} else {
|
|
if (modelBone.sequence.uintC - v45 > 0) {
|
|
v45 = modelBone.sequence.uintC;
|
|
}
|
|
|
|
if (v46.duration) {
|
|
auto v234 = v45 - modelBone.sequence.uintC;
|
|
auto v235 = CMath::fuint(v234 * modelBone.sequence.float14);
|
|
v47 = (modelBone.sequence.uint1C + v235) % v46.duration;
|
|
}
|
|
}
|
|
} else {
|
|
if (v46.duration) {
|
|
auto v234 = v45 - modelBone.sequence.uintC;
|
|
auto v235 = CMath::fuint(v234 * modelBone.sequence.float14);
|
|
v47 = (modelBone.sequence.uint1C + v235) % v46.duration;
|
|
}
|
|
}
|
|
|
|
modelBone.sequence.uint0 = v47;
|
|
modelBone.sequence.uint4 = modelBone.sequence.uint8;
|
|
modelBone.sequence.uint6 = i;
|
|
}
|
|
|
|
// TODO
|
|
|
|
uint32_t boneFlags = bone.flags | modelBone.flags;
|
|
|
|
C44Matrix* boneParentMatrix;
|
|
|
|
if (bone.parentIndex == 0xFFFF) {
|
|
boneParentMatrix = &this->matrixF4;
|
|
} else {
|
|
boneParentMatrix = &this->m_boneMatrices[bone.parentIndex];
|
|
|
|
if (boneFlags & (0x1 | 0x2 | 0x4)) {
|
|
// TODO
|
|
}
|
|
}
|
|
|
|
if (boneFlags & (0x80 | 0x200)) {
|
|
C44Matrix boneLocalMatrix;
|
|
|
|
if (bone.rotationTrack.sequenceTimes.Count()) {
|
|
auto& rotationTrack = bone.rotationTrack;
|
|
|
|
if (
|
|
rotationTrack.sequenceTimes.Count() > 1
|
|
|| (rotationTrack.sequenceTimes.Count() == 1 && rotationTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C4Quaternion defaultValue = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
M2AnimateTrack<M2CompQuat, C4Quaternion>(this, &modelBone, rotationTrack, modelBone.rotationTrack, defaultValue);
|
|
}
|
|
|
|
boneLocalMatrix = C44Matrix(modelBone.rotationTrack.currentValue);
|
|
} else {
|
|
// TODO
|
|
}
|
|
|
|
if (bone.scaleTrack.sequenceTimes.Count()) {
|
|
auto& scaleTrack = bone.scaleTrack;
|
|
|
|
if (
|
|
scaleTrack.sequenceTimes.Count() > 1
|
|
|| (scaleTrack.sequenceTimes.Count() == 1 && scaleTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 1.0f, 1.0f, 1.0f };
|
|
M2AnimateTrack<C3Vector, C3Vector>(this, &modelBone, scaleTrack, modelBone.scaleTrack, defaultValue);
|
|
}
|
|
|
|
boneLocalMatrix.Scale(modelBone.scaleTrack.currentValue);
|
|
}
|
|
|
|
// TODO
|
|
// conditional involving bone flags and a matrix member of M2ModelBone
|
|
|
|
C3Vector translation;
|
|
|
|
if (bone.translationTrack.sequenceTimes.Count()) {
|
|
auto& translationTrack = bone.translationTrack;
|
|
|
|
if (
|
|
translationTrack.sequenceTimes.Count() > 1
|
|
|| (translationTrack.sequenceTimes.Count() == 1 && translationTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateTrack<C3Vector, C3Vector>(this, &modelBone, translationTrack, modelBone.translationTrack, defaultValue);
|
|
}
|
|
|
|
translation = modelBone.translationTrack.currentValue + bone.pivot;
|
|
} else {
|
|
translation = bone.pivot;
|
|
}
|
|
|
|
boneLocalMatrix.d0 += translation.x;
|
|
boneLocalMatrix.d1 += translation.y;
|
|
boneLocalMatrix.d2 += translation.z;
|
|
|
|
C3Vector negPivot = {
|
|
-bone.pivot.x,
|
|
-bone.pivot.y,
|
|
-bone.pivot.z
|
|
};
|
|
|
|
boneLocalMatrix.Translate(negPivot);
|
|
|
|
this->m_boneMatrices[i] = boneLocalMatrix * *boneParentMatrix;
|
|
} else {
|
|
this->m_boneMatrices[i] = *boneParentMatrix;
|
|
}
|
|
|
|
if (boneFlags & (0x8 | 0x10 | 0x20 | 0x40)) {
|
|
// TODO
|
|
}
|
|
|
|
// TODO
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->colors.Count(); i++) {
|
|
auto& color = this->m_shared->m_data->colors[i];
|
|
auto& modelColor = this->m_colors[i];
|
|
|
|
auto& colorTrack = color.colorTrack;
|
|
if (
|
|
colorTrack.sequenceTimes.Count() > 1
|
|
|| (colorTrack.sequenceTimes.Count() == 1 && colorTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateTrack<C3Vector, C3Vector>(
|
|
this,
|
|
this->m_bones,
|
|
color.colorTrack,
|
|
modelColor.colorTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
auto& alphaTrack = color.alphaTrack;
|
|
if (
|
|
alphaTrack.sequenceTimes.Count() > 1
|
|
|| (alphaTrack.sequenceTimes.Count() == 1 && alphaTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
float defaultValue = 1.0f;
|
|
M2AnimateTrack<fixed16, float>(
|
|
this,
|
|
this->m_bones,
|
|
color.alphaTrack,
|
|
modelColor.alphaTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->textureWeights.Count(); i++) {
|
|
auto& textureWeight = this->m_shared->m_data->textureWeights[i];
|
|
auto& modelTextureWeight = this->m_textureWeights[i];
|
|
|
|
auto& weightTrack = textureWeight.weightTrack;
|
|
if (
|
|
weightTrack.sequenceTimes.Count() > 1
|
|
|| (weightTrack.sequenceTimes.Count() == 1 && weightTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
float defaultValue = 1.0f;
|
|
M2AnimateTrack<fixed16, float>(
|
|
this,
|
|
this->m_bones,
|
|
textureWeight.weightTrack,
|
|
modelTextureWeight.weightTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->lights.Count(); i++) {
|
|
auto& light = this->m_shared->m_data->lights[i];
|
|
auto& modelLight = this->m_lights[i];
|
|
|
|
if (modelLight.uint64) {
|
|
uint8_t defaultValue = 1;
|
|
M2AnimateTrack<uint8_t, uint8_t>(
|
|
this,
|
|
&this->m_bones[light.boneIndex],
|
|
light.visibilityTrack,
|
|
modelLight.visibilityTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
if ((modelLight.uint64 == 0 || modelLight.visibilityTrack.currentValue == 0) && this->uint90) {
|
|
continue;
|
|
}
|
|
|
|
auto& ambientIntensityTrack = light.ambientIntensityTrack;
|
|
if (
|
|
ambientIntensityTrack.sequenceTimes.Count() > 1
|
|
|| (ambientIntensityTrack.sequenceTimes.Count() == 1 && ambientIntensityTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
float defaultValue = 0.0f;
|
|
M2AnimateTrack<float, float>(
|
|
this,
|
|
&this->m_bones[light.boneIndex],
|
|
light.ambientIntensityTrack,
|
|
modelLight.ambientIntensityTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
auto& ambientColorTrack = light.ambientColorTrack;
|
|
if (
|
|
ambientColorTrack.sequenceTimes.Count() > 1
|
|
|| (ambientColorTrack.sequenceTimes.Count() == 1 && ambientColorTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateTrack<C3Vector, C3Vector>(
|
|
this,
|
|
&this->m_bones[light.boneIndex],
|
|
light.ambientColorTrack,
|
|
modelLight.ambientColorTrack,
|
|
defaultValue
|
|
);
|
|
|
|
float mul = modelLight.ambientIntensityTrack.currentValue * this->float198;
|
|
|
|
modelLight.light.m_ambColor.x = modelLight.ambientColorTrack.currentValue.x * mul;
|
|
modelLight.light.m_ambColor.y = modelLight.ambientColorTrack.currentValue.y * mul;
|
|
modelLight.light.m_ambColor.z = modelLight.ambientColorTrack.currentValue.z * mul;
|
|
}
|
|
|
|
auto& diffuseIntensityTrack = light.diffuseIntensityTrack;
|
|
if (
|
|
diffuseIntensityTrack.sequenceTimes.Count() > 1
|
|
|| (diffuseIntensityTrack.sequenceTimes.Count() == 1 && diffuseIntensityTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
float defaultValue = 0.0f;
|
|
M2AnimateTrack<float, float>(
|
|
this,
|
|
&this->m_bones[light.boneIndex],
|
|
light.diffuseIntensityTrack,
|
|
modelLight.diffuseIntensityTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
auto& diffuseColorTrack = light.diffuseColorTrack;
|
|
if (
|
|
diffuseColorTrack.sequenceTimes.Count() > 1
|
|
|| (diffuseColorTrack.sequenceTimes.Count() == 1 && diffuseColorTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateTrack<C3Vector, C3Vector>(
|
|
this,
|
|
&this->m_bones[light.boneIndex],
|
|
light.diffuseColorTrack,
|
|
modelLight.diffuseColorTrack,
|
|
defaultValue
|
|
);
|
|
|
|
float mul = modelLight.diffuseIntensityTrack.currentValue * this->float198;
|
|
|
|
modelLight.light.m_dirColor.x = modelLight.ambientColorTrack.currentValue.x * mul;
|
|
modelLight.light.m_dirColor.y = modelLight.ambientColorTrack.currentValue.y * mul;
|
|
modelLight.light.m_dirColor.z = modelLight.ambientColorTrack.currentValue.z * mul;
|
|
}
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->cameras.Count(); i++) {
|
|
auto& camera = this->m_shared->m_data->cameras[i];
|
|
auto& modelCamera = this->m_cameras[i];
|
|
|
|
auto& positionTrack = camera.positionTrack;
|
|
if (
|
|
positionTrack.sequenceTimes.Count() > 1
|
|
|| (positionTrack.sequenceTimes.Count() == 1 && positionTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateSplineTrack<M2SplineKey<C3Vector>, C3Vector>(
|
|
this,
|
|
this->m_bones,
|
|
camera.positionTrack,
|
|
modelCamera.positionTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
auto& targetTrack = camera.targetTrack;
|
|
if (
|
|
targetTrack.sequenceTimes.Count() > 1
|
|
|| (targetTrack.sequenceTimes.Count() == 1 && targetTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
C3Vector defaultValue = { 0.0f, 0.0f, 0.0f };
|
|
M2AnimateSplineTrack<M2SplineKey<C3Vector>, C3Vector>(
|
|
this,
|
|
this->m_bones,
|
|
camera.targetTrack,
|
|
modelCamera.targetTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
|
|
auto& rollTrack = camera.rollTrack;
|
|
if (
|
|
rollTrack.sequenceTimes.Count() > 1
|
|
|| (rollTrack.sequenceTimes.Count() == 1 && rollTrack.sequenceTimes[0].times.Count() > this->uint90)
|
|
) {
|
|
float defaultValue = 0.0f;
|
|
M2AnimateSplineTrack<M2SplineKey<float>, float>(
|
|
this,
|
|
this->m_bones,
|
|
camera.rollTrack,
|
|
modelCamera.rollTrack,
|
|
defaultValue
|
|
);
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::AnimateMTSimple(const C44Matrix* view, const C3Vector& a3, const C3Vector& a4, float a5, float a6) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::AnimateST() {
|
|
if (!this->m_loaded) {
|
|
return;
|
|
}
|
|
|
|
auto attachParent = this->m_attachParent;
|
|
|
|
if (!attachParent) {
|
|
this->m_currentLighting = &this->m_lighting;
|
|
} else {
|
|
this->m_flag8000 = attachParent->m_flag8000;
|
|
|
|
if (this->m_flag8000 && attachParent->m_flags & 0x1) {
|
|
this->m_currentLighting = &this->m_lighting;
|
|
} else {
|
|
this->m_currentLighting = attachParent->m_currentLighting;
|
|
}
|
|
}
|
|
|
|
if (!this->m_currentLighting) {
|
|
this->m_currentLighting = &this->m_lighting;
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->lights.Count(); i++) {
|
|
auto& light = this->m_shared->m_data->lights[i];
|
|
auto& modelLight = this->m_lights[i];
|
|
|
|
int32_t visible = 0;
|
|
if (modelLight.uint64 && modelLight.visibilityTrack.currentValue) {
|
|
visible = 1;
|
|
|
|
if (light.lightType == M2LIGHT_1) {
|
|
// TODO
|
|
} else {
|
|
float v10 = -this->m_boneMatrices[light.boneIndex].c0;
|
|
float v11 = -this->m_boneMatrices[light.boneIndex].c1;
|
|
float v12 = -this->m_boneMatrices[light.boneIndex].c2;
|
|
|
|
float x = this->m_scene->m_viewInv.a0 * v10
|
|
+ this->m_scene->m_viewInv.b0 * v11
|
|
+ this->m_scene->m_viewInv.c0 * v12;
|
|
float y = this->m_scene->m_viewInv.a1 * v10
|
|
+ this->m_scene->m_viewInv.b1 * v11
|
|
+ this->m_scene->m_viewInv.c1 * v12;
|
|
float z = this->m_scene->m_viewInv.a2 * v10
|
|
+ this->m_scene->m_viewInv.b2 * v11
|
|
+ this->m_scene->m_viewInv.c2 * v12;
|
|
|
|
C3Vector dir = { x, y, z };
|
|
|
|
modelLight.light.SetDirection(dir);
|
|
}
|
|
}
|
|
|
|
modelLight.light.SetVisible(visible);
|
|
|
|
// TODO modelLight.light.dword4 = this->m_scene->uint14;
|
|
}
|
|
|
|
if (this->m_shared->m_data->cameras.Count()) {
|
|
this->AnimateCamerasST();
|
|
}
|
|
|
|
// TODO
|
|
|
|
if (this->m_flag8) {
|
|
this->m_drawPrev = &this->m_scene->m_drawList;
|
|
this->m_drawNext = this->m_scene->m_drawList;
|
|
this->m_scene->m_drawList = this;
|
|
|
|
if (this->m_drawNext) {
|
|
this->m_drawNext->m_drawPrev = &this->m_drawNext;
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::AttachToScene(CM2Scene* scene) {
|
|
this->DetachFromScene();
|
|
|
|
this->m_scene = scene;
|
|
|
|
this->m_scenePrev = &this->m_scene->m_modelList;
|
|
this->m_sceneNext = this->m_scene->m_modelList;
|
|
this->m_scene->m_modelList = this;
|
|
if (this->m_sceneNext) {
|
|
this->m_sceneNext->m_scenePrev = &this->m_sceneNext;
|
|
}
|
|
|
|
if (this->m_loaded) {
|
|
for (int32_t i = 0; i < this->m_shared->m_data->lights.Count(); i++) {
|
|
this->m_lights[i].light.Initialize(this->m_scene);
|
|
}
|
|
|
|
// TODO
|
|
// - sequence / sequence fallback logic
|
|
} else {
|
|
for (auto modelCall = this->m_modelCallList; modelCall; modelCall = modelCall->modelCallNext) {
|
|
modelCall->time += this->m_scene->m_time;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CM2Model::CancelDeferredSequences(uint32_t boneIndex, bool a3) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::DetachFromScene() {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::FindKey(M2ModelBoneSeq* sequence, const M2TrackBase& track, uint32_t& currentKey, uint32_t& nextKey, float& ratio) {
|
|
if (!track.sequenceTimes.Count()) {
|
|
nextKey = 0;
|
|
currentKey = 0;
|
|
ratio = 0.0f;
|
|
|
|
return;
|
|
}
|
|
|
|
uint32_t v6 = sequence->uint0;
|
|
uint32_t v7 = sequence->uint4;
|
|
|
|
if (track.loopIndex == 0xFFFF) {
|
|
if (v7 >= track.sequenceTimes.Count()) {
|
|
v7 = 0;
|
|
}
|
|
} else {
|
|
v6 = this->m_loops[track.loopIndex];
|
|
v7 = 0;
|
|
}
|
|
|
|
uint32_t v12 = track.sequenceTimes[v7].times.Count();
|
|
|
|
if (v12 <= 1) {
|
|
nextKey = 0;
|
|
currentKey = 0;
|
|
ratio = 0.0f;
|
|
|
|
return;
|
|
}
|
|
|
|
if (currentKey >= v12) {
|
|
currentKey = 0;
|
|
}
|
|
|
|
uint32_t v15 = currentKey;
|
|
auto& v24 = track.sequenceTimes[v7];
|
|
auto v14 = v24.times.Data();
|
|
auto v16 = v6 - v14[currentKey];
|
|
uint32_t* v17;
|
|
uint32_t* v18;
|
|
uint32_t* v19;
|
|
uint32_t v20;
|
|
uint32_t v21;
|
|
|
|
if (v16 >= 500) {
|
|
if (v16 < 0xFFFFFE0C) {
|
|
v15 = 0;
|
|
|
|
if (v6 >= 500) {
|
|
v20 = v12;
|
|
|
|
while (1) {
|
|
v21 = (v20 + v15) >> 1;
|
|
|
|
if (v6 >= v14[v21]) {
|
|
v15 = v21 + 1;
|
|
|
|
if (v21 + 1 >= v12 || v6 < v14[v21 + 1]) {
|
|
v15 = v21;
|
|
goto LABEL_36;
|
|
}
|
|
} else {
|
|
v20 = v21 - 1;
|
|
}
|
|
|
|
if (v15 >= v20) {
|
|
goto LABEL_36;
|
|
}
|
|
}
|
|
}
|
|
|
|
v19 = v14 + 1;
|
|
|
|
do {
|
|
if (*v19 > v6) {
|
|
break;
|
|
}
|
|
|
|
++v15;
|
|
++v19;
|
|
} while (v15 < v12 - 1);
|
|
} else if (v15) {
|
|
v18 = &v14[v15];
|
|
|
|
do {
|
|
if (*v18 <= v6) {
|
|
break;
|
|
}
|
|
|
|
--v15;
|
|
--v18;
|
|
} while (v15);
|
|
}
|
|
} else if (v15 < v12 - 1) {
|
|
v17 = &v14[v15 + 1];
|
|
|
|
do {
|
|
if (*v17 > v6) {
|
|
break;
|
|
}
|
|
|
|
++v15;
|
|
++v17;
|
|
} while (v15 < v12 - 1);
|
|
}
|
|
|
|
LABEL_36:
|
|
|
|
if (v15 + 1 >= v24.times.Count()) {
|
|
nextKey = v15;
|
|
currentKey = v15;
|
|
ratio = 0.0f;
|
|
} else {
|
|
currentKey = v15;
|
|
nextKey = v15 + 1;
|
|
|
|
uint32_t* v22 = &v24.times[v15];
|
|
float v23 = static_cast<float>(v6 - v22[0]);
|
|
float v25 = static_cast<float>(v22[1] - v22[0]);
|
|
ratio = v23 / v25;
|
|
}
|
|
}
|
|
|
|
CAaBox& CM2Model::GetBoundingBox(CAaBox& bounds) {
|
|
// TODO
|
|
// WaitForLoad
|
|
|
|
bounds = this->m_shared->m_data->bounds.extent;
|
|
|
|
return bounds;
|
|
}
|
|
|
|
HCAMERA CM2Model::GetCameraByIndex(uint32_t index) {
|
|
if (!this->m_loaded) {
|
|
this->WaitForLoad("GetCameraByIndex");
|
|
}
|
|
|
|
return this->m_cameras[index].m_camera;
|
|
}
|
|
|
|
C3Vector CM2Model::GetPosition() {
|
|
return reinterpret_cast<C3Vector&>(this->matrixF4.d0) * this->m_scene->m_viewInv;
|
|
}
|
|
|
|
int32_t CM2Model::Initialize(CM2Scene* scene, CM2Shared* shared, CM2Model* a4, uint32_t flags) {
|
|
this->AttachToScene(scene);
|
|
|
|
// TODO
|
|
// this->dword30[23] = this->m_scene->dwordC;
|
|
|
|
this->m_shared = shared;
|
|
this->m_shared->AddRef();
|
|
|
|
if (a4) {
|
|
a4->m_refCount++;
|
|
}
|
|
|
|
this->m_flags = flags;
|
|
|
|
this->m_modelCallTail = &this->m_modelCallList;
|
|
|
|
this->uint74 = this->m_scene->m_time;
|
|
|
|
// TODO
|
|
|
|
return this->m_shared->CallbackWhenLoaded(this);
|
|
}
|
|
|
|
int32_t CM2Model::InitializeLoaded() {
|
|
if (!this->m_shared->m_m2DataLoaded || !this->m_shared->m_skinProfileLoaded) {
|
|
return 1;
|
|
}
|
|
|
|
uint32_t dataSize
|
|
= (sizeof(M2ModelBone) * this->m_shared->m_data->bones.Count())
|
|
+ (sizeof(uint32_t) * this->m_shared->m_data->loops.Count())
|
|
+ (sizeof(uint32_t) * this->m_shared->skinProfile->skinSections.Count())
|
|
+ (sizeof(M2ModelColor) * this->m_shared->m_data->colors.Count())
|
|
+ (sizeof(HTEXTURE) * this->m_shared->m_data->textures.Count())
|
|
+ (sizeof(M2ModelTextureWeight) * this->m_shared->m_data->textureWeights.Count())
|
|
+ (sizeof(M2ModelTextureTransform) * this->m_shared->m_data->textureTransforms.Count())
|
|
+ (sizeof(M2ModelAttachment) * this->m_shared->m_data->attachments.Count())
|
|
+ (sizeof(M2ModelLight) * this->m_shared->m_data->lights.Count())
|
|
+ (sizeof(M2ModelCamera) * this->m_shared->m_data->cameras.Count());
|
|
|
|
// TODO
|
|
// allocate space for particles and ribbons
|
|
|
|
char* data = static_cast<char*>(SMemAlloc(dataSize, __FILE__, __LINE__, 0));
|
|
|
|
if (this->m_shared->m_data->bones.Count()) {
|
|
this->m_bones = reinterpret_cast<M2ModelBone*>(&data[0]);
|
|
data += (sizeof(M2ModelBone) * this->m_shared->m_data->bones.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->bones.Count(); i++) {
|
|
new (&this->m_bones[i]) M2ModelBone();
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->bones.Count(); i++) {
|
|
this->m_bones[i].flags = this->m_shared->m_data->bones[i].flags;
|
|
}
|
|
|
|
// TODO use A16 allocator
|
|
this->m_boneMatrices = static_cast<C44Matrix*>(SMemAlloc(sizeof(C44Matrix) * this->m_shared->m_data->bones.Count(), __FILE__, __LINE__, 0));
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->bones.Count(); i++) {
|
|
new (&this->m_boneMatrices[i]) C44Matrix();
|
|
}
|
|
}
|
|
|
|
if (this->m_shared->m_data->loops.Count()) {
|
|
this->m_loops = reinterpret_cast<uint32_t*>(&data[0]);
|
|
data += (sizeof(uint32_t) * this->m_shared->m_data->loops.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->loops.Count(); i++) {
|
|
if (this->m_loops[i]) {
|
|
this->m_loops[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
|
|
if (this->m_shared->m_data->colors.Count()) {
|
|
this->m_colors = reinterpret_cast<M2ModelColor*>(&data[0]);
|
|
data += (sizeof(M2ModelColor) * this->m_shared->m_data->colors.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->colors.Count(); i++) {
|
|
new (&this->m_colors[i]) M2ModelColor();
|
|
}
|
|
}
|
|
|
|
if (this->m_shared->m_data->textures.Count()) {
|
|
this->m_textures = reinterpret_cast<HTEXTURE*>(&data[0]);
|
|
data += (sizeof(HTEXTURE) * this->m_shared->m_data->textures.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->textures.Count(); i++) {
|
|
HTEXTURE textureHandle = this->model30
|
|
? this->model30->m_textures[i]
|
|
: this->m_shared->textures[i];
|
|
|
|
this->m_textures[i] = textureHandle
|
|
? HandleDuplicate(textureHandle)
|
|
: nullptr;
|
|
}
|
|
}
|
|
|
|
if (this->m_shared->m_data->textureWeights.Count()) {
|
|
this->m_textureWeights = reinterpret_cast<M2ModelTextureWeight*>(&data[0]);
|
|
data += (sizeof(M2ModelTextureWeight) * this->m_shared->m_data->textureWeights.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->textureWeights.Count(); i++) {
|
|
new (&this->m_textureWeights[i]) M2ModelTextureWeight();
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
|
|
if (this->m_shared->m_data->lights.Count()) {
|
|
this->m_lights = reinterpret_cast<M2ModelLight*>(&data[0]);
|
|
data += (sizeof(M2ModelLight) * this->m_shared->m_data->lights.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->lights.Count(); i++) {
|
|
new (&this->m_lights[i]) M2ModelLight();
|
|
|
|
auto& light = this->m_shared->m_data->lights[i];
|
|
auto& modelLight = this->m_lights[i];
|
|
|
|
modelLight.light.Initialize(this->m_scene);
|
|
modelLight.light.SetLightType(static_cast<M2LIGHTTYPE>(light.lightType));
|
|
modelLight.ambientIntensityTrack.currentValue = 1.0f;
|
|
modelLight.diffuseIntensityTrack.currentValue = 1.0f;
|
|
modelLight.visibilityTrack.currentValue = 1;
|
|
}
|
|
}
|
|
|
|
if (this->m_shared->m_data->cameras.Count()) {
|
|
this->m_cameras = reinterpret_cast<M2ModelCamera*>(&data[0]);
|
|
data += (sizeof(M2ModelCamera) * this->m_shared->m_data->cameras.Count());
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->cameras.Count(); i++) {
|
|
new (&this->m_cameras[i]) M2ModelCamera();
|
|
}
|
|
|
|
for (int32_t i = 0; i < this->m_shared->m_data->cameras.Count(); i++) {
|
|
auto& camera = this->m_shared->m_data->cameras[i];
|
|
auto cameraHandle = CameraCreate();
|
|
|
|
if (camera.fieldOfView <= 0.0f || camera.fieldOfView >= 3.1415927f || camera.farClip <= camera.nearClip) {
|
|
break;
|
|
}
|
|
|
|
DataMgrSetFloat(cameraHandle, 4, camera.fieldOfView);
|
|
DataMgrSetFloat(cameraHandle, 3, camera.nearClip);
|
|
DataMgrSetFloat(cameraHandle, 2, camera.farClip);
|
|
|
|
this->m_cameras[i].m_camera = cameraHandle;
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
|
|
this->m_loaded = 1;
|
|
|
|
uint32_t savedTime = this->m_scene->m_time;
|
|
|
|
while (this->m_modelCallList) {
|
|
auto modelCall = this->m_modelCallList;
|
|
|
|
this->m_scene->m_time = modelCall->time;
|
|
|
|
switch (modelCall->type) {
|
|
case 0: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 1: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 2: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 3: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 4: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 5: {
|
|
this->SetBoneSequence(
|
|
modelCall->args[0],
|
|
modelCall->args[1],
|
|
modelCall->args[2],
|
|
modelCall->args[3],
|
|
*reinterpret_cast<float*>(&modelCall->args[4]),
|
|
modelCall->args[5],
|
|
modelCall->args[6]
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case 6: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 7: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 8: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 9: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 10: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 11: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 12: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 13: {
|
|
// TODO
|
|
break;
|
|
}
|
|
|
|
case 14: {
|
|
// TODO
|
|
break;
|
|
}
|
|
}
|
|
|
|
this->m_modelCallList = modelCall->modelCallNext;
|
|
|
|
if (modelCall->type == 0) {
|
|
HTEXTURE texture = reinterpret_cast<HTEXTURE>(&modelCall->args[1]);
|
|
|
|
if (texture) {
|
|
HandleClose(texture);
|
|
}
|
|
}
|
|
|
|
SMemFree(modelCall);
|
|
}
|
|
|
|
this->m_scene->m_time = savedTime;
|
|
|
|
this->UpdateLoaded();
|
|
this->m_flag800 = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int32_t CM2Model::IsBatchDoodadCompatible(M2Batch* batch) {
|
|
// TODO
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t CM2Model::IsDrawable(int32_t a2, int32_t a3) {
|
|
if (!this->m_loaded && a2) {
|
|
this->WaitForLoad(nullptr);
|
|
}
|
|
|
|
if (!this->m_flag2) {
|
|
if (!this->m_loaded) {
|
|
return 0;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < this->m_shared->m_data->textures.Count(); i++) {
|
|
auto texture = this->m_textures[i];
|
|
|
|
if (!texture) {
|
|
continue;
|
|
}
|
|
|
|
if (!TextureGetGxTex(texture, a2, nullptr)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
this->m_flag2 = 1;
|
|
}
|
|
|
|
if (!this->m_flag200 && a3) {
|
|
// TODO
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int32_t CM2Model::IsLoaded(int32_t a2, int32_t attachments) {
|
|
if (this->m_flags & 0x20) {
|
|
if (this->m_loaded) {
|
|
return 1;
|
|
}
|
|
|
|
if (a2) {
|
|
this->WaitForLoad(nullptr);
|
|
}
|
|
|
|
return this->m_loaded && this->m_shared->m_m2DataLoaded && this->m_shared->m_skinProfileLoaded;
|
|
}
|
|
|
|
if (!this->m_loaded && a2) {
|
|
this->WaitForLoad(nullptr);
|
|
}
|
|
|
|
if (!this->m_loaded) {
|
|
return 0;
|
|
}
|
|
|
|
if (!attachments || this->m_flag100) {
|
|
return 1;
|
|
}
|
|
|
|
// TODO
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CM2Model::LinkToCallbackListTail() {
|
|
this->m_callbackPrev = this->m_shared->m_callbackListTail;
|
|
this->m_callbackNext = nullptr;
|
|
*this->m_shared->m_callbackListTail = this;
|
|
this->m_shared->m_callbackListTail = &this->m_callbackNext;
|
|
}
|
|
|
|
int32_t CM2Model::ProcessCallbacks() {
|
|
// TODO
|
|
return 1;
|
|
}
|
|
|
|
void CM2Model::ProcessCallbacksRecursive() {
|
|
if (!this->m_loaded) {
|
|
return;
|
|
}
|
|
|
|
this->m_refCount++;
|
|
|
|
if (this->ProcessCallbacks()) {
|
|
// TODO process attachments
|
|
}
|
|
|
|
this->Release();
|
|
}
|
|
|
|
void CM2Model::Release() {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::SetAnimating(int32_t animating) {
|
|
if (!animating) {
|
|
if (this->m_animatePrev) {
|
|
*this->m_animatePrev = this->m_animateNext;
|
|
|
|
if (this->m_animateNext) {
|
|
this->m_animateNext->m_animatePrev = this->m_animatePrev;
|
|
}
|
|
|
|
this->m_animatePrev = nullptr;
|
|
this->m_animateNext = nullptr;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (this->m_flags & 0x20 && !this->m_loaded) {
|
|
this->WaitForLoad(nullptr);
|
|
}
|
|
|
|
if (!this->m_animatePrev) {
|
|
this->m_animatePrev = &this->m_scene->m_animateList;
|
|
this->m_animateNext = this->m_scene->m_animateList;
|
|
this->m_scene->m_animateList = this;
|
|
|
|
if (this->m_animateNext) {
|
|
this->m_animateNext->m_animatePrev = &this->m_animateNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CM2Model::SetBoneSequence(uint32_t boneId, uint32_t sequenceId, uint32_t a4, uint32_t time, float a6, int32_t a7, int32_t a8) {
|
|
if (sequenceId == -1) {
|
|
this->UnsetBoneSequence(boneId, a7, a8);
|
|
return;
|
|
}
|
|
|
|
if (!this->m_loaded) {
|
|
auto m = SMemAlloc(sizeof(CM2ModelCall), __FILE__, __LINE__, 0x0);
|
|
auto modelCall = new (m) CM2ModelCall();
|
|
|
|
modelCall->type = 5;
|
|
modelCall->modelCallNext = nullptr;
|
|
modelCall->time = this->m_scene->m_time;
|
|
modelCall->args[0] = boneId;
|
|
modelCall->args[1] = sequenceId;
|
|
modelCall->args[2] = a4;
|
|
modelCall->args[3] = time;
|
|
*reinterpret_cast<float*>(&modelCall->args[4]) = a6;
|
|
modelCall->args[5] = a7;
|
|
modelCall->args[6] = a8;
|
|
|
|
*this->m_modelCallTail = modelCall;
|
|
this->m_modelCallTail = &modelCall->modelCallNext;
|
|
|
|
return;
|
|
}
|
|
|
|
if (this->m_flag800) {
|
|
a7 = 0;
|
|
}
|
|
|
|
uint16_t boneIndex;
|
|
if (boneId == -1) {
|
|
boneIndex = 0;
|
|
} else if (boneId < this->m_shared->m_data->boneIndicesById.Count()) {
|
|
boneIndex = this->m_shared->m_data->boneIndicesById[boneId];
|
|
} else {
|
|
boneIndex = -1;
|
|
}
|
|
|
|
if (boneIndex >= this->m_shared->m_data->bones.Count()) {
|
|
return;
|
|
}
|
|
|
|
M2SequenceFallback fallback;
|
|
this->Sub826350(fallback, sequenceId);
|
|
int32_t v33 = a4 == -1;
|
|
|
|
uint16_t v15 = CM2Model::Sub8260C0(this->m_shared->m_data, fallback.uint0, a4 != -1 ? a4 : 0);
|
|
uint32_t v16 = v15;
|
|
uint32_t v32 = v15;
|
|
uint32_t v17;
|
|
|
|
if (v15 != 0xFFFF) {
|
|
if (!v33) {
|
|
goto LABEL_30;
|
|
}
|
|
|
|
goto LABEL_29;
|
|
}
|
|
|
|
v17 = this->m_shared->m_data->sequenceIdxHashById.Count();
|
|
v33 = 1;
|
|
v32 = v17;
|
|
uint16_t v18;
|
|
|
|
if (v17) {
|
|
uint32_t v20 = fallback.uint0 % v17;
|
|
v18 = this->m_shared->m_data->sequenceIdxHashById[v20];
|
|
|
|
if (v18 != 0xFFFF) {
|
|
uint32_t v21 = 1;
|
|
|
|
if (this->m_shared->m_data->sequences[v18].id != fallback.uint0) {
|
|
while (1) {
|
|
v20 = (v20 + v21 * v21) % v32;
|
|
v18 = this->m_shared->m_data->sequenceIdxHashById[v20];
|
|
|
|
if (v18 == 0xFFFF) {
|
|
break;
|
|
}
|
|
|
|
++v21;
|
|
|
|
if (this->m_shared->m_data->sequences[v18].id == fallback.uint0) {
|
|
goto LABEL_26;
|
|
}
|
|
}
|
|
|
|
v32 = 0xFFFF;
|
|
|
|
goto LABEL_29;
|
|
}
|
|
|
|
goto LABEL_26;
|
|
}
|
|
|
|
v32 = 0xFFFF;
|
|
} else {
|
|
v18 = 0;
|
|
|
|
if (this->m_shared->m_data->sequences.Count()) {
|
|
while (this->m_shared->m_data->sequences[v18].id != fallback.uint0) {
|
|
++v18;
|
|
|
|
if (v18 >= this->m_shared->m_data->sequences.Count()) {
|
|
goto LABEL_20;
|
|
}
|
|
}
|
|
|
|
LABEL_26:
|
|
v32 = v18;
|
|
goto LABEL_29;
|
|
}
|
|
|
|
LABEL_20:
|
|
v32 = 0xFFFF;
|
|
}
|
|
|
|
LABEL_29:
|
|
this->Sub826E60(&a4, &v32);
|
|
v16 = v32;
|
|
|
|
LABEL_30:
|
|
if (this->m_shared->m_data->sequences[v16].flags & 0x20) {
|
|
if (this->Sub8269C0(boneId, boneIndex)) {
|
|
this->CancelDeferredSequences(boneIndex, a8 != 0);
|
|
|
|
auto& modelBone = this->m_bones[boneIndex];
|
|
|
|
if (a8) {
|
|
modelBone.uint90 = sequenceId;
|
|
modelBone.uint94 = a4;
|
|
|
|
this->SetPrimaryBoneSequence(v16, boneIndex, fallback, time, a6, a7);
|
|
modelBone.sequence.uintB = v33;
|
|
} else {
|
|
this->SetSecondaryBoneSequence(v16, boneIndex, fallback, time, a6);
|
|
modelBone.secondarySequence.uintB = v33;
|
|
}
|
|
}
|
|
} else {
|
|
this->SetBoneSequenceDeferred(v16, this->m_shared->m_data, boneIndex, time, a6, fallback, a7, a8, v33);
|
|
}
|
|
}
|
|
|
|
void CM2Model::SetBoneSequenceDeferred(uint16_t a2, M2Data* data, uint16_t boneIndex, uint32_t time, float a6, M2SequenceFallback fallback, int32_t a8, int32_t a9, int32_t a10) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::SetIndices() {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::SetLightingCallback(void (*lightingCallback)(CM2Model*, CM2Lighting*, void*), void* lightingArg) {
|
|
this->m_lightingCallback = lightingCallback;
|
|
this->m_lightingArg = lightingArg;
|
|
}
|
|
|
|
void CM2Model::SetLoadedCallback(void (*loadedCallback)(CM2Model*, void*), void* loadedArg) {
|
|
this->m_loadedCallback = loadedCallback;
|
|
this->m_loadedArg = loadedArg;
|
|
|
|
this->UpdateLoaded();
|
|
}
|
|
|
|
void CM2Model::SetPrimaryBoneSequence(uint16_t sequenceIndex, uint16_t boneIndex, M2SequenceFallback fallback, uint32_t time, float a6, int32_t a7) {
|
|
auto& modelBone = this->m_bones[boneIndex];
|
|
auto& sequence = this->m_shared->m_data->sequences[sequenceIndex];
|
|
|
|
if (a7) {
|
|
if (!modelBone.sequence.uintA || sequenceIndex != modelBone.sequence.uint8) {
|
|
double v10;
|
|
double v11;
|
|
double v12;
|
|
|
|
if (modelBone.secondarySequence.uint8 == 0xFFFF
|
|
|| ((v10 = (double)(modelBone.uint9C - this->m_scene->m_time) * modelBone.floatA0, v10 >= 0.0) ? (v10 <= 1.0 ? (v11 = v10 * ((3.0 - (v10 + v10)) * v10)) : (v11 = 1.0)) : (v11 = 0.0), v11 * modelBone.floatA4 <= 0.5)
|
|
) {
|
|
memcpy(&modelBone.secondarySequence, &modelBone.sequence, sizeof(modelBone.secondarySequence));
|
|
|
|
modelBone.uint9C = this->m_scene->m_time + sequence.blendtime;
|
|
if (sequence.blendtime) {
|
|
v12 = 1.0 / (double)sequence.blendtime;
|
|
} else {
|
|
v12 = 1.0;
|
|
}
|
|
modelBone.floatA0 = v12;
|
|
modelBone.floatA4 = 1.0f;
|
|
}
|
|
}
|
|
} else {
|
|
modelBone.secondarySequence.uint8 = -1;
|
|
}
|
|
|
|
this->SetupBoneSequence(sequenceIndex, fallback, time, a6, &modelBone.sequence);
|
|
|
|
int32_t v13 = modelBone.sequence.uint10;
|
|
if (modelBone.sequence.uintC == v13 || ((sequence.flags & 0x1) != 0 && (v13 -= this->m_scene->m_time, v13 <= 0))) {
|
|
modelBone.sequence.uintA = 1;
|
|
}
|
|
|
|
// TODO
|
|
// if (!modelBone.dword98) {
|
|
// modelBone.dword98 = (DWORD)&this->dword14;
|
|
// v14 = this->dword14;
|
|
// v15 = &smodelBone.word96;
|
|
// *v15 = v14;
|
|
// if (v14 != 0xFFFF) {
|
|
// this->m_bones[v14].dword98 = v15;
|
|
// }
|
|
// LOWORD(v13) = a3;
|
|
// LOWORD(this->dword14) = a3;
|
|
// }
|
|
}
|
|
|
|
void CM2Model::SetSecondaryBoneSequence(uint16_t a2, uint16_t boneIndex, M2SequenceFallback fallback, uint32_t time, float a6) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::SetupBoneSequence(uint16_t sequenceIndex, M2SequenceFallback fallback, uint32_t a4, float a5, M2ModelBoneSeq* boneSequence) {
|
|
auto& sequence = this->m_shared->m_data->sequences[sequenceIndex];
|
|
|
|
int32_t v9 = rand();
|
|
uint32_t v10 = (sequence.replay.l + (sequence.replay.h - sequence.replay.l) * v9 / 0x8000 == 0)
|
|
+ sequence.replay.l + (sequence.replay.h - sequence.replay.l) * v9 / 0x8000;
|
|
int32_t v11 = v10 * sequence.duration;
|
|
|
|
double v12;
|
|
double v13;
|
|
long double v15;
|
|
|
|
if (fallback.uint2 == 1 || fallback.uint2 == 3) {
|
|
v12 = -a5;
|
|
} else {
|
|
v12 = a5;
|
|
}
|
|
|
|
v13 = 0.0;
|
|
|
|
uint32_t v18 = 0;
|
|
if (v12 < 0.0) {
|
|
v18 = v11;
|
|
}
|
|
|
|
if (fallback.uint2 == 2 || fallback.uint2 == 3) {
|
|
v12 = 0.0;
|
|
}
|
|
|
|
if (abs(v12) > 0.0000099999997) {
|
|
v13 = 1.0 / v12;
|
|
}
|
|
|
|
v15 = abs(v13);
|
|
uint32_t v16 = this->m_scene->m_time - floor((double)a4 * v15);
|
|
|
|
if ((~(this->m_scene->m_flags >> 2) & 0x1) != 0) {
|
|
v16++;
|
|
}
|
|
|
|
boneSequence->uint8 = sequenceIndex;
|
|
boneSequence->uintC = v16;
|
|
boneSequence->uint20 = v10;
|
|
boneSequence->uintA = 0;
|
|
boneSequence->uint10 = v16 + floor(v15 * (double)(unsigned int)v11);
|
|
boneSequence->uint1C = v18;
|
|
boneSequence->float14 = v12;
|
|
boneSequence->float18 = v13;
|
|
}
|
|
|
|
void CM2Model::SetupLighting() {
|
|
if (!this->m_attachParent || this->m_attachParent->m_flags & 0x1) {
|
|
this->Animate();
|
|
|
|
CAaSphere sphere;
|
|
sphere.c = this->GetPosition();
|
|
sphere.r = 0.0f;
|
|
|
|
this->m_lighting.Initialize(this->m_scene, sphere);
|
|
this->m_scene->SelectLights(&this->m_lighting);
|
|
|
|
if (this->m_lightingCallback) {
|
|
this->m_lightingCallback(this, &this->m_lighting, this->m_lightingArg);
|
|
}
|
|
|
|
this->m_lighting.SetupSunlight();
|
|
this->m_lighting.CameraSpace();
|
|
}
|
|
|
|
// TODO
|
|
// for (auto model = this->model58; model; model = model->model60) {
|
|
// model->SetupLighting();
|
|
// }
|
|
}
|
|
|
|
void CM2Model::SetVisible(int32_t visible) {
|
|
if (this->m_attachParent) {
|
|
this->m_flag80 = visible ? 1 : 0;
|
|
} else {
|
|
this->m_flag8 = visible ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
void CM2Model::SetWorldTransform(const C3Vector& position, float orientation, float scale) {
|
|
C44Matrix(this->matrixB4);
|
|
|
|
this->matrixB4.RotateAroundZ(orientation);
|
|
this->matrixB4.Scale(scale);
|
|
this->matrixB4.d0 = position.x;
|
|
this->matrixB4.d1 = position.y;
|
|
this->matrixB4.d2 = position.z;
|
|
|
|
this->m_flag8000 = 1;
|
|
}
|
|
|
|
void CM2Model::Sub826350(M2SequenceFallback& fallback, uint32_t sequenceId) {
|
|
auto data = this->m_shared->m_data;
|
|
|
|
int32_t v12;
|
|
if (CM2Model::Sub825E00(data, 0)) {
|
|
v12 = 0;
|
|
} else if (CM2Model::Sub825E00(data, 147)) {
|
|
v12 = 147;
|
|
} else {
|
|
v12 = data->sequences[0].id;
|
|
}
|
|
|
|
uint32_t v10[506];
|
|
memset(v10, 0, sizeof(v10));
|
|
|
|
if (CM2Model::Sub825E00(data, sequenceId)) {
|
|
fallback.uint0 = sequenceId;
|
|
fallback.uint2 = 0;
|
|
return;
|
|
}
|
|
|
|
// TODO
|
|
}
|
|
|
|
int32_t CM2Model::Sub8269C0(uint32_t boneId, uint16_t boneIndex) {
|
|
// TODO
|
|
return 1;
|
|
}
|
|
|
|
void CM2Model::Sub826E60(uint32_t* a2, uint32_t* a3) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::UnlinkFromCallbackList() {
|
|
if (this->m_callbackPrev) {
|
|
*this->m_callbackPrev = this->m_callbackNext;
|
|
|
|
if (this->m_callbackNext) {
|
|
this->m_callbackNext->m_callbackPrev = this->m_callbackPrev;
|
|
} else {
|
|
this->m_shared->m_callbackListTail = this->m_callbackPrev;
|
|
}
|
|
|
|
this->m_callbackPrev = nullptr;
|
|
this->m_callbackNext = nullptr;
|
|
}
|
|
}
|
|
|
|
void CM2Model::UnsetBoneSequence(uint32_t boneId, int32_t a3, int32_t a4) {
|
|
// TODO
|
|
}
|
|
|
|
void CM2Model::UpdateLoaded() {
|
|
auto model = this;
|
|
|
|
while (model) {
|
|
if (!model->IsLoaded(0, !(this->m_flags & 0x20))) {
|
|
break;
|
|
}
|
|
|
|
if (model->m_loadedCallback) {
|
|
model->m_loadedCallback(this, model->m_loadedArg);
|
|
model->m_loadedCallback = nullptr;
|
|
}
|
|
|
|
model = model->m_attachParent;
|
|
}
|
|
}
|
|
|
|
void CM2Model::WaitForLoad(const char* a2) {
|
|
if (this->m_shared->asyncObject) {
|
|
AsyncFileReadWait(this->m_shared->asyncObject);
|
|
}
|
|
|
|
if (this->m_shared->asyncObject) {
|
|
AsyncFileReadWait(this->m_shared->asyncObject);
|
|
}
|
|
|
|
if (this->m_flags & 0x20) {
|
|
this->InitializeLoaded();
|
|
}
|
|
}
|