SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
MDL.cpp
Go to the documentation of this file.
1#include <mdlpp/structs/MDL.h>
2
3#include <BufferStream.h>
5
6using namespace mdlpp::MDL;
7using namespace sourcepp;
8
9constexpr int32_t MDL_ID = 'I' + ('D' << 8) + ('S' << 16) + ('T' << 24);
10
11bool MDL::open(const std::byte* data, std::size_t size) {
12 BufferStreamReadOnly stream{data, size};
13
14 if (stream.read<int32_t>() != MDL_ID) {
15 return false;
16 }
17
18 if (stream.read(this->version); this->version < 44 || this->version > 49) {
19 return false;
20 }
21
22 stream
23 .read(this->checksum)
24 .read(this->name, 64)
25 .skip<int32_t>() // dataLength
26 .read(this->eyePosition)
27 .read(this->illuminationPosition)
28 .read(this->hullMin)
29 .read(this->hullMax)
30 .read(this->viewBBoxMin)
31 .read(this->viewBBoxMax);
32
33 this->flags = static_cast<Flags>(stream.read<int32_t>());
34
35 const auto boneCount = stream.read<int32_t>();
36 const auto boneOffset = stream.read<int32_t>();
37
38 const auto boneControllerCount = stream.read<int32_t>();
39 const auto boneControllerOffset = stream.read<int32_t>();
40
41 const auto hitboxSetCount = stream.read<int32_t>();
42 const auto hitboxSetOffset = stream.read<int32_t>();
43
44 //auto animDescCount = stream.read<int32_t>();
45 //auto animDescOffset = stream.read<int32_t>();
46 stream.skip<int32_t>(2);
47
48 //auto sequenceDescCount = stream.read<int32_t>();
49 //auto sequenceDescOffset = stream.read<int32_t>();
50 stream.skip<int32_t>(2);
51
52 stream
53 .read(this->activityListVersion)
54 .read(this->eventsIndexed);
55
56 const auto materialCount = stream.read<int32_t>();
57 const auto materialOffset = stream.read<int32_t>();
58
59 const auto materialDirCount = stream.read<int32_t>();
60 const auto materialDirOffset = stream.read<int32_t>();
61
62 const auto skinReferenceCount = stream.read<int32_t>();
63 const auto skinReferenceFamilyCount = stream.read<int32_t>();
64 const auto skinReferenceOffset = stream.read<int32_t>();
65
66 const auto bodyPartCount = stream.read<int32_t>();
67 const auto bodyPartOffset = stream.read<int32_t>();
68
69 // Done reading sequentially, start seeking to offsets
70
71 stream.seek(boneOffset);
72 for (int i = 0; i < boneCount; i++) {
73 auto& bone = this->bones.emplace_back();
74
75 parser::binary::readStringAtOffset(stream, bone.name);
76 stream
77 .read(bone.parent)
78 .read(bone.boneController)
79 .read(bone.position)
80 .read(bone.rotationQuat)
81 .read(bone.rotationEuler)
82 .read(bone.positionScale)
83 .read(bone.rotationScale)
84 .read(bone.poseToBose)
85 .read(bone.alignment)
86 .read(bone.flags)
87 .read(bone.procType)
88 .read(bone.procIndex)
89 .read(bone.physicsBone);
90 parser::binary::readStringAtOffset(stream, bone.surfacePropName, std::ios::cur, sizeof(int32_t) * 12 + sizeof(math::Vec3f) * 4 + sizeof(math::Quat) * 2 + sizeof(math::Mat3x4f) + sizeof(Bone::Flags));
91 stream.read(bone.contents);
92
93 // _unused0
94 stream.skip<int32_t>(8);
95 }
96
97 stream.seek(boneControllerOffset);
98 for (int i = 0; i < boneControllerCount; i++) {
99 this->boneControllers.push_back(stream.read<BoneController>());
100
101 // _unused0
102 stream.skip<int32_t>(8);
103 }
104
105 for (int i = 0; i < hitboxSetCount; i++) {
106 const auto hitboxSetPos = hitboxSetOffset + i * (sizeof(int32_t) * 3);
107 stream.seek_u(hitboxSetPos);
108
109 auto& hitboxSet = this->hitboxSets.emplace_back();
110
111 parser::binary::readStringAtOffset(stream, hitboxSet.name);
112 const auto hitboxCount = stream.read<int32_t>();
113 const auto hitboxOffset = stream.read<int32_t>();
114
115 for (int j = 0; j < hitboxCount; j++) {
116 const auto hitboxPos = hitboxOffset + j * (sizeof(int32_t) * 11 + sizeof(math::Vec3f) * 2);
117 stream.seek_u(hitboxSetPos + hitboxPos);
118
119 auto& hitbox = hitboxSet.hitboxes.emplace_back();
120
121 stream
122 .read(hitbox.bone)
123 .read(hitbox.group)
124 .read(hitbox.bboxMin)
125 .read(hitbox.bboxMax);
126
127 // note: we don't know what model versions use absolute vs. relative offsets here
128 // and this is unimportant, so skip parsing the bbox name here
129 //readStringAtOffset(stream, hitbox.name, std::ios::cur, sizeof(int32_t) * 3 + sizeof(Vec3f) * 2);
130 stream.skip<int32_t>();
131 hitbox.name = "";
132
133 // _unused0
134 stream.skip<int32_t>(8);
135 }
136 }
137
138 /*
139 stream.seek(animDescOffset);
140 for (int i = 0; i < animDescCount; i++) {
141 // todo(wrapper)
142 }
143
144 stream.seek(sequenceDescOffset);
145 for (int i = 0; i < sequenceDescCount; i++) {
146 // todo(wrapper)
147 }
148 */
149
150 stream.seek(materialOffset);
151 for (int i = 0; i < materialCount; i++) {
152 auto& material = this->materials.emplace_back();
153
154 parser::binary::readStringAtOffset(stream, material.name);
155 stream.read(material.flags);
156
157 // used
158 stream.skip<int32_t>();
159 // _unused0
160 stream.skip<int32_t>(13);
161 }
162
163 stream.seek(materialDirOffset);
164 for (int i = 0; i < materialDirCount; i++) {
165 auto& materialDir = this->materialDirectories.emplace_back();
166
167 parser::binary::readStringAtOffset(stream, materialDir, std::ios::beg, 0);
168 }
169
170 stream.seek(skinReferenceOffset);
171 for (int i = 0; i < skinReferenceFamilyCount; i++) {
172 std::vector<int16_t> skinFamily;
173 skinFamily.reserve(skinReferenceCount);
174 for (int j = 0; j < skinReferenceCount; j++) {
175 skinFamily.push_back(stream.read<int16_t>());
176 }
177 this->skins.push_back(std::move(skinFamily));
178 }
179
180 for (int i = 0; i < bodyPartCount; i++) {
181 const auto bodyPartPos = bodyPartOffset + i * (sizeof(int32_t) * 4);
182 stream.seek_u(bodyPartPos);
183
184 auto& bodyPart = this->bodyParts.emplace_back();
185
186 parser::binary::readStringAtOffset(stream, bodyPart.name);
187
188 const auto modelsCount = stream.read<int32_t>();
189 stream.skip<int32_t>(); // base
190 const auto modelsOffset = stream.read<int32_t>();
191
192 for (int j = 0; j < modelsCount; j++) {
193 auto modelPos = modelsOffset + j * (64 + sizeof(float) + sizeof(int32_t) * 20);
194 stream.seek_u(bodyPartPos + modelPos);
195
196 auto& model = bodyPart.models.emplace_back();
197
198 stream
199 .read(model.name, 64)
200 .read(model.type)
201 .read(model.boundingRadius);
202
203 const auto meshesCount = stream.read<int32_t>();
204 const auto meshesOffset = stream.read<int32_t>();
205
206 stream
207 .read(model.verticesCount)
208 .read(model.verticesOffset);
209
210 for (int k = 0; k < meshesCount; k++) {
211 const auto meshPos = meshesOffset + k * (sizeof(int32_t) * (18 + MAX_LOD_COUNT) + sizeof(math::Vec3f));
212 stream.seek_u(bodyPartPos + modelPos + meshPos);
213
214 auto& mesh = model.meshes.emplace_back();
215
216 stream
217 .read(mesh.material)
218 .skip<int32_t>()
219 .read(mesh.verticesCount)
220 .read(mesh.verticesOffset)
221 .skip<int32_t>(2)
222 .read(mesh.materialType)
223 .read(mesh.materialParam)
224 .read(mesh.meshID)
225 .read(mesh.center);
226 }
227 }
228 }
229
230 return true;
231}
constexpr int32_t MDL_ID
Definition: MDL.cpp:9
Definition: MDL.h:11
constexpr int MAX_LOD_COUNT
Definition: Generic.h:11
Vec4f Quat
Definition: Math.h:330
void readStringAtOffset(BufferStream &stream, std::string &str, std::ios::seekdir offsetFrom=std::ios::cur, std::size_t subtractFromOffset=sizeof(int32_t))
Reads an integer from the stream, seeks there, reads a string, and seeks back.
Definition: Binary.cpp:7
Definition: LZMA.h:11
sourcepp::math::Vec3f viewBBoxMax
Definition: MDL.h:298
sourcepp::math::Vec3f hullMax
Definition: MDL.h:296
std::vector< Material > materials
Definition: MDL.h:325
int32_t activityListVersion
Definition: MDL.h:320
Flags flags
Definition: MDL.h:300
bool open(const std::byte *data, std::size_t size)
Definition: MDL.cpp:11
std::string name
Definition: MDL.h:290
sourcepp::math::Vec3f viewBBoxMin
Definition: MDL.h:297
sourcepp::math::Vec3f eyePosition
Definition: MDL.h:293
sourcepp::math::Vec3f hullMin
Definition: MDL.h:295
std::vector< std::vector< int16_t > > skins
Definition: MDL.h:335
std::vector< std::string > materialDirectories
Definition: MDL.h:329
int32_t checksum
Definition: MDL.h:287
sourcepp::math::Vec3f illuminationPosition
Definition: MDL.h:294
std::vector< BodyPart > bodyParts
Definition: MDL.h:339
std::vector< BoneController > boneControllers
Definition: MDL.h:308
std::vector< Bone > bones
Definition: MDL.h:304
int32_t eventsIndexed
Definition: MDL.h:321
std::vector< HitboxSet > hitboxSets
Definition: MDL.h:312