Reimplement CSkinRules/CSkinnedModel; skinning kinda works!

This commit is contained in:
Luke Street 2022-03-10 01:33:17 -05:00
parent 8714fbf844
commit cd963c4a5c
35 changed files with 346 additions and 284 deletions

View File

@ -455,7 +455,7 @@ zeus::CTransform CAnimData::GetLocatorTransform(CSegId id, const CCharAnimTime*
if (!x220_30_poseBuilt) {
x2fc_poseBuilder.BuildTransform(id, ret);
} else {
ret.setRotation(x224_pose.GetTransformMinusOffset(id));
ret.setRotation(x224_pose.GetRotation(id));
ret.origin = x224_pose.GetOffset(id);
}
return ret;
@ -544,13 +544,13 @@ void CAnimData::RecalcPoseBuilder(const CCharAnimTime* time) {
void CAnimData::RenderAuxiliary(const zeus::CFrustum& frustum) const { x120_particleDB.AddToRendererClipped(frustum); }
void CAnimData::Render(CSkinnedModel& model, const CModelFlags& drawFlags,
const std::optional<CVertexMorphEffect>& morphEffect, const float* morphMagnitudes) {
const std::optional<CVertexMorphEffect>& morphEffect, TVectorRef morphMagnitudes) {
SetupRender(model, morphEffect, morphMagnitudes);
DrawSkinnedModel(model, drawFlags);
}
void CAnimData::SetupRender(CSkinnedModel& model, const std::optional<CVertexMorphEffect>& morphEffect,
const float* morphMagnitudes) {
TVectorRef morphMagnitudes) {
OPTICK_EVENT();
if (!x220_30_poseBuilt) {
x2fc_poseBuilder.BuildNoScale(x224_pose);
@ -560,7 +560,7 @@ void CAnimData::SetupRender(CSkinnedModel& model, const std::optional<CVertexMor
}
void CAnimData::DrawSkinnedModel(CSkinnedModel& model, const CModelFlags& flags) {
// TODO: some GX light stuff?
aurora::gfx::set_chan_mat_src(GX::COLOR0A0, GX::SRC_REG);
model.Draw(flags);
}
@ -806,8 +806,8 @@ void CAnimData::SetInfraModel(const TLockedToken<CModel>& model, const TLockedTo
}
void CAnimData::PoseSkinnedModel(CSkinnedModel& model, const CPoseAsTransforms& pose,
const std::optional<CVertexMorphEffect>& morphEffect, const float* morphMagnitudes) {
model.Calculate(pose, morphEffect, morphMagnitudes);
const std::optional<CVertexMorphEffect>& morphEffect, TVectorRef morphMagnitudes) {
model.Calculate(pose, morphEffect, morphMagnitudes, nullptr);
}
void CAnimData::AdvanceParticles(const zeus::CTransform& xf, float dt, const zeus::CVector3f& vec,

View File

@ -195,9 +195,9 @@ public:
void RecalcPoseBuilder(const CCharAnimTime* time);
void RenderAuxiliary(const zeus::CFrustum& frustum) const;
void Render(CSkinnedModel& model, const CModelFlags& drawFlags, const std::optional<CVertexMorphEffect>& morphEffect,
const float* morphMagnitudes);
TVectorRef morphMagnitudes);
void SetupRender(CSkinnedModel& model, const std::optional<CVertexMorphEffect>& morphEffect,
const float* morphMagnitudes);
TVectorRef morphMagnitudes);
static void DrawSkinnedModel(CSkinnedModel& model, const CModelFlags& flags);
void PreRender();
void BuildPose();
@ -219,7 +219,7 @@ public:
const TLockedToken<CSkinnedModel>& GetModelData() const { return xd8_modelData; }
static void PoseSkinnedModel(CSkinnedModel& model, const CPoseAsTransforms& pose,
const std::optional<CVertexMorphEffect>& morphEffect, const float* morphMagnitudes);
const std::optional<CVertexMorphEffect>& morphEffect, TVectorRef morphMagnitudes);
void AdvanceParticles(const zeus::CTransform& xf, float dt, const zeus::CVector3f&, CStateManager& stateMgr);
float GetAverageVelocity(int animIn) const;
void ResetPOILists();

View File

@ -22,7 +22,7 @@ CFactoryFnReturn CCharacterFactory::CDummyFactory::Build(const SObjectTag& tag,
const CCharacterInfo& charInfo = *params.GetOwnedObj<const CCharacterInfo*>();
switch (tag.type.toUint32() & 0x1) {
switch (tag.type.toUint32()) {
case 0:
return TToken<CSkinnedModel>::GetIObjObjectFor(std::make_unique<CSkinnedModel>(
*g_SimplePool, charInfo.GetModelId(), charInfo.GetSkinRulesId(), charInfo.GetCharLayoutInfoId()));

View File

@ -33,17 +33,10 @@ void CHierarchyPoseBuilder::RecursivelyBuildNoScale(const CSegId& boneId, const
CPoseAsTransforms& pose, const zeus::CQuaternion& parentRot,
const zeus::CMatrix3f& parentXf,
const zeus::CVector3f& parentOffset) const {
zeus::CVector3f bindOffset;
if (x0_layoutDesc.GetScaledLayoutDescription()) {
const CLayoutDescription::CScaledLayoutDescription& desc = *x0_layoutDesc.GetScaledLayoutDescription();
bindOffset = desc.ScaledLayout()->GetFromRootUnrotated(boneId);
} else
bindOffset = x0_layoutDesc.GetCharLayoutInfo()->GetFromRootUnrotated(boneId);
zeus::CQuaternion quat = parentRot * node.x4_rotation;
zeus::CMatrix3f xf = quat;
zeus::CVector3f xfOffset = parentXf * node.x14_offset + parentOffset;
pose.Insert(boneId, quat, xfOffset, bindOffset);
pose.Insert(boneId, quat, xfOffset);
CSegId curBone = node.x0_child;
while (curBone != 0) {
@ -59,29 +52,25 @@ void CHierarchyPoseBuilder::RecursivelyBuild(const CSegId& boneId, const CTreeNo
zeus::CQuaternion quat = parentRot * node.x4_rotation;
float scale;
zeus::CVector3f bindOffset;
if (x0_layoutDesc.GetScaledLayoutDescription()) {
const CLayoutDescription::CScaledLayoutDescription& desc = *x0_layoutDesc.GetScaledLayoutDescription();
scale = desc.GlobalScale();
bindOffset = desc.ScaledLayout()->GetFromRootUnrotated(boneId);
scale = x0_layoutDesc.GetScaledLayoutDescription()->GlobalScale();
} else {
scale = 1.f;
bindOffset = x0_layoutDesc.GetCharLayoutInfo()->GetFromRootUnrotated(boneId);
}
zeus::CMatrix3f mtxXf;
zeus::CMatrix3f rotation;
if (scale == 1.f)
mtxXf = quat;
rotation = quat;
else
mtxXf = parentXf * zeus::CMatrix3f(scale);
rotation = parentXf * (zeus::CMatrix3f{node.x4_rotation} * zeus::CMatrix3f{scale});
zeus::CVector3f xfOffset = parentXf * node.x14_offset + parentOffset;
pose.Insert(boneId, mtxXf, xfOffset, bindOffset);
zeus::CVector3f offset = parentOffset + (parentXf * node.x14_offset);
pose.Insert(boneId, rotation, offset);
CSegId curBone = node.x0_child;
while (curBone != 0) {
const CTreeNode& node = x38_treeMap[curBone];
RecursivelyBuild(curBone, node, pose, quat, quat, xfOffset);
RecursivelyBuild(curBone, node, pose, quat, quat, offset);
curBone = node.x1_sibling;
}
}

View File

@ -14,7 +14,6 @@ set(CHARACTER_SOURCES
CTransitionDatabaseGame.hpp CTransitionDatabaseGame.cpp
CHierarchyPoseBuilder.hpp CHierarchyPoseBuilder.cpp
CPoseAsTransforms.hpp CPoseAsTransforms.cpp
CSkinBank.hpp CSkinBank.cpp
CCharLayoutInfo.hpp CCharLayoutInfo.cpp
CLayoutDescription.hpp
CSegIdList.hpp CSegIdList.cpp

View File

@ -99,7 +99,7 @@ void CParticleDatabase::UpdateParticleGenDB(float dt, const CPoseAsTransforms& p
switch (info.GetParentedMode()) {
case CParticleData::EParentedMode::Initial: {
if (info.GetIsGrabInitialData()) {
zeus::CTransform segXf((info.GetFlags() & 0x10) ? zeus::CMatrix3f() : pose.GetTransformMinusOffset(segId),
zeus::CTransform segXf((info.GetFlags() & 0x10) ? zeus::CMatrix3f() : pose.GetRotation(segId),
off * scale);
zeus::CTransform compXf = xf * segXf;
info.SetCurTransform(compXf.getRotation());
@ -125,7 +125,7 @@ void CParticleDatabase::UpdateParticleGenDB(float dt, const CPoseAsTransforms& p
info.SetIsGrabInitialData(false);
}
zeus::CTransform segXf(pose.GetTransformMinusOffset(segId), off * scale);
zeus::CTransform segXf(pose.GetRotation(segId), off * scale);
zeus::CTransform compXf = xf * segXf;
if (info.GetParentedMode() == CParticleData::EParentedMode::ContinuousEmitter) {

View File

@ -4,7 +4,8 @@
namespace metaforce {
CPoseAsTransforms::CPoseAsTransforms(u8 boneCount) : x1_count(boneCount), xd0_transformArr(new Transform[boneCount]) {}
CPoseAsTransforms::CPoseAsTransforms(u8 boneCount)
: x1_count(boneCount), xd0_transformArr(std::make_unique<zeus::CTransform[]>(boneCount)) {}
bool CPoseAsTransforms::ContainsDataFor(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
@ -24,32 +25,23 @@ void CPoseAsTransforms::AccumulateScaledTransform(const CSegId& id, zeus::CMatri
const zeus::CTransform& CPoseAsTransforms::GetTransform(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
assert(link.second.IsValid());
return xd0_transformArr[link.second].m_originToAccum;
}
const zeus::CTransform& CPoseAsTransforms::GetRestToAccumTransform(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
assert(link.second.IsValid());
return xd0_transformArr[link.second].m_restPoseToAccum;
return xd0_transformArr[link.second];
}
const zeus::CVector3f& CPoseAsTransforms::GetOffset(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
assert(link.second.IsValid());
return xd0_transformArr[link.second].m_originToAccum.origin;
return xd0_transformArr[link.second].origin;
}
const zeus::CMatrix3f& CPoseAsTransforms::GetRotation(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
assert(link.second.IsValid());
return xd0_transformArr[link.second].m_originToAccum.basis;
return xd0_transformArr[link.second].basis;
}
void CPoseAsTransforms::Insert(const CSegId& id, const zeus::CMatrix3f& rotation, const zeus::CVector3f& offset,
const zeus::CVector3f& restOffset) {
Transform& xfOut = xd0_transformArr[x0_nextId];
xfOut.m_originToAccum = zeus::CTransform(rotation, offset);
xfOut.m_restPoseToAccum = xfOut.m_originToAccum * zeus::CTransform::Translate(-restOffset);
void CPoseAsTransforms::Insert(const CSegId& id, const zeus::CMatrix3f& rotation, const zeus::CVector3f& offset) {
xd0_transformArr[x0_nextId] = zeus::CTransform(rotation, offset);
std::pair<CSegId, CSegId>& link = x8_links[id];
link.first = xd4_lastInserted;
@ -58,4 +50,10 @@ void CPoseAsTransforms::Insert(const CSegId& id, const zeus::CMatrix3f& rotation
++x0_nextId;
}
CSegId CPoseAsTransforms::GetParent(const CSegId& id) const {
const std::pair<CSegId, CSegId>& link = x8_links[id];
assert(link.first.IsValid());
return link.first;
}
} // namespace metaforce

View File

@ -4,9 +4,9 @@
#include <memory>
#include <utility>
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Character/CCharLayoutInfo.hpp"
#include "Runtime/Character/CSegId.hpp"
#include "Runtime/RetroTypes.hpp"
#include <zeus/CMatrix3f.hpp>
#include <zeus/CTransform.hpp>
@ -16,31 +16,26 @@ namespace metaforce {
class CPoseAsTransforms {
friend class CAnimData;
public:
struct Transform {
zeus::CTransform m_originToAccum;
zeus::CTransform m_restPoseToAccum;
};
private:
CSegId x0_nextId = 0;
CSegId x1_count;
std::array<std::pair<CSegId, CSegId>, 100> x8_links;
std::unique_ptr<Transform[]> xd0_transformArr;
std::unique_ptr<zeus::CTransform[]> xd0_transformArr;
CSegId xd4_lastInserted = 0;
public:
explicit CPoseAsTransforms(u8 boneCount);
bool ContainsDataFor(const CSegId& id) const;
void Clear();
void AccumulateScaledTransform(const CSegId& id, zeus::CMatrix3f& rotation, float scale) const;
const zeus::CTransform& GetTransform(const CSegId& id) const;
const zeus::CTransform& GetRestToAccumTransform(const CSegId& id) const;
const zeus::CVector3f& GetOffset(const CSegId& id) const;
const zeus::CMatrix3f& GetRotation(const CSegId& id) const;
const zeus::CMatrix3f& GetTransformMinusOffset(const CSegId& id) const { return GetRotation(id); }
void Insert(const CSegId& id, const zeus::CMatrix3f& rotation, const zeus::CVector3f& offset,
const zeus::CVector3f& restOffset);
void Insert(const CSegId& id, const zeus::CMatrix3f& rotation, const zeus::CVector3f& offset);
[[nodiscard]] bool ContainsDataFor(const CSegId& id) const;
[[nodiscard]] const zeus::CTransform& GetTransform(const CSegId& id) const;
[[nodiscard]] const zeus::CVector3f& GetOffset(const CSegId& id) const;
[[nodiscard]] const zeus::CMatrix3f& GetRotation(const CSegId& id) const;
[[nodiscard]] CSegId GetLastInserted() const { return xd4_lastInserted; }
[[nodiscard]] CSegId GetParent(const CSegId& id) const;
};
} // namespace metaforce

View File

@ -1,21 +0,0 @@
#include "Runtime/Character/CSkinBank.hpp"
#include "Runtime/Character/CPoseAsTransforms.hpp"
namespace metaforce {
CSkinBank::CSkinBank(CInputStream& in) {
u32 boneCount = in.ReadLong();
x0_segments.reserve(boneCount);
for (u32 i = 0; i < boneCount; ++i)
x0_segments.emplace_back(in);
}
void CSkinBank::GetBankTransforms(std::vector<const zeus::CTransform*>& out, const CPoseAsTransforms& pose) const {
for (CSegId id : x0_segments) {
const zeus::CTransform& xf = pose.GetRestToAccumTransform(id);
out.push_back(&xf);
}
}
} // namespace metaforce

View File

@ -1,19 +0,0 @@
#pragma once
#include <vector>
#include "Runtime/Streams/IOStreams.hpp"
#include "Runtime/Character/CSegId.hpp"
namespace metaforce {
class CPoseAsTransforms;
class CSkinBank {
std::vector<CSegId> x0_segments;
public:
explicit CSkinBank(CInputStream& in);
void GetBankTransforms(std::vector<const zeus::CTransform*>& out, const CPoseAsTransforms& pose) const;
};
} // namespace metaforce

View File

@ -31,31 +31,47 @@ CSkinRules::CSkinRules(CInputStream& in) {
x14_normalCount = ReadCount(in);
}
// void CSkinRules::TransformVerticesCPU(std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vnOut,
// const CPoseAsTransforms& pose, const CModel& model) const {
// OPTICK_EVENT();
// vnOut.resize(m_poolToSkinIdx.size());
// for (size_t i = 0; i < m_poolToSkinIdx.size(); ++i) {
// const CVirtualBone& vb = m_virtualBones[m_poolToSkinIdx[i]];
// zeus::CVector3f origVertex = model.GetPoolVertex(i);
// zeus::CVector3f vertex;
// zeus::CVector3f origNormal = model.GetPoolNormal(i);
// zeus::CVector3f normal;
// for (const SSkinWeighting& w : vb.GetWeights()) {
// const zeus::CTransform& xf = pose.GetRestToAccumTransform(w.m_id);
// vertex += (xf * origVertex) * w.m_weight;
// normal += (xf.basis.inverted().transposed() * origNormal) * w.m_weight;
// }
// vnOut[i] = std::make_pair(vertex, normal.normalized());
// }
// }
void CSkinRules::BuildAccumulatedTransforms(const CPoseAsTransforms& pose, const CCharLayoutInfo& info) {
std::array<zeus::CVector3f, 100> points;
CSegId segId = pose.GetLastInserted();
while (segId != 0) {
zeus::CVector3f origin;
if (segId != 3) { // root ID
origin = info.GetFromRootUnrotated(segId);
}
const auto rotatedOrigin = pose.GetRotation(segId) * origin;
points[segId] = pose.GetOffset(segId) - rotatedOrigin;
segId = pose.GetParent(segId);
}
for (auto& bone : x0_bones) {
bone.BuildAccumulatedTransform(pose, points.data());
}
}
void CSkinRules::BuildPoints(TConstVectorRef positions, TVectorRef out) {
size_t offset = 0;
for (auto& bone : x0_bones) {
u32 vertexCount = bone.GetVertexCount();
bone.BuildPoints(positions->data() + offset, out, vertexCount);
offset += vertexCount;
}
}
void CSkinRules::BuildNormals(TConstVectorRef normals, TVectorRef out) {
size_t offset = 0;
for (auto& bone : x0_bones) {
u32 vertexCount = bone.GetVertexCount();
bone.BuildNormals(normals->data() + offset, out, vertexCount);
offset += vertexCount;
}
}
CFactoryFnReturn FSkinRulesFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& params,
CObjectReference* selfRef) {
return TToken<CSkinRules>::GetIObjObjectFor(std::make_unique<CSkinRules>(in));
}
auto StreamInSkinWeighting(CInputStream& in) {
static inline auto StreamInSkinWeighting(CInputStream& in) {
rstl::reserved_vector<SSkinWeighting, 3> weights;
u32 weightCount = in.ReadLong();
for (int i = 0; i < std::min(3u, weightCount); ++i) {
@ -67,6 +83,58 @@ auto StreamInSkinWeighting(CInputStream& in) {
return weights;
}
CVirtualBone::CVirtualBone(CInputStream& in)
: x0_weights(StreamInSkinWeighting(in)), x1c_vertexCount(in.ReadLong()) {}
CVirtualBone::CVirtualBone(CInputStream& in) : x0_weights(StreamInSkinWeighting(in)), x1c_vertexCount(in.ReadLong()) {}
void CVirtualBone::BuildPoints(const zeus::CVector3f* in, TVectorRef out, u32 count) const {
for (u32 i = 0; i < count; ++i) {
out->emplace_back(x20_xf * in[i]);
}
}
void CVirtualBone::BuildNormals(const zeus::CVector3f* in, TVectorRef out, u32 count) const {
for (u32 i = 0; i < count; ++i) {
out->emplace_back(x50_rotation * in[i]);
}
}
void CVirtualBone::BuildAccumulatedTransform(const CPoseAsTransforms& pose, const zeus::CVector3f* points) {
BuildFinalPosMatrix(pose, points);
x50_rotation = pose.GetRotation(x0_weights[0].x0_id);
}
static constexpr zeus::CMatrix3f WeightedMatrix(const zeus::CMatrix3f& m1, float w1, const zeus::CMatrix3f& m2, float w2) {
return {
m1[0] * w1 + m2[0] * w2,
m1[1] * w1 + m2[1] * w2,
m1[2] * w1 + m2[2] * w2,
};
}
static constexpr zeus::CVector3f WeightedVector(const zeus::CVector3f& v1, float w1, const zeus::CVector3f& v2, float w2) {
return v1 * w1 + v2 * w2;
}
void CVirtualBone::BuildFinalPosMatrix(const CPoseAsTransforms& pose, const zeus::CVector3f* points) {
if (x0_weights.size() == 1) {
const auto id = x0_weights[0].x0_id;
x20_xf = {pose.GetRotation(id), points[id]};
} else if (x0_weights.size() == 2) {
const auto w0 = x0_weights[0];
const auto w1 = x0_weights[1];
x20_xf = {
WeightedMatrix(pose.GetRotation(w0.x0_id), w0.x4_weight, pose.GetRotation(w1.x0_id), w1.x4_weight),
WeightedVector(points[w0.x0_id], w0.x4_weight, points[w1.x0_id], w1.x4_weight),
};
} else if (x0_weights.size() == 3) {
const auto w0 = x0_weights[0];
const auto w1 = x0_weights[1];
const auto w2 = x0_weights[2];
auto rot = WeightedMatrix(pose.GetRotation(w0.x0_id), w0.x4_weight, pose.GetRotation(w1.x0_id), w1.x4_weight);
auto pos = WeightedVector(points[w0.x0_id], w0.x4_weight, points[w1.x0_id], w1.x4_weight);
pose.AccumulateScaledTransform(w2.x0_id, rot, w2.x4_weight);
x20_xf = {rot, pos + points[w2.x0_id] * w2.x4_weight};
} else {
x20_xf = {};
}
}
} // namespace metaforce

View File

@ -3,12 +3,14 @@
#include <vector>
#include "Runtime/CFactoryMgr.hpp"
#include "Runtime/Character/CSkinBank.hpp"
#include "Runtime/Character/CSegId.hpp"
#include "Runtime/Graphics/CCubeModel.hpp"
#include "Runtime/RetroTypes.hpp"
#include <zeus/CVector3f.hpp>
namespace metaforce {
class CCharLayoutInfo;
class CPoseAsTransforms;
class CModel;
@ -24,12 +26,20 @@ class CVirtualBone {
rstl::reserved_vector<SSkinWeighting, 3> x0_weights;
u32 x1c_vertexCount;
zeus::CTransform x20_xf;
zeus::CMatrix3f x50_mtx;
zeus::CMatrix3f x50_rotation;
public:
explicit CVirtualBone(CInputStream& in);
[[nodiscard]] const rstl::reserved_vector<SSkinWeighting, 3>& GetWeights() const { return x0_weights; }
void BuildPoints(const zeus::CVector3f* in, TVectorRef out, u32 count) const;
void BuildNormals(const zeus::CVector3f* in, TVectorRef out, u32 count) const;
void BuildAccumulatedTransform(const CPoseAsTransforms& pose, const zeus::CVector3f* points);
[[nodiscard]] const auto& GetWeights() const { return x0_weights; }
[[nodiscard]] u32 GetVertexCount() const { return x1c_vertexCount; }
private:
void BuildFinalPosMatrix(const CPoseAsTransforms& pose, const zeus::CVector3f* points);
};
class CSkinRules {
@ -42,17 +52,12 @@ class CSkinRules {
public:
explicit CSkinRules(CInputStream& in);
// void GetBankTransforms(std::vector<const zeus::CTransform*>& out, const CPoseAsTransforms& pose,
// int skinBankIdx) const {
// // FIXME: This is definitely not proper behavior, this is here to fix the phazon suit crashing
// if (x0_skinBanks.size() <= skinBankIdx) {
// return;
// }
// x0_skinBanks[skinBankIdx].GetBankTransforms(out, pose);
// }
void BuildPoints(TConstVectorRef positions, TVectorRef out);
void BuildNormals(TConstVectorRef normals, TVectorRef out);
void BuildAccumulatedTransforms(const CPoseAsTransforms& pose, const CCharLayoutInfo& info);
// void TransformVerticesCPU(std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vnOut,
// const CPoseAsTransforms& pose, const CModel& model) const;
[[nodiscard]] u32 GetVertexCount() const { return x10_vertexCount; }
[[nodiscard]] u32 GetNormalCount() const { return x14_normalCount; }
};
CFactoryFnReturn FSkinRulesFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& params,

View File

@ -121,7 +121,7 @@ void CCubeModel::Draw(const CModelFlags& flags) {
DrawSurfaces(flags);
}
void CCubeModel::Draw(TVectorRef positions, TVectorRef normals, const CModelFlags& flags) {
void CCubeModel::Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
CCubeMaterial::KillCachedViewDepState();
SetSkinningArraysCurrent(positions, normals);
DrawSurfaces(flags);
@ -149,7 +149,7 @@ void CCubeModel::DrawAlphaSurfaces(const CModelFlags& flags) {
}
}
void CCubeModel::DrawFlat(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces) {
void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) {
if (positions == nullptr) {
SetArraysCurrent();
} else {
@ -175,7 +175,7 @@ void CCubeModel::DrawFlat(TVectorRef positions, TVectorRef normals, ESurfaceSele
}
}
void CCubeModel::DrawNormal(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces) {
void CCubeModel::DrawNormal(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassZero);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
@ -277,7 +277,7 @@ void CCubeModel::SetRenderModelBlack(bool v) {
// TODO another value is set here, but always 0?
}
void CCubeModel::SetSkinningArraysCurrent(TVectorRef positions, TVectorRef normals) {
void CCubeModel::SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals) {
aurora::gfx::model::set_vertex_buffer(positions);
aurora::gfx::model::set_normal_buffer(normals);
// colors unused

View File

@ -21,18 +21,19 @@ enum class ESurfaceSelection {
};
// These parameters were originally float*
using TVectorRef = const std::vector<zeus::CVector3f>*;
using TVectorRef = std::vector<zeus::CVector3f>*;
using TConstVectorRef = const std::vector<zeus::CVector3f>*;
class CCubeModel {
friend class CModel;
private:
class ModelInstance {
std::vector<CCubeSurface>* x0_surfacePtrs; // was rstl::vector<void*>*
u8* x4_materialData; //
std::vector<zeus::CVector3f>* x8_positions; // was void*
std::vector<zeus::CVector3f>* xc_normals; // was void*
std::vector<zeus::CColor>* x10_colors; // was void*
std::vector<CCubeSurface>* x0_surfacePtrs; // was rstl::vector<void*>*
u8* x4_materialData; //
std::vector<zeus::CVector3f>* x8_positions; // was void*
std::vector<zeus::CVector3f>* xc_normals; // was void*
std::vector<zeus::CColor>* x10_colors; // was void*
std::vector<aurora::Vec2<float>>* x14_texCoords; // was void*
std::vector<aurora::Vec2<float>>* x18_packedTexCoords; // was void*
@ -55,8 +56,10 @@ private:
[[nodiscard]] std::vector<CCubeSurface>* Surfaces() const { return x0_surfacePtrs; }
[[nodiscard]] u8* GetMaterialPointer() const { return x4_materialData; }
void SetMaterialPointer(u8* mat) { x4_materialData = mat; }
[[nodiscard]] TVectorRef GetVertexPointer() const { return x8_positions; }
[[nodiscard]] TVectorRef GetNormalPointer() const { return xc_normals; }
[[nodiscard]] TVectorRef GetVertexPointer() { return x8_positions; }
[[nodiscard]] TConstVectorRef GetVertexPointer() const { return x8_positions; }
[[nodiscard]] TVectorRef GetNormalPointer() { return xc_normals; }
[[nodiscard]] TConstVectorRef GetNormalPointer() const { return xc_normals; }
[[nodiscard]] std::vector<zeus::CColor>* GetColorPointer() const { return x10_colors; }
[[nodiscard]] std::vector<aurora::Vec2<float>>* GetTCPointer() const { return x14_texCoords; }
[[nodiscard]] std::vector<aurora::Vec2<float>>* GetPackedTCPointer() const { return x18_packedTexCoords; }
@ -84,8 +87,8 @@ public:
void RemapMaterialData(u8* data, std::vector<TCachedToken<CTexture>>& textures);
void Draw(const CModelFlags& flags);
void DrawAlpha(const CModelFlags& flags);
void DrawFlat(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces);
void DrawNormal(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces);
void DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces);
void DrawNormal(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces);
void DrawNormal(const CModelFlags& flags);
void DrawSurface(const CCubeSurface& surface, const CModelFlags& flags);
void DrawSurfaceWireframe(const CCubeSurface& surface);
@ -101,8 +104,10 @@ public:
[[nodiscard]] CCubeSurface* GetFirstSortedSurface() { return x3c_firstSortedSurf; }
[[nodiscard]] const CCubeSurface* GetFirstSortedSurface() const { return x3c_firstSortedSurf; }
[[nodiscard]] TVectorRef GetPositions() const { return x0_modelInstance.GetVertexPointer(); }
[[nodiscard]] TVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); }
[[nodiscard]] TVectorRef GetPositions() { return x0_modelInstance.GetVertexPointer(); }
[[nodiscard]] TConstVectorRef GetPositions() const { return x0_modelInstance.GetVertexPointer(); }
[[nodiscard]] TVectorRef GetNormals() { return x0_modelInstance.GetNormalPointer(); }
[[nodiscard]] TConstVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); }
[[nodiscard]] TCachedToken<CTexture>& GetTexture(u32 idx) const { return x1c_textures->at(idx); }
static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask,
@ -121,11 +126,11 @@ public:
static const CTexture* sShadowTexture;
private:
void Draw(TVectorRef positions, TVectorRef normals, const CModelFlags& flags);
void Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags);
void DrawAlphaSurfaces(const CModelFlags& flags);
void DrawNormalSurfaces(const CModelFlags& flags);
void DrawSurfaces(const CModelFlags& flags);
void SetSkinningArraysCurrent(TVectorRef positions, TVectorRef normals);
void SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals);
void SetStaticArraysCurrent();
};
} // namespace metaforce

View File

@ -634,9 +634,9 @@ u32 CCubeRenderer::GetFPS() { return CGraphics::GetFPS(); }
void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) {}
void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {}
void CCubeRenderer::DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TVectorRef positions, TVectorRef normals, const CModelFlags& flags) {}
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {}
void CCubeRenderer::DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TVectorRef positions, TVectorRef normals) {}
TConstVectorRef positions, TConstVectorRef normals) {}
void CCubeRenderer::DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) {}
void CCubeRenderer::SetWireframeFlags(s32 flags) {}
void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {}

View File

@ -180,9 +180,9 @@ public:
void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) override;
void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) override;
void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TVectorRef positions, TVectorRef normals, const CModelFlags& flags) override;
void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color, TVectorRef positions,
TVectorRef normals) override;
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) override;
void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TConstVectorRef positions, TConstVectorRef normals) override;
void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) override;
void SetWireframeFlags(s32 flags) override;
void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) override;

View File

@ -37,8 +37,10 @@ public:
[[nodiscard]] std::vector<CCubeSurface>* GetSurfaces() { return &x50_surfaces; }
[[nodiscard]] const std::vector<CCubeSurface>* GetSurfaces() const { return &x50_surfaces; }
[[nodiscard]] const u8* GetMaterialPointer() const { return x4c_materialData; }
[[nodiscard]] TVectorRef GetVertexPointer() const { return &x60_positions; }
[[nodiscard]] TVectorRef GetNormalPointer() const { return &x64_normals; }
[[nodiscard]] TVectorRef GetVertexPointer() { return &x60_positions; }
[[nodiscard]] TConstVectorRef GetVertexPointer() const { return &x60_positions; }
[[nodiscard]] TVectorRef GetNormalPointer() { return &x64_normals; }
[[nodiscard]] TConstVectorRef GetNormalPointer() const { return &x64_normals; }
[[nodiscard]] const std::vector<zeus::CColor>* GetColorPointer() const { return &x68_colors; }
[[nodiscard]] const std::vector<aurora::Vec2<float>>* GetTCPointer() const { return &x6c_texCoords; }
[[nodiscard]] const std::vector<aurora::Vec2<float>>* GetPackedTCPointer() const { return &x70_packedTexCoords; }

View File

@ -201,9 +201,13 @@ void CModel::EnableTextureTimeout() { sIsTextureTimeoutEnabled = true; }
void CModel::DisableTextureTimeout() { sIsTextureTimeoutEnabled = false; }
TVectorRef CModel::GetPositions() const { return x28_modelInst->GetPositions(); }
TVectorRef CModel::GetPositions() { return x28_modelInst->GetPositions(); }
TVectorRef CModel::GetNormals() const { return x28_modelInst->GetNormals(); }
TConstVectorRef CModel::GetPositions() const { return x28_modelInst->GetPositions(); }
TVectorRef CModel::GetNormals() { return x28_modelInst->GetNormals(); }
TConstVectorRef CModel::GetNormals() const { return x28_modelInst->GetNormals(); }
void CModel::VerifyCurrentShader(u32 matIdx) {
if (matIdx > x18_matSets.size()) {
@ -264,7 +268,7 @@ void CModel::Draw(CModelFlags flags) {
x28_modelInst->Draw(flags);
}
void CModel::Draw(TVectorRef positions, TVectorRef normals, const CModelFlags& flags) {
void CModel::Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
if (flags.x2_flags & CModelFlagBits::DrawNormal) {
x28_modelInst->DrawNormal(positions, normals, ESurfaceSelection::All);
}

View File

@ -100,13 +100,15 @@ public:
void VerifyCurrentShader(u32 matIdx);
void Touch(u32 matIdx);
void Draw(CModelFlags flags);
void Draw(TVectorRef positions, TVectorRef normals, const CModelFlags& flags);
void Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags);
void DrawSortedParts(CModelFlags flags);
void DrawUnsortedParts(CModelFlags flags);
bool IsLoaded(u32 matIdx);
TVectorRef GetPositions() const;
TVectorRef GetNormals() const;
TVectorRef GetPositions();
TConstVectorRef GetPositions() const;
TVectorRef GetNormals();
TConstVectorRef GetNormals() const;
u32 GetNumMaterialSets() const { return x18_matSets.size(); }
bool IsOpaque() const { return x28_modelInst->x3c_firstSortedSurf == nullptr; }
const zeus::CAABox& GetAABB() const { return x28_modelInst->x20_worldAABB; }

View File

@ -70,8 +70,7 @@ void CRainSplashGenerator::Draw(const zeus::CTransform& xf) {
DoDraw(xf);
}
CRainSplashGenerator::SSplashLine::SSplashLine()
: m_renderer(CLineRenderer::EPrimitiveMode::LineStrip, 3, {}, false) {}
CRainSplashGenerator::SSplashLine::SSplashLine() : m_renderer(CLineRenderer::EPrimitiveMode::LineStrip, 3, {}, false) {}
CRainSplashGenerator::SRainSplash::SRainSplash() {
for (size_t i = 0; i < x0_lines.capacity(); ++i) {
@ -146,16 +145,16 @@ void CRainSplashGenerator::Update(float dt, CStateManager& mgr) {
}
}
u32 CRainSplashGenerator::GetNextBestPt(u32 pt, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
CRandom16& rand, float minZ) {
const auto& refVert = vn[pt];
u32 CRainSplashGenerator::GetNextBestPt(u32 pt, const SSkinningWorkspace& workspace, CRandom16& rand, float minZ) {
const auto& refVert = workspace.m_vertexWorkspace[pt];
float maxDist = 0.f;
u32 nextPt = pt;
for (int i = 0; i < 3; ++i) {
const auto idx = u32(rand.Range(0, int(vn.size() - 1)));
const auto& vert = vn[idx];
const float distSq = (refVert.first - vert.first).magSquared();
if (distSq > maxDist && vert.second.dot(zeus::skUp) >= 0.f && (vert.first.z() <= 0.f || vert.first.z() > minZ)) {
const auto idx = u32(rand.Range(0, int(workspace.m_vertexWorkspace.size() - 1)));
const auto& vert = workspace.m_vertexWorkspace[idx];
const auto& norm = workspace.m_normalWorkspace[idx];
const float distSq = (refVert - vert).magSquared();
if (distSq > maxDist && norm.dot(zeus::skUp) >= 0.f && (vert.z() <= 0.f || vert.z() > minZ)) {
nextPt = idx;
maxDist = distSq;
}
@ -177,7 +176,7 @@ void CRainSplashGenerator::AddPoint(const zeus::CVector3f& pos) {
x38_queueTail += 1;
}
void CRainSplashGenerator::GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
void CRainSplashGenerator::GeneratePoints(const SSkinningWorkspace& workspace) {
if (!x48_25_raining)
return;
@ -185,8 +184,8 @@ void CRainSplashGenerator::GeneratePoints(const std::vector<std::pair<zeus::CVec
for (u32 i = 0; i < x44_genRate; ++i) {
if (x40_queueSize >= x0_rainSplashes.size())
break;
x34_curPoint = GetNextBestPt(x34_curPoint, vn, x10_random, x2c_minZ);
AddPoint(x14_scale * vn[x34_curPoint].first);
x34_curPoint = GetNextBestPt(x34_curPoint, workspace, x10_random, x2c_minZ);
AddPoint(x14_scale * workspace.m_vertexWorkspace[x34_curPoint]);
}
x20_generateTimer = 0.f;
}

View File

@ -7,6 +7,7 @@
#include "Runtime/RetroTypes.hpp"
#include "Runtime/rstl.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
#include <zeus/CVector3f.hpp>
@ -61,14 +62,13 @@ class CRainSplashGenerator {
void UpdateRainSplashRange(CStateManager& mgr, int start, int end, float dt);
void UpdateRainSplashes(CStateManager& mgr, float magnitude, float dt);
void DoDraw(const zeus::CTransform& xf);
static u32 GetNextBestPt(u32 pt, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn, CRandom16& rand,
float minZ);
static u32 GetNextBestPt(u32 pt, const SSkinningWorkspace& workspace, CRandom16& rand, float minZ);
void AddPoint(const zeus::CVector3f& pos);
public:
CRainSplashGenerator(const zeus::CVector3f& scale, u32 maxSplashes, u32 genRate, float minZ, float alpha);
void Update(float dt, CStateManager& mgr);
void GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
void GeneratePoints(const SSkinningWorkspace& workspace);
void Draw(const zeus::CTransform& xf);
bool IsRaining() const { return x48_25_raining; }
};

View File

@ -4,13 +4,17 @@
#include "Runtime/Graphics/CVertexMorphEffect.hpp"
#include <logvisor/logvisor.hpp>
#include <list>
namespace metaforce {
static logvisor::Module Log("metaforce::CSkinnedModel");
CSkinnedModel::CSkinnedModel(const TLockedToken<CModel>& model, const TLockedToken<CSkinRules>& skinRules,
const TLockedToken<CCharLayoutInfo>& layoutInfo)
: x4_model(std::move(model)), x10_skinRules(std::move(skinRules)), x1c_layoutInfo(std::move(layoutInfo)) {
: x4_model(std::move(model))
, x10_skinRules(std::move(skinRules))
, x1c_layoutInfo(std::move(layoutInfo))
, m_workspace(*x10_skinRules) {
if (!x4_model) {
Log.report(logvisor::Fatal, FMT_STRING("bad model token provided to CSkinnedModel"));
}
@ -26,32 +30,36 @@ CSkinnedModel::CSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinR
: CSkinnedModel(store.GetObj(SObjectTag{FOURCC('CMDL'), model}), store.GetObj(SObjectTag{FOURCC('CSKR'), skinRules}),
store.GetObj(SObjectTag{FOURCC('CINF'), layoutInfo})) {}
void CSkinnedModel::Calculate(const CPoseAsTransforms& pose, const std::optional<CVertexMorphEffect>& morphEffect,
const float* morphMagnitudes) {
// TODO
// if (morphEffect || g_PointGenFunc) {
// if (boo::ObjToken<boo::IGraphicsBufferD> vertBuf = m_modelInst->UpdateUniformData(drawFlags, nullptr, nullptr))
// {
// x10_skinRules->TransformVerticesCPU(m_vertWorkspace, pose, *x4_model);
// if (morphEffect)
// morphEffect->MorphVertices(m_vertWorkspace, morphMagnitudes, x10_skinRules, pose);
// if (g_PointGenFunc)
// g_PointGenFunc(g_PointGenCtx, m_vertWorkspace);
// x4_model->ApplyVerticesCPU(vertBuf, m_vertWorkspace);
// m_modifiedVBO = true;
// }
// } else {
// if (boo::ObjToken<boo::IGraphicsBufferD> vertBuf =
// m_modelInst->UpdateUniformData(drawFlags, x10_skinRules.GetObj(), &pose)) {
// if (m_modifiedVBO) {
// x4_model->RestoreVerticesCPU(vertBuf);
// m_modifiedVBO = false;
// }
// }
// }
void CSkinnedModel::AllocateStorage() {
if (x34_owned) {
m_workspace.Reset(*x10_skinRules);
}
}
void CSkinnedModel::Draw(TVectorRef verts, TVectorRef norms, const CModelFlags& drawFlags) {
void CSkinnedModel::Calculate(const CPoseAsTransforms& pose, const std::optional<CVertexMorphEffect>& morphEffect,
TConstVectorRef morphMagnitudes, SSkinningWorkspace* workspace) {
if (workspace == nullptr) {
if (x35_disableWorkspaces) {
x10_skinRules->BuildAccumulatedTransforms(pose, *x1c_layoutInfo);
return;
}
AllocateStorage();
workspace = &m_workspace;
}
x10_skinRules->BuildAccumulatedTransforms(pose, *x1c_layoutInfo);
x10_skinRules->BuildPoints(x4_model->GetPositions(), &workspace->m_vertexWorkspace);
x10_skinRules->BuildNormals(x4_model->GetNormals(), &workspace->m_normalWorkspace);
if (morphEffect) {
morphEffect->MorphVertices(*workspace, morphMagnitudes, x10_skinRules, pose);
}
if (g_PointGenFunc != nullptr) {
g_PointGenFunc(*workspace);
}
}
void CSkinnedModel::Draw(TConstVectorRef verts, TConstVectorRef norms, const CModelFlags& drawFlags) {
OPTICK_EVENT();
x4_model->Draw(verts, norms, drawFlags);
// PostDrawFunc();
@ -63,10 +71,10 @@ void CSkinnedModel::Draw(const CModelFlags& drawFlags) {
CGraphics::SetModelMatrix(mtx * x10_skinRules->x0_bones.front().x20_xf);
x4_model->Draw(drawFlags);
CGraphics::SetModelMatrix(mtx);
} else if (x24_vertWorkspace.empty()) {
} else if (m_workspace.IsEmpty()) {
x4_model->Draw(drawFlags);
} else {
x4_model->Draw(&x24_vertWorkspace, &x2c_normalWorkspace, drawFlags);
x4_model->Draw(&m_workspace.m_vertexWorkspace, &m_workspace.m_normalWorkspace, drawFlags);
// PostDrawFunc();
}
}
@ -77,19 +85,49 @@ void CSkinnedModel::DoDrawCallback(const FCustomDraw& func) const {
CGraphics::SetModelMatrix(mtx * x10_skinRules->x0_bones.front().x20_xf);
func(x4_model->GetPositions(), x4_model->GetNormals());
CGraphics::SetModelMatrix(mtx);
} else if (x24_vertWorkspace.empty()) {
} else if (m_workspace.IsEmpty()) {
func(x4_model->GetPositions(), x4_model->GetNormals());
} else {
func(&x24_vertWorkspace, &x2c_normalWorkspace);
func(&m_workspace.m_vertexWorkspace, &m_workspace.m_normalWorkspace);
// PostDrawFunc();
}
}
CMorphableSkinnedModel::CMorphableSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules,
CAssetId layoutInfo)
: CSkinnedModel(store, model, skinRules, layoutInfo) {}
: CSkinnedModel(store, model, skinRules, layoutInfo) {
const auto vertexCount = GetSkinRules()->GetVertexCount();
const auto& modelPositions = *GetModel()->GetPositions();
CSkinnedModel::FPointGenerator CSkinnedModel::g_PointGenFunc = nullptr;
void* CSkinnedModel::g_PointGenCtx = nullptr;
x40_morphMagnitudes.resize(vertexCount);
std::vector<std::pair<zeus::CVector3f, std::list<u32>>> vertMap;
for (int vertIdx = 0; vertIdx < vertexCount; ++vertIdx) {
const auto curPos = modelPositions[vertIdx];
if (std::find_if(vertMap.cbegin(), vertMap.cend(), [=](const auto& pair) { return pair.first.isEqu(curPos); }) ==
vertMap.cend()) {
auto& [_, list] = vertMap.emplace_back(curPos, std::list<u32>{});
for (int idx = vertIdx; idx < vertexCount; ++idx) {
// Originally uses ==, but adjusted to match above
if (modelPositions[idx].isEqu(curPos)) {
list.emplace_back(idx);
}
}
}
}
const auto& modelNormals = *GetModel()->GetNormals();
for (const auto& [_, idxs] : vertMap) {
zeus::CVector3f averagedNormal;
for (const auto idx : idxs) {
averagedNormal += modelNormals[idx];
}
averagedNormal.normalize();
for (const auto idx : idxs) {
x40_morphMagnitudes[idx] = averagedNormal;
}
}
}
FPointGenerator CSkinnedModel::g_PointGenFunc;
} // namespace metaforce

View File

@ -18,15 +18,32 @@ class CPoseAsTransforms;
class CVertexMorphEffect;
class IObjectStore;
// Originally vert + normal workspaces were allocated together, but here separated for ease of use
struct SSkinningWorkspace {
std::vector<zeus::CVector3f> m_vertexWorkspace;
std::vector<zeus::CVector3f> m_normalWorkspace;
SSkinningWorkspace(const CSkinRules& rules) { Reset(rules); }
void Reset(const CSkinRules& rules) {
m_vertexWorkspace.clear();
m_normalWorkspace.clear();
m_vertexWorkspace.reserve(rules.GetVertexCount());
m_normalWorkspace.reserve(rules.GetNormalCount());
}
[[nodiscard]] bool IsEmpty() const { return m_vertexWorkspace.empty() || m_normalWorkspace.empty(); }
};
// Lambda instead of userdata pointer
using FCustomDraw = std::function<void(TVectorRef positions, TVectorRef normals)>;
using FCustomDraw = std::function<void(TConstVectorRef positions, TConstVectorRef normals)>;
using FPointGenerator = std::function<void(const SSkinningWorkspace& workspace)>;
class CSkinnedModel {
TLockedToken<CModel> x4_model;
TLockedToken<CSkinRules> x10_skinRules;
TLockedToken<CCharLayoutInfo> x1c_layoutInfo;
std::vector<zeus::CVector3f> x24_vertWorkspace; // was rstl::auto_ptr<float[]>
std::vector<zeus::CVector3f> x2c_normalWorkspace; // was rstl::auto_ptr<float[]>
// rstl::auto_ptr<float[]> x24_vertWorkspace;
// rstl::auto_ptr<float[]> x2c_normalWorkspace;
SSkinningWorkspace m_workspace;
bool x34_owned = true;
bool x35_disableWorkspaces = false;
@ -42,28 +59,25 @@ public:
void SetLayoutInfo(const TLockedToken<CCharLayoutInfo>& inf) { x1c_layoutInfo = inf; }
const TLockedToken<CCharLayoutInfo>& GetLayoutInfo() const { return x1c_layoutInfo; }
void AllocateStorage();
void Calculate(const CPoseAsTransforms& pose, const std::optional<CVertexMorphEffect>& morphEffect,
const float* morphMagnitudes);
void Draw(TVectorRef verts, TVectorRef normals, const CModelFlags& drawFlags);
TConstVectorRef averagedNormals, SSkinningWorkspace* workspace);
void Draw(TConstVectorRef verts, TConstVectorRef normals, const CModelFlags& drawFlags);
void Draw(const CModelFlags& drawFlags);
void DoDrawCallback(const FCustomDraw& func) const;
using FPointGenerator = void (*)(void* item, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
static void SetPointGeneratorFunc(void* ctx, FPointGenerator func) {
g_PointGenFunc = func;
g_PointGenCtx = ctx;
}
static void SetPointGeneratorFunc(FPointGenerator func) { g_PointGenFunc = std::move(func); }
static void ClearPointGeneratorFunc() { g_PointGenFunc = nullptr; }
static FPointGenerator g_PointGenFunc;
static void* g_PointGenCtx;
};
class CMorphableSkinnedModel : public CSkinnedModel {
std::unique_ptr<float[]> x40_morphMagnitudes;
std::vector<zeus::CVector3f> x40_morphMagnitudes; // was rstl::auto_ptr<float[]>
public:
CMorphableSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules, CAssetId layoutInfo);
const float* GetMorphMagnitudes() const { return x40_morphMagnitudes.get(); }
TConstVectorRef GetMorphMagnitudes() const { return &x40_morphMagnitudes; }
TVectorRef GetMorphMagnitudes() { return &x40_morphMagnitudes; }
};
} // namespace metaforce

View File

@ -8,8 +8,8 @@ CVertexMorphEffect::CVertexMorphEffect(const zeus::CUnitVector3f& v1, const zeus
float f2, CRandom16& random)
: x0_(v1), x20_diagExtent(diagExtent), x24_random(random) {}
void CVertexMorphEffect::MorphVertices(std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
const float* magnitudes, const TLockedToken<CSkinRules>& skinRules,
const CPoseAsTransforms& pose) const {}
void CVertexMorphEffect::MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef magnitudes,
const TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose) const {
}
} // namespace metaforce
} // namespace metaforce

View File

@ -5,6 +5,7 @@
#include "Runtime/CToken.hpp"
#include "Runtime/Character/CPoseAsTransforms.hpp"
#include "Runtime/Graphics/CCubeModel.hpp"
#include <zeus/CUnitVector.hpp>
#include <zeus/CVector3f.hpp>
@ -12,6 +13,7 @@
namespace metaforce {
class CRandom16;
class CSkinRules;
struct SSkinningWorkspace;
class CVertexMorphEffect {
zeus::CUnitVector3f x0_;
@ -28,7 +30,7 @@ class CVertexMorphEffect {
public:
CVertexMorphEffect(const zeus::CUnitVector3f& v1, const zeus::CVector3f& v2, float diagExtent, float f2,
CRandom16& random);
void MorphVertices(std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn, const float* magnitudes,
void MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef magnitudes,
const TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose) const;
void Reset(const zeus::CVector3f& dir, const zeus::CVector3f& pos, float duration) {}
void Update(float) {}

View File

@ -93,9 +93,9 @@ public:
virtual void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) = 0;
virtual void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) = 0;
virtual void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TVectorRef positions, TVectorRef normals, const CModelFlags& flags) = 0;
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) = 0;
virtual void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TVectorRef positions, TVectorRef normals) = 0;
TConstVectorRef positions, TConstVectorRef normals) = 0;
virtual void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) = 0;
virtual void SetWireframeFlags(s32 flags) = 0;
virtual void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) = 0;

View File

@ -501,10 +501,6 @@ void CGrappleArm::RenderXRayModel(const CStateManager& mgr, const zeus::CTransfo
// CGraphics::DisableAllLights();
}
void CGrappleArm::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
static_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
}
void CGrappleArm::Render(const CStateManager& mgr, const zeus::CVector3f& pos, const CModelFlags& flags,
const CActorLights* lights) {
if (!x3b2_24_active || x3b2_29_suitLoading) {
@ -528,7 +524,8 @@ void CGrappleArm::Render(const CStateManager& mgr, const zeus::CVector3f& pos, c
}
if (x3a4_rainSplashGenerator && x3a4_rainSplashGenerator->IsRaining()) {
CSkinnedModel::SetPointGeneratorFunc(x3a4_rainSplashGenerator.get(), PointGenerator);
CSkinnedModel::SetPointGeneratorFunc(
[&](const auto& workspace) { x3a4_rainSplashGenerator->GeneratePoints(workspace); });
}
x0_grappleArmModel->Render(mgr, modelXf, useLights, useFlags);

View File

@ -102,8 +102,6 @@ private:
void UpdateSwingAction(float grappleSwingT, float dt, CStateManager& mgr);
void RenderXRayModel(const CStateManager& mgr, const zeus::CTransform& modelXf, const CModelFlags& flags);
static void PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
public:
explicit CGrappleArm(const zeus::CVector3f& scale);
void AsyncLoadSuit(CStateManager& mgr);

View File

@ -250,10 +250,6 @@ void CGunWeapon::TouchHolo(const CStateManager& mgr) {
x60_holoModelData->Touch(mgr, 0);
}
void CGunWeapon::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
static_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
}
void CGunWeapon::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::CTransform& xf, const CModelFlags& flags,
const CActorLights* lights) {
if (!x218_26_loaded)
@ -262,7 +258,8 @@ void CGunWeapon::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::CT
zeus::CTransform armXf = xf * x10_solidModelData->GetScaledLocatorTransform("elbow");
if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining())
CSkinnedModel::SetPointGeneratorFunc(x1bc_rainSplashGenerator, PointGenerator);
CSkinnedModel::SetPointGeneratorFunc(
[&](const auto& workspace) { x1bc_rainSplashGenerator->GeneratePoints(workspace); });
if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x200_beamId != CPlayerState::EBeamId::Ice) {
/* Hot Draw */

View File

@ -102,8 +102,6 @@ protected:
void LockTokens(CStateManager& mgr);
void UnlockTokens();
static void PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
public:
CGunWeapon(CAssetId ancsId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial,
const zeus::CVector3f& scale);

View File

@ -30,14 +30,14 @@ CActorModelParticles::CItem::CItem(const CEntity& ent, CActorModelParticles& par
x8_onFireGens.resize(8);
}
static s32 GetNextBestPt(s32 start, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
CRandom16& rnd) {
const zeus::CVector3f& startVec = vn[start].first;
static s32 GetNextBestPt(s32 start, const SSkinningWorkspace& workspace, CRandom16& rnd) {
const auto& verts = workspace.m_vertexWorkspace;
const zeus::CVector3f& startVec = verts[start];
s32 ret = start;
float maxMag = 0.f;
for (s32 i = 0; i < 10; ++i) {
s32 idx = rnd.Range(0, s32(vn.size()) - 1);
const zeus::CVector3f& rndVec = vn[idx].first;
s32 idx = rnd.Range(0, s32(verts.size()) - 1);
const zeus::CVector3f& rndVec = verts[idx];
float mag = (startVec - rndVec).magSquared();
if (mag > maxMag) {
ret = idx;
@ -46,11 +46,15 @@ static s32 GetNextBestPt(s32 start, const std::vector<std::pair<zeus::CVector3f,
}
return ret;
}
void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
void CActorModelParticles::CItem::GeneratePoints(const SSkinningWorkspace& workspace) {
const auto& verts = workspace.m_vertexWorkspace;
const auto& norms = workspace.m_normalWorkspace;
for (std::pair<std::unique_ptr<CElementGen>, u32>& pair : x8_onFireGens) {
if (pair.first) {
CRandom16 rnd(pair.second);
const zeus::CVector3f& vec = vn[rnd.Float() * (vn.size() - 1)].first;
const zeus::CVector3f& vec = verts[rnd.Float() * (verts.size() - 1)];
pair.first->SetTranslation(xec_particleOffsetScale * vec);
}
}
@ -60,9 +64,9 @@ void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeu
s32 count = (x84_ashMaxParticles >= 16 ? 16 : x84_ashMaxParticles);
s32 idx = x80_ashPointIterator;
for (u32 i = 0; i < count; ++i) {
idx = GetNextBestPt(idx, vn, rnd);
x78_ashGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
zeus::CVector3f v = vn[idx].second;
idx = GetNextBestPt(idx, workspace, rnd);
x78_ashGen->SetTranslation(xec_particleOffsetScale * verts[idx]);
zeus::CVector3f v = norms[idx];
if (v.canBeNormalized()) {
v.normalize();
x78_ashGen->SetOrientation(zeus::CTransform{v.cross(zeus::skUp), v, zeus::skUp, zeus::skZero3f});
@ -80,10 +84,10 @@ void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeu
std::unique_ptr<CElementGen> iceGen = x128_parent.MakeIceGen();
iceGen->SetGlobalOrientAndTrans(xf8_iceXf);
s32 idx = GetNextBestPt(xb0_icePointIterator, vn, rnd);
iceGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
s32 idx = GetNextBestPt(xb0_icePointIterator, workspace, rnd);
iceGen->SetTranslation(xec_particleOffsetScale * verts[idx]);
iceGen->SetOrientation(zeus::CTransform::MakeRotationsBasedOnY(zeus::CUnitVector3f(vn[idx].second)));
iceGen->SetOrientation(zeus::CTransform::MakeRotationsBasedOnY(zeus::CUnitVector3f(norms[idx])));
x8c_iceGens.push_back(std::move(iceGen));
xb0_icePointIterator = (x8c_iceGens.size() == 4 ? -1 : idx);
@ -98,9 +102,9 @@ void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeu
#endif
s32 idx = xc8_electricPointIterator;
for (u32 i = 0; i < end; ++i) {
xc0_electricGen->SetOverrideIPos(vn[rnd.Range(0, s32(vn.size()) - 1)].first * xec_particleOffsetScale);
idx = rnd.Range(0, s32(vn.size()) - 1);
xc0_electricGen->SetOverrideFPos(vn[idx].first * xec_particleOffsetScale);
xc0_electricGen->SetOverrideIPos(verts[rnd.Range(0, s32(verts.size()) - 1)] * xec_particleOffsetScale);
idx = rnd.Range(0, s32(verts.size()) - 1);
xc0_electricGen->SetOverrideFPos(verts[idx] * xec_particleOffsetScale);
xc0_electricGen->ForceParticleCreation(1);
}
@ -109,7 +113,7 @@ void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeu
}
if (xd4_rainSplashGen)
xd4_rainSplashGen->GeneratePoints(vn);
xd4_rainSplashGen->GeneratePoints(workspace);
}
bool CActorModelParticles::CItem::UpdateOnFire(float dt, CActor* actor, CStateManager& mgr) {
@ -516,19 +520,12 @@ void CActorModelParticles::Update(float dt, CStateManager& mgr) {
}
}
void CActorModelParticles::PointGenerator(void* ctx,
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
static_cast<CItem*>(ctx)->GeneratePoints(vn);
}
void CActorModelParticles::SetupHook(TUniqueId uid) {
const auto search = FindSystem(uid);
if (search == x0_items.cend()) {
return;
}
CSkinnedModel::SetPointGeneratorFunc(&*search, PointGenerator);
CSkinnedModel::SetPointGeneratorFunc([=](const auto& workspace) { search->GeneratePoints(workspace); });
}
std::list<CActorModelParticles::CItem>::iterator CActorModelParticles::FindSystem(TUniqueId uid) {
@ -622,7 +619,7 @@ void CActorModelParticles::LightDudeOnFire(CActor& act) {
const CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend() && iter->xdc_ashy && iter->xdc_ashy.IsLoaded()) {
// iter->xdc_ashy->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge);
// iter->xdc_ashy->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge);
return iter->xdc_ashy.GetObj();
}
return nullptr;

View File

@ -71,7 +71,7 @@ public:
public:
CItem(const CEntity& ent, CActorModelParticles& parent);
void GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
void GeneratePoints(const SSkinningWorkspace& workspace);
bool Update(float dt, CStateManager& mgr);
void Lock(EDependency i);
void Unlock(EDependency i);
@ -150,7 +150,6 @@ private:
public:
CActorModelParticles();
static void PointGenerator(void* item, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
void AddStragglersToRenderer(const CStateManager& mgr);
void Update(float dt, CStateManager& mgr);
void SetupHook(TUniqueId uid);

View File

@ -1657,10 +1657,6 @@ void CMorphBall::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
}
}
void CMorphBall::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
static_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
}
void CMorphBall::Render(const CStateManager& mgr, const CActorLights* lights) const {
SCOPED_GRAPHICS_DEBUG_GROUP("CPlayer::Render", zeus::skPurple);
zeus::CTransform ballToWorld = GetBallToWorld();
@ -1685,7 +1681,8 @@ void CMorphBall::Render(const CStateManager& mgr, const CActorLights* lights) co
// flags.m_extendedShader = EExtendedShader::LightingCubeReflection;
if (x1c1c_rainSplashGen && x1c1c_rainSplashGen->IsRaining()) {
CSkinnedModel::SetPointGeneratorFunc(x1c1c_rainSplashGen.get(), PointGenerator);
CSkinnedModel::SetPointGeneratorFunc(
[&](const auto& workspace) { x1c1c_rainSplashGen->GeneratePoints(workspace); });
}
if (x1c34_boostLightFactor != 1.f) {

View File

@ -170,7 +170,6 @@ private:
static zeus::CVector3f TransformSpiderBallForcesXY(const zeus::CVector2f& forces, CStateManager& mgr);
static zeus::CVector3f TransformSpiderBallForcesXZ(const zeus::CVector2f& forces, CStateManager& mgr);
void ResetSpiderBallForces();
static void PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
public:
CMorphBall(CPlayer& player, float radius);

View File

@ -416,7 +416,7 @@ void CSnakeWeedSwarm::RenderBoid(u32 idx, const CBoid& boid, u32& posesToBuild)
if (posesToBuild & 1 << modelIdx) {
posesToBuild &= ~(1 << modelIdx);
animData.BuildPose();
model.Calculate(animData.GetPose(), std::nullopt, nullptr);
model.Calculate(animData.GetPose(), std::nullopt, nullptr, nullptr); // TODO x178_workspaces[modelIdx]
}
CGraphics::SetModelMatrix(
zeus::CTransform::Translate(boid.GetPosition() - zeus::CVector3f(0.f, 0.f, boid.GetZOffset())) *