SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
mdlpp.cpp
Go to the documentation of this file.
1#include <mdlpp/mdlpp.h>
2
3#include <algorithm>
4#include <span>
5#include <utility>
6
7using namespace mdlpp;
8using namespace sourcepp;
9
10bool StudioModel::open(const std::byte* mdlData, std::size_t mdlSize,
11 const std::byte* vtxData, std::size_t vtxSize,
12 const std::byte* vvdData, std::size_t vvdSize) {
13 if (this->opened || !mdlData || !vtxData || !vvdData || !mdlSize || !vtxSize || !vvdSize) {
14 return false;
15 }
16 if ((!this->mdl.open(mdlData, mdlSize) ||
17 !this->vtx.open(vtxData, vtxSize, this->mdl)) ||
18 !this->vvd.open(vvdData, vvdSize, this->mdl)) {
19 return false;
20 }
21 this->opened = true;
22 return true;
23}
24
25bool StudioModel::open(const unsigned char* mdlData, std::size_t mdlSize,
26 const unsigned char* vtxData, std::size_t vtxSize,
27 const unsigned char* vvdData, std::size_t vvdSize) {
28 return this->open(reinterpret_cast<const std::byte*>(mdlData), mdlSize,
29 reinterpret_cast<const std::byte*>(vtxData), vtxSize,
30 reinterpret_cast<const std::byte*>(vvdData), vvdSize);
31}
32
33bool StudioModel::open(const std::vector<std::byte>& mdlData,
34 const std::vector<std::byte>& vtxData,
35 const std::vector<std::byte>& vvdData) {
36 return this->open(mdlData.data(), mdlData.size(),
37 vtxData.data(), vtxData.size(),
38 vvdData.data(), vvdData.size());
39}
40
41bool StudioModel::open(const std::vector<unsigned char>& mdlData,
42 const std::vector<unsigned char>& vtxData,
43 const std::vector<unsigned char>& vvdData) {
44 return this->open(mdlData.data(), mdlData.size(),
45 vtxData.data(), vtxData.size(),
46 vvdData.data(), vvdData.size());
47}
48
49StudioModel::operator bool() const {
50 return this->opened;
51}
52
54 BakedModel model;
55
56 // According to my limited research, vertices stay constant (ignoring LOD fixups) but indices vary with LOD level
57 static constexpr auto convertVertex = [](const VVD::Vertex& vertex) {
58 return BakedModel::Vertex{vertex.position, vertex.normal, vertex.uv};
59 };
60 if (this->vvd.fixups.empty()) {
61 std::transform(this->vvd.vertices.begin(), this->vvd.vertices.end(), std::back_inserter(model.vertices), convertVertex);
62 } else {
63 for (const auto& [LOD, sourceVertexID, vertexCount] : this->vvd.fixups) {
64 if (LOD < currentLOD) {
65 continue;
66 }
67 std::span fixupVertices{this->vvd.vertices.begin() + sourceVertexID, static_cast<std::span<const VVD::Vertex>::size_type>(vertexCount)};
68 std::transform(fixupVertices.begin(), fixupVertices.end(), std::back_inserter(model.vertices), convertVertex);
69 }
70 }
71
72 for (int bodyPartIndex = 0; bodyPartIndex < this->mdl.bodyParts.size(); bodyPartIndex++) {
73 auto& mdlBodyPart = this->mdl.bodyParts.at(bodyPartIndex);
74 auto& vtxBodyPart = this->vtx.bodyParts.at(bodyPartIndex);
75
76 for (int modelIndex = 0; modelIndex < mdlBodyPart.models.size(); modelIndex++) {
77 auto& mdlModel = mdlBodyPart.models.at(modelIndex);
78 auto& vtxModel = vtxBodyPart.models.at(modelIndex);
79
80 if (mdlModel.verticesCount == 0) {
81 continue;
82 }
83
84 for (int meshIndex = 0; meshIndex < mdlModel.meshes.size(); meshIndex++) {
85 auto& mdlMesh = mdlModel.meshes.at(meshIndex);
86 auto& vtxMesh = vtxModel.modelLODs.at(currentLOD).meshes.at(meshIndex);
87
88 std::vector<uint16_t> indices;
89 for (const auto& stripGroup : vtxMesh.stripGroups) {
90 for (const auto& strip : stripGroup.strips) {
91 const auto addIndex = [&indices, mdlMesh, mdlModel, stripGroup](int index) {
92 indices.push_back(stripGroup.vertices.at(index).meshVertexID + mdlMesh.verticesOffset + mdlModel.verticesOffset);
93 };
94
95 // Remember to flip the winding order
96 if (strip.flags & VTX::Strip::FLAG_IS_TRILIST) {
97 for (int i = 0; i < strip.indices.size(); i += 3) {
98 addIndex(strip.indices[ i ]);
99 addIndex(strip.indices[i+2]);
100 addIndex(strip.indices[i+1]);
101 }
102 } else {
103 for (auto i = strip.indices.size() - 1; i >= 2; i -= 3) {
104 addIndex(strip.indices[ i ]);
105 addIndex(strip.indices[i-2]);
106 addIndex(strip.indices[i-1]);
107 }
108 }
109 }
110 }
111
112 model.meshes.push_back({std::move(indices), mdlMesh.material});
113 }
114 }
115 }
116
117 return model;
118}
Definition: mdlpp.h:9
Definition: LZMA.h:11
sourcepp::math::Vec3f position
Definition: mdlpp.h:16
A more accessible version of StudioModel's vertex data, so it can be rendered or converted more easil...
Definition: mdlpp.h:14
std::vector< Vertex > vertices
Definition: mdlpp.h:20
std::vector< Mesh > meshes
Definition: mdlpp.h:26
bool open(const std::byte *data, std::size_t size)
Definition: MDL.cpp:11
std::vector< BodyPart > bodyParts
Definition: MDL.h:339
MDL::MDL mdl
Definition: mdlpp.h:50
bool open(const std::byte *mdlData, std::size_t mdlSize, const std::byte *vtxData, std::size_t vtxSize, const std::byte *vvdData, std::size_t vvdSize)
Definition: mdlpp.cpp:10
BakedModel processModelData(int currentLOD=ROOT_LOD) const
Definition: mdlpp.cpp:53
VVD::VVD vvd
Definition: mdlpp.h:52
VTX::VTX vtx
Definition: mdlpp.h:51
@ FLAG_IS_TRILIST
Definition: VTX.h:22
std::vector< BodyPart > bodyParts
Definition: VTX.h:125
std::vector< Fixup > fixups
Definition: VVD.h:50
std::vector< Vertex > vertices
Definition: VVD.h:53