DolphinCSkinnedModel 99% & CSkinnedModelWithAvgNormals 96% (#51)

This commit is contained in:
Luke Street
2026-03-27 14:25:32 -06:00
committed by GitHub
parent fed052c678
commit cef20ccefe
12 changed files with 481 additions and 54 deletions
+22 -22
View File
@@ -14820,21 +14820,21 @@ Initialize__14CGameAllocatorFR10COsContext = .text:0x803521BC; // type:function
__dt__14CGameAllocatorFv = .text:0x80352544; // type:function size:0x88 scope:global
__ct__14CGameAllocatorFv = .text:0x803525CC; // type:function size:0x94 scope:global
GetMemInfoFromBlockPtr__14CGameAllocatorCFPCv = .text:0x80352660; // type:function size:0x8 scope:global
fn_80352668 = .text:0x80352668; // type:function size:0xA0
AllocateNewWorkspace__13CSkinnedModelFPPf = .text:0x80352668; // type:function size:0xA0 scope:global
ClearPointGeneratorFunc__13CSkinnedModelFv = .text:0x80352708; // type:function size:0xC scope:global
SetPointGeneratorFunc__13CSkinnedModelFPvPFPvPC9CVector3fPC9CVector3fi_v = .text:0x80352714; // type:function size:0xC scope:global
RemoveDummySkinnedModelRef__13CSkinnedModelFv = .text:0x80352720; // type:function size:0x20
fn_80352740 = .text:0x80352740; // type:function size:0x20
fn_80352760 = .text:0x80352760; // type:function size:0x10C
AddDummySkinnedModelRef__13CSkinnedModelFv = .text:0x80352740; // type:function size:0x20
PostDrawFunc__13CSkinnedModelCFv = .text:0x80352760; // type:function size:0x10C
AllocateStorage__13CSkinnedModelFv = .text:0x8035286C; // type:function size:0x180 scope:global
EnsureAllocation__13CSkinnedModelFi = .text:0x803529EC; // type:function size:0x184 scope:global
TickAllocations__13CSkinnedModelFv = .text:0x80352B70; // type:function size:0xA8 scope:global
CalculateDefault__13CSkinnedModelFv = .text:0x80352C18; // type:function size:0xE0 scope:global
Calculate__13CSkinnedModelFRC17CPoseAsTransformsRCQ24rstl37optional_object<18CVertexMorphEffect>PCfPf = .text:0x80352CF8; // type:function size:0x1F0 scope:global
fn_80352EE8 = .text:0x80352EE8; // type:function size:0x38
DoDrawCallback__13CSkinnedModelF14FCustomDrawCPv = .text:0x80352F20; // type:function size:0x144 scope:global
fn_80353064 = .text:0x80353064; // type:function size:0xBC
fn_80353120 = .text:0x80353120; // type:function size:0x15C
Draw__13CSkinnedModelCFPCfPCfRC11CModelFlags = .text:0x80352EE8; // type:function size:0x38 scope:global
DoDrawCallback__13CSkinnedModelFPFPCfPCfPCv_vPv = .text:0x80352F20; // type:function size:0x144 scope:global
Draw__13CSkinnedModelCFRC11CModelFlags = .text:0x80353064; // type:function size:0xBC scope:global
Construct__13CSkinnedModelFv = .text:0x80353120; // type:function size:0x15C
__dt__13CSkinnedModelFv = .text:0x8035327C; // type:function size:0xE8 scope:global
__ct__13CSkinnedModelFRC13CSkinnedModel = .text:0x80353364; // type:function size:0xD4 scope:global
__ct__13CSkinnedModelFRC21TLockedToken<6CModel>RC26TLockedToken<10CSkinRules>RC31TLockedToken<15CCharLayoutInfo>Q213CSkinnedModel14EDataOwnership = .text:0x80353438; // type:function size:0xD4 scope:global
@@ -14848,7 +14848,7 @@ ProcessingNormals__10CSkinRulesFiPPUs = .text:0x803538F4; // type:function size:
ProcessingPoints__10CSkinRulesFiPPUs = .text:0x803539F0; // type:function size:0xFC scope:global
WaitForQueue__Fv = .text:0x80353AEC; // type:function size:0x30 scope:global
StartNextTransaction__10CSkinRulesFv = .text:0x80353B1C; // type:function size:0xF8 scope:global
InitLockedCacheState__10CSkinRulesFRC10CSkinRules = .text:0x80353C14; // type:function size:0x50 scope:global
InitLockedCacheState__10CSkinRulesFRC6CModel = .text:0x80353C14; // type:function size:0x50 scope:global
FSkinRulesFactory__FRC10SObjectTagR12CInputStreamRC15CVParamTransfer = .text:0x80353C64; // type:function size:0xE0 scope:global
__dt__20TToken<10CSkinRules>Fv = .text:0x80353D44; // type:function size:0x90 scope:global
GetIObjObjectFor__20TToken<10CSkinRules>FRCQ24rstl22auto_ptr<10CSkinRules> = .text:0x80353DD4; // type:function size:0x2C scope:global
@@ -14936,17 +14936,17 @@ Reset__18CVertexMorphEffectFRC13CUnitVector3fRC9CVector3ff = .text:0x803574E0; /
MorphVertices__18CVertexMorphEffectCFP9CVector3fPC9CVector3fRC26TLockedToken<10CSkinRules>RC17CPoseAsTransformsUi = .text:0x80357598; // type:function size:0x3D4 scope:global
Update__18CVertexMorphEffectFf = .text:0x8035796C; // type:function size:0x38 scope:global
__ct__27CSkinnedModelWithAvgNormalsFRC13CSkinnedModel = .text:0x803579A4; // type:function size:0x35C scope:global
fn_80357D00 = .text:0x80357D00; // type:function size:0x7C
fn_80357D7C = .text:0x80357D7C; // type:function size:0x28
fn_80357DA4 = .text:0x80357DA4; // type:function size:0x54
fn_80357DF8 = .text:0x80357DF8; // type:function size:0x98
fn_80357E90 = .text:0x80357E90; // type:function size:0xB4
fn_80357F44 = .text:0x80357F44; // type:function size:0x8C
fn_80357FD0 = .text:0x80357FD0; // type:function size:0x50
fn_80358020 = .text:0x80358020; // type:function size:0x7C
fn_8035809C = .text:0x8035809C; // type:function size:0x78
push_back__Q24rstl105vector<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>FRCQ24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>> = .text:0x80357D00; // type:function size:0x7C scope:weak
construct<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>>__4rstlFPvRCQ24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>> = .text:0x80357D7C; // type:function size:0x28
__ct__Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>FRCQ24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>> = .text:0x80357DA4; // type:function size:0x54 scope:weak
__ct__Q24rstl35list<Ui,Q24rstl17rmemory_allocator>FRCQ24rstl35list<Ui,Q24rstl17rmemory_allocator> = .text:0x80357DF8; // type:function size:0x98 scope:weak
insert<Q34rstl35list<Ui,Q24rstl17rmemory_allocator>14const_iterator>__Q24rstl35list<Ui,Q24rstl17rmemory_allocator>FRCQ34rstl35list<Ui,Q24rstl17rmemory_allocator>8iteratorQ34rstl35list<Ui,Q24rstl17rmemory_allocator>14const_iteratorQ34rstl35list<Ui,Q24rstl17rmemory_allocator>14const_iterator = .text:0x80357E90; // type:function size:0xB4
__dt__Q34rstl35list<Ui,Q24rstl17rmemory_allocator>14destroy_helperFv = .text:0x80357F44; // type:function size:0x8C scope:weak
__ct__Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>FRC9CVector3fRCQ24rstl35list<Ui,Q24rstl17rmemory_allocator> = .text:0x80357FD0; // type:function size:0x50 scope:weak
do_erase__Q24rstl35list<Ui,Q24rstl17rmemory_allocator>FPQ34rstl35list<Ui,Q24rstl17rmemory_allocator>4node = .text:0x80358020; // type:function size:0x7C scope:weak
__dt__Q24rstl35list<Ui,Q24rstl17rmemory_allocator>Fv = .text:0x8035809C; // type:function size:0x78 scope:weak
reserve__Q24rstl105vector<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>Fi = .text:0x80358114; // type:function size:0xE0 scope:global
fn_803581F4 = .text:0x803581F4; // type:function size:0x68
uninitialized_copy<Q24rstl231pointer_iterator<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl105vector<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,PQ24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>>__4rstlFQ24rstl231pointer_iterator<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl105vector<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl231pointer_iterator<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl105vector<Q24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>PQ24rstl61pair<9CVector3f,Q24rstl35list<Ui,Q24rstl17rmemory_allocator>> = .text:0x803581F4; // type:function size:0x68
__dt__13CTimeProviderFv = .text:0x8035825C; // type:function size:0x78 scope:global
__ct__13CTimeProviderFRCf = .text:0x803582D4; // type:function size:0x60 scope:global
GetMRAMSafe__10CARAMTokenFv = .text:0x80358334; // type:function size:0x54 scope:global
@@ -17838,7 +17838,7 @@ lbl_803D8220 = .rodata:0x803D8220; // type:object size:0x7 data:string
@stringBase0 = .rodata:0x803D8230; // type:object size:0xD scope:local data:string_table
lbl_803D8240 = .rodata:0x803D8240; // type:object size:0x7 data:string
lbl_803D8248 = .rodata:0x803D8248; // type:object size:0xB0
lbl_803D82F8 = .rodata:0x803D82F8; // type:object size:0x7 data:string
@stringBase0 = .rodata:0x803D82F8; // type:object size:0x7 scope:local data:string_table
lbl_803D8300 = .rodata:0x803D8300; // type:object size:0x7 data:string
lbl_803D8308 = .rodata:0x803D8308; // type:object size:0x7 data:string
skInvalidString = .rodata:0x803D8310; // type:object size:0x10 scope:local data:wstring
@@ -22173,12 +22173,12 @@ lbl_805A95E4 = .sbss:0x805A95E4; // type:object size:0x4 data:4byte
lbl_805A95E8 = .sbss:0x805A95E8; // type:object size:0x1 data:byte
lbl_805A95E9 = .sbss:0x805A95E9; // type:object size:0x1 data:byte
lbl_805A95EA = .sbss:0x805A95EA; // type:object size:0x6 data:byte
lbl_805A95F0 = .sbss:0x805A95F0; // type:object size:0x4 data:4byte
lbl_805A95F4 = .sbss:0x805A95F4; // type:object size:0x4 data:4byte
sPointGen__13CSkinnedModel = .sbss:0x805A95F0; // type:object size:0x4 scope:global data:4byte
sPointGenData__13CSkinnedModel = .sbss:0x805A95F4; // type:object size:0x4 scope:global data:4byte
skCurrentToken__8Skinning = .sbss:0x805A95F8; // type:object size:0x2 data:2byte
sNumSkinnedObjects__8Skinning = .sbss:0x805A95FC; // type:object size:0x4 data:4byte
sSkinningInitialized__8Skinning = .sbss:0x805A9600; // type:object size:0x1 data:byte
lbl_805A9601 = .sbss:0x805A9601; // type:object size:0x7 data:byte
sbDumpedSpinLockMessage__8Skinning = .sbss:0x805A9601; // type:object size:0x1 scope:local data:byte
lbl_805A9608 = .sbss:0x805A9608; // type:object size:0x1 data:byte
lbl_805A960C = .sbss:0x805A960C; // type:object size:0x1 data:byte
lbl_805A9610 = .sbss:0x805A9610; // type:object size:0x4 data:4byte
+12
View File
@@ -3,14 +3,26 @@
#include "Kyoto/Animation/CVirtualBone.hpp"
class CCharLayoutInfo;
class CInputStream;
class CModel;
class CPoseAsTransforms;
class CSkinRules {
public:
CSkinRules(CInputStream& in);
~CSkinRules();
void InitLockedCacheState(const CModel& model);
void BuildAccumulatedTransforms(const CPoseAsTransforms& pose,
const CCharLayoutInfo& layoutInfo) const;
void BuildPoints(volatile void* pipe) const;
void BuildNormals(volatile void* pipe) const;
void BuildNormalsFrom(const CVector3f* averageNormals, CVector3f* out) const;
uint GetNumPoints() const { return x10_vertexCount; }
uint GetNumNormals() const { return x14_normalCount; }
int GetNumVirtualBones() const { return x0_virtualBones.size(); }
const rstl::vector< CVirtualBone >& GetVirtualBones() const { return x0_virtualBones; }
private:
rstl::vector< CVirtualBone > x0_virtualBones;
+24 -7
View File
@@ -3,6 +3,7 @@
#include "types.h"
#include "Kyoto/Animation/CSkinRules.hpp"
#include "Kyoto/TToken.hpp"
#include "rstl/auto_ptr.hpp"
@@ -10,12 +11,13 @@
class CModel;
class CModelFlags;
class CSkinRules;
class CCharLayoutInfo;
class CPoseAsTransforms;
class CVector3f;
class CVertexMorphEffect;
typedef void (*TDrawFunc)(const float*, const float*, const void*);
class CSkinnedModel {
public:
enum EDataOwnership {
@@ -33,34 +35,49 @@ public:
const TLockedToken< CCharLayoutInfo >& GetLayoutInfo() const { return x1c_layoutInfo; }
void CalculateDefault();
int GetNumPoints() const;
int GetNumPoints() const { return x10_skinRules->GetNumPoints(); }
const CVector3f* GetPositions() const;
void Calculate(const CPoseAsTransforms&, const rstl::optional_object< CVertexMorphEffect >&,
const float*, float*);
void Draw(const CModelFlags&) const;
void Draw(const float* positions, const float* normals, const CModelFlags& flags) const;
void DoDrawCallback(TDrawFunc func, void* data);
void PostDrawFunc() const;
float* AllocateNewWorkspace(float** vertOut);
static void SetPointGeneratorFunc(void*, void (*)(void*, const CVector3f*, const CVector3f*, int));
static void ClearPointGeneratorFunc();
static void AddDummySkinnedModelRef();
static void RemoveDummySkinnedModelRef();
void Construct();
void AllocateStorage();
static void TickAllocations();
static void* EnsureAllocation(int size);
typedef void (*TPointGenFunc)(void*, const CVector3f*, const CVector3f*, int);
static TPointGenFunc sPointGen;
static void* sPointGenData;
private:
TLockedToken< CModel > x4_model;
TLockedToken< CSkinRules > x10_skinRules;
TLockedToken< CCharLayoutInfo > x1c_layoutInfo;
rstl::auto_ptr< float[] > x28_vertWorkspace;
rstl::auto_ptr< float[] > x30_normalWorkspace;
mutable rstl::auto_ptr< float > x28_vertWorkspace;
mutable rstl::auto_ptr< float > x30_normalWorkspace;
bool x38_owned;
bool x39_disableWorkspaces;
};
class CSkinnedModelWithAvgNormals {
CSkinnedModel x0_skinnedModel;
uchar x3c_pad[4];
const float* x40_avgNormals;
rstl::auto_ptr< float > x3c_avgNormals;
public:
CSkinnedModelWithAvgNormals(const CSkinnedModel& model);
const CSkinnedModel& GetSkinnedModel() const { return x0_skinnedModel; }
const float* GetAvgNormals() const { return x40_avgNormals; }
float* GetAvgNormals() const { return x3c_avgNormals.get(); }
};
#endif // _CSKINNEDMODEL
+1
View File
@@ -17,6 +17,7 @@ public:
explicit CVirtualBone(CInputStream& in);
const rstl::reserved_vector< SSkinWeighting, 3 >& GetWeights() const { return x0_weights; }
uint GetVertexCount() const { return x1c_vertexCount; }
const CTransform4f& GetTransform() const { return x20_xf; }
void BuildPoints(const ushort*, volatile void*, int) const;
void BuildNormals(const ushort*, volatile void*, int) const;
+1
View File
@@ -30,6 +30,7 @@ public:
CModel(const rstl::auto_ptr< uchar >& data, int length, IObjectStore& store);
void Touch(int) const;
void Draw(const CModelFlags&) const;
void Draw(const float* positions, const float* normals, const CModelFlags& flags) const;
bool IsLoaded(int matIdx) const;
const float* GetPositions() const;
const float* GetNormals() const;
+2
View File
@@ -29,6 +29,8 @@ void GXInitFifoLimits(GXFifoObj* fifo, u32 hiWaterMark, u32 loWaterMark);
GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb);
void GXEnableBreakPt(void* breakPt);
void GXDisableBreakPt(void);
volatile void* GXRedirectWriteGatherPipe(void* buf);
void GXRestoreWriteGatherPipe(void);
#ifdef __cplusplus
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef _RSTL_ALLOCATOR_AUTO_PTR
#define _RSTL_ALLOCATOR_AUTO_PTR
#include "types.h"
namespace rstl {
template < typename T, typename Alloc >
struct allocator_auto_ptr {
allocator_auto_ptr(T* ptr, Alloc* alloc) : x0_ptr(ptr), x4_alloc(alloc) {}
~allocator_auto_ptr() {
if (x0_ptr != nullptr) {
x4_alloc->deallocate(x0_ptr);
x0_ptr = nullptr;
}
}
T* release() const {
T* ret = x0_ptr;
const_cast< allocator_auto_ptr* >(this)->x0_ptr = nullptr;
return ret;
}
private:
T* x0_ptr;
Alloc* x4_alloc;
};
} // namespace rstl
#endif // _RSTL_ALLOCATOR_AUTO_PTR
+57 -3
View File
@@ -12,7 +12,6 @@ class list {
public:
class iterator;
class const_iterator;
iterator erase(const iterator& item) { return do_erase(item.get_node()); }
// private:
#pragma pack(push, 1)
@@ -26,6 +25,33 @@ public:
, xc_empty_prev(reinterpret_cast< node* >(&xc_empty_prev))
, x10_empty_next(reinterpret_cast< node* >(&xc_empty_prev))
, x14_count(0) {}
struct destroy_helper {
destroy_helper(list* l) : x0_list(l), x4_active(true) {}
~destroy_helper() {
if (x4_active) {
x0_list->destroy();
}
}
void release() { x4_active = false; }
private:
list* x0_list;
bool x4_active;
};
list(const list& other)
: x0_allocator(other.x0_allocator)
, x4_start(reinterpret_cast< node* >(&xc_empty_prev))
, x8_end(reinterpret_cast< node* >(&xc_empty_prev))
, xc_empty_prev(reinterpret_cast< node* >(&xc_empty_prev))
, x10_empty_next(reinterpret_cast< node* >(&xc_empty_prev))
, x14_count(0) {
destroy_helper dh(this);
insert(end(), other.begin(), other.end());
dh.release();
}
~list();
node* do_erase(node* item);
@@ -36,6 +62,9 @@ public:
int size() const { return x14_count; }
bool empty() const { return x14_count == 0; }
T& front() { return *x4_start->get_value(); }
const T& front() const { return *x4_start->get_value(); }
void pop_front() { erase(x4_start); }
iterator begin() { return iterator(x4_start); }
@@ -43,6 +72,7 @@ public:
iterator end() { return iterator(x8_end); }
const_iterator end() const { return const_iterator(x8_end); }
iterator erase(const iterator& item) { return do_erase(item.get_node()); }
iterator erase(const iterator& start, const iterator& end) {
node* last = end.get_node();
node* it = start.get_node();
@@ -90,6 +120,30 @@ public:
return nn;
}
iterator insert(const iterator& pos, const T& val) {
do_insert_before(pos.get_node(), val);
return pos;
}
template < typename InputIterator >
void insert(const iterator& pos, InputIterator first, InputIterator last) {
node* cur = first.get_node();
while (cur != last.get_node()) {
do_insert_before(pos.get_node(), *cur->get_value());
cur = cur->get_next();
}
}
// TODO: demo map shows this delegates to clear(),
// but this matches better in CSkinnedModelWithAvgNormals
void destroy() {
node* end = x8_end;
node* it = x4_start;
while (it != end) {
it = do_erase(it);
}
}
void remove(const T& val);
// TODO non-matching
@@ -184,7 +238,7 @@ list< T, Alloc >::~list() {
node* it = cur;
node* next = cur->get_next();
cur = next;
destroy(it->get_value());
rstl::destroy(it->get_value());
x0_allocator.deallocate(it);
}
}
@@ -197,7 +251,7 @@ typename list< T, Alloc >::node* list< T, Alloc >::do_erase(node* node) {
}
node->get_prev()->set_next(node->get_next());
node->get_next()->set_prev(node->get_prev());
destroy(node->get_value());
rstl::destroy(node->get_value());
x0_allocator.deallocate(node);
x14_count--;
return result;
+1 -20
View File
@@ -3,6 +3,7 @@
#include "types.h"
#include "rstl/allocator_auto_ptr.hpp"
#include "rstl/iterator.hpp"
#include "rstl/pointer_iterator.hpp"
#include "rstl/rmemory_allocator.hpp"
@@ -10,26 +11,6 @@
class CInputStream;
namespace rstl {
template < typename T, typename Alloc >
struct allocator_auto_ptr {
allocator_auto_ptr(T* ptr, Alloc* alloc) : x0_ptr(ptr), x4_alloc(alloc) {}
~allocator_auto_ptr() {
if (x0_ptr != nullptr) {
x4_alloc->deallocate(x0_ptr);
x0_ptr = nullptr;
}
}
T* release() const {
T* ret = x0_ptr;
const_cast< allocator_auto_ptr* >(this)->x0_ptr = nullptr;
return ret;
}
private:
T* x0_ptr;
Alloc* x4_alloc;
};
template < typename T, typename Alloc = rmemory_allocator >
class vector {
-1
View File
@@ -86,7 +86,6 @@ uint CMediumAllocPool::GetNumBlocksAvailable() {
return ret;
}
#pragma inline_max_size(250)
void CMediumAllocPool::AddPuddle(uint len, void* data, const bool unk) {
x0_list.push_back(SMediumAllocPuddle(len, data, unk));
x18_lastNodePrev = x0_list.end();
@@ -0,0 +1,67 @@
#include "Kyoto/Animation/CSkinnedModel.hpp"
#include "Kyoto/Alloc/CMemory.hpp"
#include "Kyoto/Graphics/CModel.hpp"
#include "Kyoto/Math/CVector3f.hpp"
#include "rstl/list.hpp"
#include "rstl/pair.hpp"
#include "rstl/vector.hpp"
#pragma inline_max_size(250)
typedef rstl::pair< CVector3f, rstl::list< uint > > TPosToVertListPair;
CSkinnedModelWithAvgNormals::CSkinnedModelWithAvgNormals(const CSkinnedModel& skinnedModel)
: x0_skinnedModel(skinnedModel), x3c_avgNormals(rs_new float[skinnedModel.GetNumPoints() * 12]) {
int vertexCount = skinnedModel.GetNumPoints();
const CVector3f* modelPositions =
reinterpret_cast< const CVector3f* >(skinnedModel.GetModel()->GetPositions());
rstl::vector< TPosToVertListPair > vertMap;
vertMap.reserve(vertexCount);
for (uint vertIdx = 0; vertIdx < vertexCount; ++vertIdx) {
bool foundEqPos = false;
uint vopolSize = vertMap.size();
for (uint i = 0; i < vopolSize; ++i) {
if (vertMap[i].first.IsEqu(modelPositions[vertIdx])) {
foundEqPos = true;
break;
}
}
if (!foundEqPos) {
rstl::list< uint > tmpList;
for (uint j = vertIdx; j < vertexCount; ++j) {
if (modelPositions[j] == modelPositions[vertIdx]) {
tmpList.push_back(j);
}
}
vertMap.push_back(TPosToVertListPair(modelPositions[vertIdx], tmpList));
}
}
const CVector3f* normals =
reinterpret_cast< const CVector3f* >(skinnedModel.GetModel()->GetNormals());
float* avgNormals = x3c_avgNormals.get();
TPosToVertListPair* mapCur = vertMap.xc_items;
TPosToVertListPair* mapEnd = mapCur + vertMap.x4_count;
while (mapCur != mapEnd) {
CVector3f accum(0.f, 0.f, 0.f);
AUTO(lit, mapCur->second.begin());
AUTO(listEnd, mapCur->second.end());
for (; lit != listEnd; ++lit) {
accum += normals[*lit];
}
lit = mapCur->second.begin();
CVector3f normalized = accum.AsNormalized();
for (; lit != listEnd; ++lit) {
reinterpret_cast< CVector3f* >(avgNormals)[*lit] = normalized;
}
++mapCur;
}
}
+265 -1
View File
@@ -1,10 +1,25 @@
#pragma inline_max_size(259) // TODO: adjusted from 250 for Skinning::AddSkinnedRef
#include "Kyoto/Animation/CSkinnedModel.hpp"
#include "Kyoto/Alloc/CCircularBuffer.hpp"
#include "Kyoto/Alloc/CMemory.hpp"
#include "Kyoto/Animation/CSkinRules.hpp"
#include "Kyoto/Animation/CVertexMorphEffect.hpp"
#include "Kyoto/Graphics/CGraphics.hpp"
#include "Kyoto/Graphics/CModel.hpp"
#include "Kyoto/Graphics/CModelFlags.hpp"
#include <dolphin/PPCArch.h>
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/os/OSCache.h>
#include <rstl/optional_object.hpp>
CSkinnedModel::TPointGenFunc CSkinnedModel::sPointGen;
void* CSkinnedModel::sPointGenData;
struct SSkinnedAllocation {
SSkinnedAllocation(void* ptr, int w1, ushort w2) : x0_ptr(ptr), x4_unk1(w1), x8_unk2(w2) {}
@@ -20,6 +35,7 @@ static bool sSkinningInitialized = false;
static char sStaticSkinningData[0x80000] ATTRIBUTE_ALIGN(32);
static rstl::optional_object< CCircularBuffer > sSkinningBuffer;
static rstl::list< SSkinnedAllocation > sAllocations;
static bool sbDumpedSpinLockMessage = false;
void AddSkinnedRef();
void DelSkinnedRef();
@@ -44,6 +60,254 @@ void Skinning::DelSkinnedRef() {
--sNumSkinnedObjects;
if (sNumSkinnedObjects == 0) {
sSkinningBuffer.clear();
sAllocations.clear();
AUTO(end, sAllocations.end());
AUTO(it, sAllocations.begin());
while (it != end) {
it = sAllocations.erase(it);
}
}
}
CSkinnedModel::CSkinnedModel(const TLockedToken< CModel >& model,
const TLockedToken< CSkinRules >& skinRules,
const TLockedToken< CCharLayoutInfo >& layoutInfo,
EDataOwnership ownership)
: x4_model(model)
, x10_skinRules(skinRules)
, x1c_layoutInfo(layoutInfo)
, x28_vertWorkspace()
, x30_normalWorkspace()
, x38_owned(ownership == kDO_Owned)
, x39_disableWorkspaces(false) {
Construct();
}
CSkinnedModel::CSkinnedModel(const CSkinnedModel& other)
: x4_model(other.x4_model)
, x10_skinRules(other.x10_skinRules)
, x1c_layoutInfo(other.x1c_layoutInfo)
, x28_vertWorkspace()
, x30_normalWorkspace()
, x38_owned(other.x38_owned)
, x39_disableWorkspaces(false) {
Construct();
}
CSkinnedModel::~CSkinnedModel() { Skinning::DelSkinnedRef(); }
void CSkinnedModel::Construct() {
Skinning::AddSkinnedRef();
if (!x38_owned) {
uint numPoints = x10_skinRules->GetNumPoints();
uint numNormals = x10_skinRules->GetNumNormals();
x28_vertWorkspace = rs_new float[numPoints * 12];
x30_normalWorkspace = rs_new float[numNormals * 12];
}
if (x10_skinRules->GetNumVirtualBones() == 1) {
x39_disableWorkspaces = true;
}
}
void CSkinnedModel::Draw(const CModelFlags& flags) const {
if (x39_disableWorkspaces) {
CTransform4f saved(CGraphics::GetModelMatrix());
CGraphics::SetModelMatrix(saved * x10_skinRules->GetVirtualBones()[0].GetTransform());
x4_model->Draw(flags);
CGraphics::SetModelMatrix(saved);
} else if (x28_vertWorkspace.null()) {
x4_model->Draw(flags);
} else {
x4_model->Draw(x28_vertWorkspace.get(), x30_normalWorkspace.get(), flags);
PostDrawFunc();
}
}
void CSkinnedModel::DoDrawCallback(void (*func)(const float*, const float*, const void*),
void* data) {
const float* normals;
if (x39_disableWorkspaces) {
CTransform4f saved(CGraphics::GetModelMatrix());
CGraphics::SetModelMatrix(saved * x10_skinRules->GetVirtualBones()[0].GetTransform());
normals = x4_model->GetNormals();
func(x4_model->GetPositions(), normals, data);
CGraphics::SetModelMatrix(saved);
} else if (x28_vertWorkspace.null()) {
normals = x4_model->GetNormals();
func(x4_model->GetPositions(), normals, data);
} else {
func(x28_vertWorkspace.get(), x30_normalWorkspace.get(), data);
uint vertSize = (x10_skinRules->GetNumPoints() * 12 + 31) & ~31u;
DCFlushRangeNoSync(x28_vertWorkspace.get(), vertSize);
uint normSize = (x10_skinRules->GetNumNormals() * 12 + 31) & ~31u;
DCFlushRangeNoSync(x30_normalWorkspace.get(), normSize);
PPCSync();
PostDrawFunc();
}
}
void CSkinnedModel::Draw(const float* positions, const float* normals,
const CModelFlags& flags) const {
x4_model->Draw(positions, normals, flags);
PostDrawFunc();
}
void CSkinnedModel::Calculate(const CPoseAsTransforms& pose,
const rstl::optional_object< CVertexMorphEffect >& morphEffect,
const float* averagedNormals, float* workVerts) {
uint vertSize = x10_skinRules->GetNumPoints() * 12;
uint normSize = x10_skinRules->GetNumNormals() * 12;
float* verts;
if (workVerts != nullptr) {
verts = workVerts;
} else {
if (x39_disableWorkspaces) {
x10_skinRules->BuildAccumulatedTransforms(pose, **x1c_layoutInfo);
return;
}
AllocateStorage();
verts = x28_vertWorkspace.get();
}
uint alignedVertSize = (vertSize + 31) & ~31u;
uint totalSize = alignedVertSize + ((normSize + 31) & ~31u);
DCFlushRange(verts, totalSize);
BOOL interruptState = OSDisableInterrupts();
volatile void* pipe = GXRedirectWriteGatherPipe(verts);
x10_skinRules->InitLockedCacheState(**x4_model);
x10_skinRules->BuildAccumulatedTransforms(pose, **x1c_layoutInfo);
x10_skinRules->BuildPoints(pipe);
int numWords = x10_skinRules->GetNumPoints() * 3;
int padWords = ((numWords + 7) & ~7) - numWords;
for (int i = 0; i < padWords; i++) {
*reinterpret_cast< volatile u32* >(pipe) = 0;
}
x10_skinRules->BuildNormals(pipe);
GXRestoreWriteGatherPipe();
OSRestoreInterrupts(interruptState);
if (morphEffect.valid()) {
(*morphEffect)
.MorphVertices(reinterpret_cast< CVector3f* >(verts),
reinterpret_cast< const CVector3f* >(averagedNormals), x10_skinRules, pose,
x10_skinRules->GetNumPoints());
DCFlushRange(verts, alignedVertSize);
}
if (sPointGen != nullptr) {
const CVector3f* positions = reinterpret_cast< const CVector3f* >(verts);
sPointGen(sPointGenData, positions, positions + x10_skinRules->GetNumPoints(),
x10_skinRules->GetNumPoints());
DCInvalidateRange(verts, totalSize);
}
}
void CSkinnedModel::CalculateDefault() {
x28_vertWorkspace = rstl::auto_ptr< float >();
x30_normalWorkspace = rstl::auto_ptr< float >();
}
void CSkinnedModel::TickAllocations() {
int syncVal = GXReadDrawSync();
if (syncVal > static_cast< int >(Skinning::skCurrentToken)) {
syncVal -= 0x10000;
}
while (Skinning::sAllocations.size() != 0) {
SSkinnedAllocation& front = Skinning::sAllocations.front();
int tokenVal = static_cast< int >(front.x8_unk2);
if (tokenVal > static_cast< int >(Skinning::skCurrentToken)) {
tokenVal -= 0x10000;
}
if (syncVal < tokenVal)
break;
Skinning::sSkinningBuffer->Free(front.x0_ptr, front.x4_unk1);
Skinning::sAllocations.pop_front();
}
}
void* CSkinnedModel::EnsureAllocation(int size) {
size = (size + 31) & ~31;
void* ptr = Skinning::sSkinningBuffer->Alloc(size);
if (ptr == nullptr && !Skinning::sbDumpedSpinLockMessage) {
Skinning::sSkinningBuffer->GetAllocatedAmount();
Skinning::sbDumpedSpinLockMessage = true;
}
s32 startTick = OSGetTick();
while (ptr == nullptr) {
TickAllocations();
ptr = Skinning::sSkinningBuffer->Alloc(size);
if (ptr == nullptr) {
s32 currentTick = OSGetTick();
if (OSTicksToMilliseconds(static_cast< uint >(currentTick - startTick)) > 60) {
GXReadDrawSync();
for (AUTO(it, Skinning::sAllocations.begin()); it != Skinning::sAllocations.end(); ++it) {
}
startTick = currentTick;
GXSetDrawSync(Skinning::skCurrentToken);
++Skinning::skCurrentToken;
}
}
}
Skinning::sAllocations.push_back(SSkinnedAllocation(ptr, size, Skinning::skCurrentToken));
return ptr;
}
void CSkinnedModel::AllocateStorage() {
if (x38_owned && (x28_vertWorkspace.null() || x30_normalWorkspace.null())) {
int vertexCount = x10_skinRules->GetNumPoints();
int normalCount = x10_skinRules->GetNumNormals();
TickAllocations();
int normSize = (normalCount * 12 + 31) & ~31;
int vertSize = (vertexCount * 12 + 31) & ~31;
int totalSize = vertSize + normSize + 32;
void* ptr = EnsureAllocation(totalSize);
if (ptr == Skinning::sStaticSkinningData) {
GXInvalidateVtxCache();
}
x28_vertWorkspace = rstl::auto_ptr< float >(static_cast< float* >(ptr));
x30_normalWorkspace =
rstl::auto_ptr< float >(reinterpret_cast< float* >(static_cast< char* >(ptr) + vertSize));
x28_vertWorkspace.release();
x30_normalWorkspace.release();
}
}
void CSkinnedModel::PostDrawFunc() const {
if (x38_owned && !x28_vertWorkspace.null()) {
x28_vertWorkspace = rstl::auto_ptr< float >();
x30_normalWorkspace = rstl::auto_ptr< float >();
GXSetDrawSync(Skinning::skCurrentToken);
++Skinning::skCurrentToken;
}
}
void CSkinnedModel::AddDummySkinnedModelRef() { Skinning::AddSkinnedRef(); }
void CSkinnedModel::RemoveDummySkinnedModelRef() { Skinning::DelSkinnedRef(); }
void CSkinnedModel::SetPointGeneratorFunc(void* data, void (*func)(void*, const CVector3f*,
const CVector3f*, int)) {
sPointGen = func;
sPointGenData = data;
}
void CSkinnedModel::ClearPointGeneratorFunc() { sPointGen = nullptr; }
float* CSkinnedModel::AllocateNewWorkspace(float** vertOut) {
const CSkinRules* skinRules = *x10_skinRules;
int normalCount = skinRules->GetNumNormals();
int vertexCount = skinRules->GetNumPoints();
int alignedNormSize = (normalCount * 12 + 31) & ~31;
int alignedVertSize = (vertexCount * 12 + 31) & ~31;
int vertSize = vertexCount * 12;
float* ptr = static_cast< float* >(
CMemory::Alloc(((vertSize + 31) & ~31) + alignedNormSize, IAllocator::kHI_RoundUpLen));
if (vertOut != nullptr) {
*vertOut = reinterpret_cast< float* >(reinterpret_cast< char* >(ptr) + alignedNormSize);
}
return ptr;
}