1#pragma once
2
3#include <nn/nn_BitTypes.h>
4#include <nn/util/util_BinTypes.h>
5#include <nn/util/util_BinaryFormat.h>
6#include <nn/util/util_ResDic.h>
7#include "nn/gfx/gfx_ResUserData.h"
8#include "nn/util/MathTypes.h"
9
10namespace nn::g3d {
11
12struct ResBoneData {
13 nn::util::BinPtrToString pName;
14 nn::util::BinTPtr<nn::gfx::ResUserData> pUserDataArray;
15 nn::util::BinTPtr<nn::util::ResDic> pUserDataDic;
16#ifndef UKING_NX_V150
17 // This array is present in Pokémon Sword and Shield's version of nnSdk but not in BotW 1.5.0.
18 uint8_t reserved[16];
19#endif
20 uint16_t index;
21 uint16_t parentIndex;
22 int16_t smoothMtxIndex;
23 int16_t rigidMtxIndex;
24 uint16_t billboardIndex;
25 uint16_t userDataCount;
26 nn::Bit32 flag;
27 nn::util::Float3 scale;
28 union {
29 nn::util::Float4 quat;
30 nn::util::Float3 euler;
31 } rotate;
32 nn::util::Float3 translate;
33};
34
35class ResBone : public nn::util::AccessorBase<ResBoneData> {
36public:
37 enum Shift {
38 Shift_Hierarchy = 4,
39 Shift_Rot = 12,
40 Shift_Billboard = 16,
41 Shift_MirroringState = 20,
42 Shift_Transform = 23,
43 };
44
45 enum Flag {
46 Flag_Visibility = 0x1 << 0,
47
48 Flag_BillboardNone = 0x0 << Shift_Billboard,
49 Flag_BillboardChild = 0x1 << Shift_Billboard,
50 Flag_BillboardWorldViewVector = 0x2 << Shift_Billboard,
51 Flag_BillboardWorldViewPoint = 0x3 << Shift_Billboard,
52 Flag_BillboardScreenViewVector = 0x4 << Shift_Billboard,
53 Flag_BillboardScreenViewPoint = 0x5 << Shift_Billboard,
54 Flag_BillboardYaxisViewVector = 0x6 << Shift_Billboard,
55 Flag_BillboardYaxisViewPoint = 0x7 << Shift_Billboard,
56 Flag_BillboardMax = Flag_BillboardYaxisViewPoint,
57
58 Flag_SegmentScaleCompensate = 0x1 << Shift_Transform,
59 Flag_ScaleUniform = 0x2 << Shift_Transform,
60 Flag_ScaleVolumeOne = 0x4 << Shift_Transform,
61 Flag_RotateZero = 0x8 << Shift_Transform,
62 Flag_TranslateZero = 0x10 << Shift_Transform,
63 Flag_ScaleOne = Flag_ScaleVolumeOne | Flag_ScaleUniform,
64 Flag_RotTransZero = Flag_RotateZero | Flag_TranslateZero,
65 Flag_Identity = Flag_ScaleOne | Flag_RotateZero | Flag_TranslateZero,
66 Flag_HiScaleUniform = Flag_ScaleUniform << Shift_Hierarchy,
67 Flag_HiScaleVolumeOne = Flag_ScaleVolumeOne << Shift_Hierarchy,
68 Flag_HiRotateZero = Flag_RotateZero << Shift_Hierarchy,
69 Flag_HiTranslateZero = Flag_TranslateZero << Shift_Hierarchy,
70 Flag_HiScaleOne = Flag_ScaleOne << Shift_Hierarchy,
71 Flag_HiRotTransZero = Flag_RotTransZero << Shift_Hierarchy,
72 Flag_HiIdentity = Flag_Identity << Shift_Hierarchy,
73 Flag_BillboardIndexNone = 0xFFFF,
74 };
75
76 enum Mask {
77 Mask_Rot = 0x7 << Shift_Rot,
78 Mask_Billboard = 0x7 << Shift_Billboard,
79 Mask_MirroringState = 0x7 << Shift_MirroringState,
80 Mask_Transform = Flag_SegmentScaleCompensate | Flag_Identity
81 };
82
83 static constexpr int InvalidBoneIndex = 0xffff;
84
85 ResBone(const ResBone&) = delete;
86 auto operator=(const nn::g3d::ResBone&) = delete;
87
88 int GetIndex() const { return index; }
89 const char* GetName() const { return pName.Get()->GetData(); }
90 int GetSmoothMtxIndex() const { return smoothMtxIndex; }
91 int GetRigidMtxIndex() const { return rigidMtxIndex; }
92 int GetParentIndex() const { return parentIndex; }
93 nn::Bit32 GetRotateMode() const { return flag & Mask_Rot; }
94 nn::Bit32 GetBillboardMode() const { return flag & Mask_Billboard; }
95 nn::Bit32 GetMirroringState() const { return flag & Mask_MirroringState; }
96 bool IsVisible() const { return (flag & Flag_Visibility) != 0; }
97 nn::util::Float3& GetScale() { return scale; }
98 const nn::util::Float3& GetScale() const { return scale; }
99 nn::util::Float3& GetTranslate() { return translate; }
100 const nn::util::Float3& GetTranslate() const { return translate; }
101 nn::util::Float3& GetRotateEuler() { return rotate.euler; }
102 const nn::util::Float3& GetRotateEuler() const { return rotate.euler; }
103 nn::util::Float4& GetRotateQuat() { return rotate.quat; }
104 const nn::util::Float4& GetRotateQuat() const { return rotate.quat; }
105 int GetUserDataCount() const { return userDataCount; }
106
107 nn::gfx::ResUserData* FindUserData(const char* key) {
108 int index = FindUserDataIndex(key);
109 if (index == util::ResDic::Npos)
110 return nullptr;
111 return GetUserData(index);
112 }
113
114 const nn::gfx::ResUserData* FindUserData(const char* key) const {
115 int index = FindUserDataIndex(key);
116 if (index == util::ResDic::Npos)
117 return nullptr;
118 return GetUserData(index);
119 }
120
121 int FindUserDataIndex(const char* key) const {
122 const util::ResDic* dict = pUserDataDic.Get();
123 if (dict == nullptr)
124 return util::ResDic::Npos;
125 return dict->FindIndex(key);
126 }
127
128 const char* GetUserDataName(int index) const {
129 const util::ResDic* dict = pUserDataDic.Get();
130 if (dict == nullptr)
131 return nullptr;
132 return dict->GetKey(index).data();
133 }
134
135 nn::gfx::ResUserData* GetUserData(int index) { return &pUserDataArray.Get()[index]; }
136
137 const nn::gfx::ResUserData* GetUserData(int index) const {
138 return &pUserDataArray.Get()[index];
139 }
140};
141
142struct ResSkeletonData {
143 nn::util::BinaryBlockHeader blockHeader;
144 nn::util::BinTPtr<nn::util::ResDic> pBoneDic;
145 nn::util::BinTPtr<nn::g3d::ResBone> pBoneArray;
146 nn::util::BinTPtr<short> pMtxToBoneTable;
147 nn::util::BinTPtr<nn::util::FloatColumnMajor4x3> pInvModelMatrixArray;
148 nn::util::BinPtr pUserPtr;
149 nn::util::BinTPtr<short> pMirroringBoneTable;
150 uint8_t reserved1[8];
151 nn::Bit32 flag;
152 uint16_t boneCount;
153 uint16_t smoothMtxCount;
154 uint16_t rigidMtxCount;
155 uint8_t reserved2[6];
156};
157
158class ResSkeleton : public nn::util::AccessorBase<nn::g3d::ResSkeletonData> {
159public:
160 static constexpr uint32_t Signature = util::MakeSignature(a: 'F', b: 'S', c: 'K', d: 'L');
161
162 enum Shift {
163 Shift_MirroringMode = 6,
164 Shift_Scale = 8,
165 Shift_Rot = 12,
166 };
167
168 enum Mask {
169 Mask_MirroringMode = 0x3 << Shift_MirroringMode,
170 Mask_Scale = 0x3 << Shift_Scale,
171 Mask_Rot = ResBone::Mask_Rot,
172 Mask_TransForm = Mask_Scale | Mask_Rot
173 };
174
175 enum ResetGuardFlag {
176 ResetGuardFlag_None = 0,
177 ResetGuardFlag_UserPtr = 1,
178 };
179
180 ResSkeleton(const ResSkeleton&) = delete;
181 auto operator=(const ResSkeleton&) = delete;
182
183 void Reset();
184 void Reset(nn::Bit32);
185
186 int GetSmoothMtxCount() const { return smoothMtxCount; }
187 int GetRigidMtxCount() const { return rigidMtxCount; }
188 int GetMtxCount() const { return GetSmoothMtxCount() + GetRigidMtxCount(); }
189 nn::Bit32 GetScaleMode() const { return flag & Mask_Scale; }
190 nn::Bit32 GetRotateMode() const { return flag & Mask_Rot; }
191 nn::Bit32 GetMirroringMode() const { return flag & Mask_MirroringMode; }
192 bool HasMirroringInfo() const { return pMirroringBoneTable.Get() != nullptr; }
193 int GetBranchEndIndex(int) const;
194 void SetUserPtr(void* ptr) { pUserPtr.Set(ptr); }
195 void* GetUserPtr() { return pUserPtr.Get(); }
196 const void* GetUserPtr() const { return pUserPtr.Get(); }
197 void UpdateBillboardMode();
198
199 int GetBoneCount() const { return boneCount; }
200
201 nn::g3d::ResBone* FindBone(const char* name) {
202 int index = FindBoneIndex(name);
203 if (index == util::ResDic::Npos)
204 return nullptr;
205 return GetBone(index);
206 }
207
208 const nn::g3d::ResBone* FindBone(const char* name) const {
209 int index = FindBoneIndex(name);
210 if (index == util::ResDic::Npos)
211 return nullptr;
212 return GetBone(index);
213 }
214
215 int FindBoneIndex(const char* name) const {
216 auto* dict = pBoneDic.Get();
217 if (dict == nullptr)
218 return util::ResDic::Npos;
219 return dict->FindIndex(key: name);
220 }
221
222 const char* GetBoneName(int index) const {
223 auto* dict = pBoneDic.Get();
224 if (dict == nullptr)
225 return nullptr;
226 return dict->GetKey(index).data();
227 }
228
229 nn::g3d::ResBone* GetBone(int index) { return &pBoneArray.Get()[index]; }
230 const nn::g3d::ResBone* GetBone(int index) const { return &pBoneArray.Get()[index]; }
231
232 int GetMirroredBoneIndex(int index) const { return pMirroringBoneTable.Get()[index]; }
233};
234
235} // namespace nn::g3d
236