OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
protomesh.cpp
Go to the documentation of this file.
1#include "protomesh.h"
2
3#include <Tempest/Log>
4
8
9using namespace Tempest;
10
13
14ProtoMesh::ProtoMesh(PackedMesh&& pm, std::string_view fname)
15 :fname(fname) {
16 attach.emplace_back(pm);
17 submeshId.resize(attach[0].sub.size());
18 auto& att = attach[0];
19 att.shape.reset(PhysicMeshShape::load(std::move(pm)));
20
21 size_t count = 0;
22 for(size_t r=0;r<att.sub.size();++r) {
23 if(att.sub[r].material.tex==nullptr) {
24 if(!att.sub[r].texName.empty())
25 Tempest::Log::e("no texture: ",att.sub[r].texName);
26 continue;
27 }
28 submeshId[count].id = 0;
29 submeshId[count].subId = r;
30 count++;
31 }
32 submeshId.resize(count);
33
34 nodes.emplace_back();
35 nodes.back().attachId = 0;
36 nodes.back().submeshIdB = 0;
37 nodes.back().submeshIdE = submeshId.size();
38 nodes.back().transform.identity();
39
40 bbox[0] = pm.bbox().first;
41 bbox[1] = pm.bbox().second;
42 setupScheme(fname);
43 }
44
45ProtoMesh::ProtoMesh(PackedMesh&& pm, const std::vector<zenkit::MorphAnimation>& aniList, std::string_view fname)
46 : ProtoMesh(std::move(pm),fname) {
47 if(attach.size()!=1) {
48 Log::d("skip animations for: ",fname);
49 return;
50 }
51
52 const size_t indexSz = sizeof(int32_t[4])*((pm.verticesId.size()+3)/4);
53 size_t samplesCnt = 0;
54
55 for(auto& i:aniList) {
56 samplesCnt += i.samples.size();
57 }
58
59 morphIndex = Resources::ssbo(Tempest::Uninitialized, indexSz*aniList.size());
60 morphSamples = Resources::ssbo(Tempest::Uninitialized, samplesCnt*sizeof(Vec4));
61
62 std::vector<int32_t> remapId;
63 std::vector<Vec4> samples;
64
65 samplesCnt = 0;
66 morph.resize(aniList.size());
67 for(size_t i=0; i<aniList.size(); ++i) {
68 remap(aniList[i],pm.verticesId,remapId,samples,samplesCnt);
69
70 morphIndex .update(remapId.data(), i*indexSz, remapId.size()*sizeof(remapId[0]));
71 morphSamples.update(samples.data(), samplesCnt*sizeof(Vec4), samples.size()*sizeof(Vec4) );
72
73 morph[i] = mkAnimation(aniList[i]);
74 morph[i].index = (i*indexSz)/sizeof(int32_t);
75
76 samplesCnt += samples.size();
77 }
78
79 if(morph.size()>0) {
80 for(auto& a:attach) {
81 a.morph.anim = &morph;
82 a.morph.index = &morphIndex;
83 a.morph.samples = &morphSamples;
84 }
85 }
86 }
87
88ProtoMesh::ProtoMesh(const zenkit::Model& library, std::unique_ptr<Skeleton>&& sk, std::string_view fname)
89 :skeleton(std::move(sk)), fname(fname) {
90 for(auto& m:library.mesh.attachments) {
91 PackedMesh pack(m.second,PackedMesh::PK_Visual);
92 attach.emplace_back(pack);
93 auto& att = attach.back();
94 att.name = m.first;
95 att.shape.reset(PhysicMeshShape::load(std::move(pack)));
96 }
97
98 nodes.resize(skeleton==nullptr ? 0 : skeleton->nodes.size());
99 for(size_t i=0;i<nodes.size();++i) {
100 Node& n = nodes[i];
101 auto& src = skeleton->nodes[i];
102 for(size_t r=0;r<attach.size();++r)
103 if(attach[r].name==src.name){
104 n.attachId = r;
105 break;
106 }
107 n.parentId = src.parent;
108 n.transform = src.tr;
109 }
110
111 for(auto& i:nodes)
112 if(i.parentId<nodes.size())
113 nodes[i.parentId].hasChild=true;
114
115 size_t subCount=0;
116 for(auto& i:nodes)
117 if(i.attachId<attach.size()) {
118 attach[i.attachId].hasNode = true;
119 subCount+=attach[i.attachId].sub.size();
120 }
121 for(auto& a:attach)
122 if(!a.hasNode)
123 subCount+=a.sub.size();
124 submeshId.resize(subCount);
125
126 subCount=0;
127 for(auto& i:nodes) {
128 i.submeshIdB = subCount;
129 if(i.attachId<attach.size()) {
130 auto& att = attach[i.attachId];
131 for(size_t r=0;r<att.sub.size();++r){
132 if(att.sub[r].material.tex==nullptr) {
133 if(!att.sub[r].texName.empty())
134 Tempest::Log::e("no texture: ",att.sub[r].texName);
135 continue;
136 }
137 submeshId[subCount].id = i.attachId;
138 submeshId[subCount].subId = r;
139 subCount++;
140 }
141 }
142 i.submeshIdE = subCount;
143 }
144 submeshId.resize(subCount);
145
146 for(size_t i=0;i<library.mesh.meshes.size();++i){
147 auto& mesh = library.mesh.meshes[i];
148 PackedMesh pkg(mesh);
149 skined.emplace_back(pkg);
150 }
151
152 if(skeleton!=nullptr) {
153 for(size_t i=0;i<skeleton->nodes.size();++i) {
154 auto& n=skeleton->nodes[i];
155 if(n.name.find("ZS_POS")==0){
156 Pos p;
157 p.name = n.name;
158 p.node = i;
159 p.transform = n.tr;
160 pos.push_back(p);
161 }
162 }
163 }
164 setupScheme(fname);
165 }
166
167ProtoMesh::ProtoMesh(const zenkit::ModelHierarchy& library, std::unique_ptr<Skeleton>&& sk, std::string_view fname)
168 :skeleton(std::move(sk)), fname(fname) {
169 nodes.resize(skeleton == nullptr ? 0 : skeleton->nodes.size());
170 for(size_t i = 0; i < nodes.size(); ++i) {
171 Node& n = nodes[i];
172 auto& src = skeleton->nodes[i];
173 n.parentId = src.parent;
174 n.transform = src.tr;
175 }
176
177 for(auto& i : nodes)
178 if(i.parentId < nodes.size())
179 nodes[i.parentId].hasChild = true;
180
181 size_t subCount = 0;
182 for(auto& i : nodes) {
183 i.submeshIdB = subCount;
184 i.submeshIdE = subCount;
185 }
186 submeshId.resize(subCount);
187
188 if(skeleton != nullptr) {
189 for(size_t i = 0; i < skeleton->nodes.size(); ++i) {
190 auto& n = skeleton->nodes[i];
191 if(n.name.find("ZS_POS") == 0) {
192 Pos p;
193 p.name = n.name;
194 p.node = i;
195 p.transform = n.tr;
196 pos.push_back(p);
197 }
198 }
199 }
200 setupScheme(fname);
201 }
202
203ProtoMesh::ProtoMesh(const zenkit::ModelMesh& library, std::unique_ptr<Skeleton>&& sk, std::string_view fname)
204 :skeleton(std::move(sk)), fname(fname){
205 for(auto& m:library.attachments) {
206 PackedMesh pack(m.second,PackedMesh::PK_Visual);
207 attach.emplace_back(pack);
208 auto& att = attach.back();
209 att.name = m.first;
210 att.shape.reset(PhysicMeshShape::load(std::move(pack)));
211 }
212
213 nodes.resize(skeleton==nullptr ? 0 : skeleton->nodes.size());
214 for(size_t i=0;i<nodes.size();++i) {
215 Node& n = nodes[i];
216 auto& src = skeleton->nodes[i];
217 for(size_t r=0;r<attach.size();++r)
218 if(attach[r].name==src.name){
219 n.attachId = r;
220 break;
221 }
222 n.parentId = src.parent;
223 n.transform = src.tr;
224 }
225
226 for(auto& i:nodes)
227 if(i.parentId<nodes.size())
228 nodes[i.parentId].hasChild=true;
229
230 size_t subCount=0;
231 for(auto& i:nodes)
232 if(i.attachId<attach.size()) {
233 attach[i.attachId].hasNode = true;
234 subCount+=attach[i.attachId].sub.size();
235 }
236 for(auto& a:attach)
237 if(!a.hasNode)
238 subCount+=a.sub.size();
239 submeshId.resize(subCount);
240
241 subCount=0;
242 for(auto& i:nodes) {
243 i.submeshIdB = subCount;
244 if(i.attachId<attach.size()) {
245 auto& att = attach[i.attachId];
246 for(size_t r=0;r<att.sub.size();++r){
247 if(att.sub[r].material.tex==nullptr) {
248 if(!att.sub[r].texName.empty())
249 Tempest::Log::e("no texture: ",att.sub[r].texName);
250 continue;
251 }
252 submeshId[subCount].id = i.attachId;
253 submeshId[subCount].subId = r;
254 subCount++;
255 }
256 }
257 i.submeshIdE = subCount;
258 }
259 submeshId.resize(subCount);
260
261 for(const auto &i : library.meshes) {
262 if(i.weights.size()<i.mesh.positions.size()){
263 Log::e("Vertex stream for skin-mesh \"", fname, "\" is too small");
264 }
265 PackedMesh pkg(i);
266 skined.emplace_back(pkg);
267 }
268
269 if(skeleton!=nullptr) {
270 for(size_t i=0;i<skeleton->nodes.size();++i) {
271 auto& n=skeleton->nodes[i];
272 if(n.name.find("ZS_POS")==0){
273 Pos p;
274 p.name = n.name;
275 p.node = i;
276 p.transform = n.tr;
277 pos.push_back(p);
278 }
279 }
280 }
281 setupScheme(fname);
282 }
283
284ProtoMesh::ProtoMesh(const Material& mat, std::vector<Resources::Vertex> vbo, std::vector<uint32_t> ibo) {
285 attach.emplace_back(mat,std::move(vbo),std::move(ibo));
286 submeshId.resize(attach[0].sub.size());
287 auto& att = attach[0];
288
289 size_t count = 0;
290 for(size_t r=0;r<att.sub.size();++r) {
291 if(att.sub[r].material.tex==nullptr) {
292 if(!att.sub[r].texName.empty())
293 Tempest::Log::e("no texture: ",att.sub[r].texName);
294 continue;
295 }
296 submeshId[count].id = 0;
297 submeshId[count].subId = r;
298 count++;
299 }
300 submeshId.resize(count);
301
302 nodes.emplace_back();
303 nodes.back().attachId = 0;
304 nodes.back().submeshIdB = 0;
305 nodes.back().submeshIdE = submeshId.size();
306 nodes.back().transform.identity();
307
308 setupScheme("");
309 }
310
313
315 size_t ret=0;
316 for(auto& i:skined)
317 ret+=i.sub.size();
318 return ret;
319 }
320
321Tempest::Matrix4x4 ProtoMesh::mapToRoot(size_t n) const {
322 Tempest::Matrix4x4 m;
323 m.identity();
324
325 while(n<nodes.size()) {
326 auto& nx = nodes[n];
327 auto mx = nx.transform;
328 mx.mul(m);
329 m = mx;
330 n = nx.parentId;
331 }
332 return m;
333 }
334
335size_t ProtoMesh::findNode(std::string_view name, size_t def) const {
336 if(skeleton==nullptr)
337 return def;
338 return skeleton->findNode(name,def);
339 }
340
341void ProtoMesh::setupScheme(std::string_view s) {
342 auto sep = s.find("_");
343 if(sep!=std::string::npos) {
344 scheme = s.substr(0,sep);
345 return;
346 }
347 sep = s.rfind(".");
348 if(sep!=std::string::npos) {
349 scheme = s.substr(0,sep);
350 return;
351 }
352 scheme = s;
353 }
354
355void ProtoMesh::remap(const zenkit::MorphAnimation& a,
356 const std::vector<uint32_t>& vertId,
357 std::vector<int32_t>& remap,
358 std::vector<Tempest::Vec4>& samples,
359 size_t idOffset) {
360 size_t indexSz = ((vertId.size()+3)/4)*4;
361 remap.resize(indexSz);
362 for(auto& i:remap)
363 i = -1;
364 for(size_t i=0; i<vertId.size(); ++i) {
365 const uint32_t id = vertId[i];
366 for(size_t r=0; r<a.vertices.size(); ++r)
367 if(a.vertices[r]==id) {
368 remap[i] = int(r+idOffset);
369 break;
370 }
371 }
372
373 samples.resize(a.samples.size());
374 for(size_t i=0; i<a.samples.size(); ++i) {
375 auto& s = a.samples[i];
376 samples[i] = Tempest::Vec4(s.x,s.y,s.z,0);
377 }
378}
379
380ProtoMesh::Morph ProtoMesh::mkAnimation(const zenkit::MorphAnimation& a) {
381 Morph ret;
382 ret.name = a.name;
383 ret.numFrames = a.frame_count;
384 ret.samplesPerFrame = a.samples.size()/a.frame_count;
385 ret.layer = a.layer;
386 ret.duration = uint64_t(a.duration>0 ? a.duration : 0);
387
388 if(a.flags&0x2 || a.duration<=0)
389 ret.tickPerFrame = size_t(1.f/a.speed); else
390 ret.tickPerFrame = size_t(a.duration/float(a.frame_count));
391
392 if(ret.tickPerFrame==0)
393 ret.tickPerFrame = 1;
394 return ret;
395 }
static PhysicMeshShape * load(PackedMesh &&packed)
std::unique_ptr< Skeleton > skeleton
Definition protomesh.h:76
std::string fname
Definition protomesh.h:89
std::string scheme
Definition protomesh.h:89
std::vector< AnimMesh > skined
Definition protomesh.h:77
Tempest::StorageBuffer morphSamples
Definition protomesh.h:80
std::vector< Attach > attach
Definition protomesh.h:82
std::vector< Pos > pos
Definition protomesh.h:86
std::vector< Node > nodes
Definition protomesh.h:83
std::vector< Morph > morph
Definition protomesh.h:78
ProtoMesh(PackedMesh &&pm, std::string_view fname)
Definition protomesh.cpp:14
Tempest::Vec3 bbox[2]
Definition protomesh.h:87
size_t skinedNodesCount() const
std::vector< SubMeshId > submeshId
Definition protomesh.h:84
StaticMesh::Morph Morph
Definition protomesh.h:73
Tempest::StorageBuffer morphIndex
Definition protomesh.h:79
size_t findNode(std::string_view name, size_t def=size_t(-1)) const
Tempest::Matrix4x4 mapToRoot(size_t node) const
static Tempest::StorageBuffer ssbo(const void *data, size_t size)
Definition resources.h:125
Tempest::Matrix4x4 transform
Definition protomesh.h:50
size_t parentId
Definition protomesh.h:48
size_t attachId
Definition protomesh.h:47
std::string name
Definition protomesh.h:68
Tempest::Matrix4x4 transform
Definition protomesh.h:69
std::string name
Definition staticmesh.h:32