Line data Source code
1 : /* vertmodel.cpp: vertex model support
2 : */
3 : #include "../libprimis-headers/cube.h"
4 : #include "../../shared/geomexts.h"
5 : #include "../../shared/glemu.h"
6 : #include "../../shared/glexts.h"
7 :
8 : #include <format>
9 : #include <memory>
10 : #include <optional>
11 :
12 : #include "interface/console.h"
13 : #include "interface/control.h"
14 :
15 : #include "render/rendergl.h"
16 : #include "render/renderlights.h"
17 : #include "render/rendermodel.h"
18 : #include "render/shader.h"
19 : #include "render/shaderparam.h"
20 : #include "render/texture.h"
21 :
22 : #include "world/entities.h"
23 : #include "world/octaworld.h"
24 : #include "world/bih.h"
25 :
26 : #include "model.h"
27 : #include "ragdoll.h"
28 : #include "animmodel.h"
29 : #include "vertmodel.h"
30 :
31 : //==============================================================================
32 : // vertmodel object
33 : //==============================================================================
34 :
35 0 : vertmodel::meshgroup * vertmodel::loadmeshes(const char *name, float smooth)
36 : {
37 0 : vertmeshgroup *group = newmeshes();
38 0 : if(!group->load(name, smooth))
39 : {
40 0 : delete group;
41 0 : return nullptr;
42 : }
43 0 : return group;
44 : }
45 :
46 0 : vertmodel::meshgroup * vertmodel::sharemeshes(const char *name, float smooth)
47 : {
48 0 : if(meshgroups.find(name) == meshgroups.end())
49 : {
50 0 : meshgroup *group = loadmeshes(name, smooth);
51 0 : if(!group)
52 : {
53 0 : return nullptr;
54 : }
55 0 : meshgroups[group->groupname()] = group;
56 : }
57 0 : return meshgroups[name];
58 : }
59 :
60 0 : vertmodel::vertmodel(std::string name) : animmodel(std::move(name))
61 : {
62 0 : }
63 :
64 : //==============================================================================
65 : // vertmodel::vbocacheentry object
66 : //==============================================================================
67 :
68 0 : vertmodel::vbocacheentry::vbocacheentry() : vbuf(0)
69 : {
70 0 : as.cur.fr1 = as.prev.fr1 = -1;
71 0 : }
72 :
73 : //==============================================================================
74 : // vertmodel::vertmesh object
75 : //==============================================================================
76 :
77 0 : vertmodel::vertmesh::vertmesh() : verts(0), tcverts(0), tris(0)
78 : {
79 0 : }
80 :
81 0 : vertmodel::vertmesh::vertmesh(std::string_view name, meshgroup *m) :
82 : Mesh(name, m),
83 0 : verts(0),
84 0 : tcverts(0),
85 0 : tris(0)
86 : {
87 0 : }
88 :
89 0 : vertmodel::vertmesh::~vertmesh()
90 : {
91 0 : delete[] verts;
92 0 : delete[] tcverts;
93 0 : delete[] tris;
94 0 : }
95 :
96 0 : void vertmodel::vertmesh::smoothnorms(float limit, bool areaweight)
97 : {
98 0 : if((static_cast<vertmeshgroup *>(group))->numframes == 1)
99 : {
100 0 : Mesh::smoothnorms<vertmodel>(verts, numverts, tris, numtris, limit, areaweight);
101 : }
102 : else
103 : {
104 0 : buildnorms(areaweight);
105 : }
106 0 : }
107 :
108 0 : void vertmodel::vertmesh::buildnorms(bool areaweight)
109 : {
110 0 : Mesh::buildnorms<vertmodel>(verts, numverts, tris, numtris, areaweight, (static_cast<vertmeshgroup *>(group))->numframes);
111 0 : }
112 :
113 0 : void vertmodel::vertmesh::calctangents(bool areaweight)
114 : {
115 0 : Mesh::calctangents<vertmodel, vertmodel::tcvert>(verts, tcverts, numverts, tris, numtris, areaweight, (static_cast<vertmeshgroup *>(group))->numframes);
116 0 : }
117 :
118 0 : void vertmodel::vertmesh::calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) const
119 : {
120 0 : for(int j = 0; j < numverts; ++j)
121 : {
122 0 : vec v = m.transform(verts[j].pos);
123 0 : bbmin.min(v);
124 0 : bbmax.max(v);
125 : }
126 0 : }
127 :
128 0 : void vertmodel::vertmesh::genBIH(BIH::mesh &m) const
129 : {
130 0 : m.setmesh(reinterpret_cast<const BIH::mesh::tri *>(tris), numtris,
131 0 : reinterpret_cast<const uchar *>(&verts->pos), sizeof(vert),
132 0 : reinterpret_cast<const uchar *>(&tcverts->tc), sizeof(tcvert));
133 0 : }
134 :
135 0 : void vertmodel::vertmesh::genshadowmesh(std::vector<triangle> &out, const matrix4x3 &m) const
136 : {
137 0 : for(int j = 0; j < numtris; ++j)
138 : {
139 0 : out.emplace_back(m.transform(verts[tris[j].vert[0]].pos),
140 0 : m.transform(verts[tris[j].vert[1]].pos),
141 0 : m.transform(verts[tris[j].vert[2]].pos));
142 : }
143 0 : }
144 :
145 0 : void vertmodel::vertmesh::assignvert(vvertg &vv, const tcvert &tc, const vert &v)
146 : {
147 0 : vv.pos = vec4<half>(v.pos, 1);
148 0 : vv.tc = tc.tc;
149 0 : vv.tangent = v.tangent;
150 0 : }
151 :
152 0 : int vertmodel::vertmesh::genvbo(std::vector<uint> &idxs, int offset)
153 : {
154 0 : voffset = offset;
155 0 : for(int i = 0; i < numtris; ++i)
156 : {
157 0 : const tri &t = tris[i];
158 0 : for(int j = 0; j < 3; ++j)
159 : {
160 0 : idxs.push_back(voffset+t.vert[j]);
161 : }
162 : }
163 0 : minvert = voffset;
164 0 : maxvert = voffset + numverts-1;
165 0 : elen = idxs.size();
166 0 : return numverts;
167 : }
168 :
169 0 : void vertmodel::vertmesh::render() const
170 : {
171 0 : if(!Shader::lastshader)
172 : {
173 0 : return;
174 : }
175 0 : glDrawRangeElements(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_INT, nullptr);
176 0 : glde++;
177 0 : xtravertsva += numverts;
178 : }
179 :
180 : //==============================================================================
181 : // vertmodel::vertmeshgroup object
182 : //==============================================================================
183 :
184 0 : vertmodel::vertmeshgroup::vertmeshgroup()
185 0 : : numframes(0), tags(nullptr), numtags(0), ebuf(0), vlen(0), vertsize(0), vdata(nullptr)
186 : {
187 0 : }
188 :
189 0 : vertmodel::vertmeshgroup::~vertmeshgroup()
190 : {
191 0 : delete[] tags;
192 0 : if(ebuf)
193 : {
194 0 : glDeleteBuffers(1, &ebuf);
195 : }
196 0 : for(size_t i = 0; i < maxvbocache; ++i)
197 : {
198 0 : if(vbocache[i].vbuf)
199 : {
200 0 : glDeleteBuffers(1, &vbocache[i].vbuf);
201 : }
202 : }
203 0 : delete[] vdata;
204 0 : }
205 :
206 0 : void vertmodel::vertmeshgroup::concattagtransform(int, const matrix4x3 &, matrix4x3 &) const
207 : {
208 0 : }
209 :
210 0 : std::optional<size_t> vertmodel::vertmeshgroup::findtag(std::string_view name)
211 : {
212 0 : for(size_t i = 0; i < numtags; ++i)
213 : {
214 0 : if(tags[i].name == name)
215 : {
216 0 : return i;
217 : }
218 : }
219 0 : return std::nullopt;
220 : }
221 :
222 0 : bool vertmodel::vertmeshgroup::addtag(std::string_view name, const matrix4x3 &matrix)
223 : {
224 0 : std::optional<size_t> idx = findtag(name);
225 0 : if(idx)
226 : {
227 0 : if(!testtags)
228 : {
229 0 : return false;
230 : }
231 0 : for(int i = 0; i < numframes; ++i)
232 : {
233 0 : tag &t = tags[i*numtags + *idx];
234 0 : t.matrix = matrix;
235 : }
236 : }
237 : else
238 : {
239 0 : tag *newtags = new tag[(numtags+1)*numframes];
240 0 : for(int i = 0; i < numframes; ++i)
241 : {
242 0 : tag *dst = &newtags[(numtags+1)*i],
243 0 : *src = &tags[numtags*i];
244 0 : if(!i)
245 : {
246 0 : for(size_t j = 0; j < numtags; ++j)
247 : {
248 0 : std::swap(dst[j].name, src[j].name);
249 : }
250 0 : dst[numtags].name = name;
251 : }
252 0 : for(size_t j = 0; j < numtags; ++j)
253 : {
254 0 : dst[j].matrix = src[j].matrix;
255 : }
256 0 : dst[numtags].matrix = matrix;
257 : }
258 0 : if(tags)
259 : {
260 0 : delete[] tags;
261 : }
262 0 : tags = newtags;
263 0 : numtags++;
264 : }
265 0 : return true;
266 : }
267 :
268 0 : int vertmodel::vertmeshgroup::totalframes() const
269 : {
270 0 : return numframes;
271 : }
272 :
273 0 : void vertmodel::vertmeshgroup::calctagmatrix(const part *p, int i, const AnimState &as, matrix4 &matrix) const
274 : {
275 0 : const matrix4x3 &tag1 = tags[as.cur.fr1*numtags + i].matrix,
276 0 : &tag2 = tags[as.cur.fr2*numtags + i].matrix;
277 0 : matrix4x3 tag;
278 0 : tag.lerp(tag1, tag2, as.cur.t);
279 0 : if(as.interp<1)
280 : {
281 0 : const matrix4x3 &tag1p = tags[as.prev.fr1*numtags + i].matrix,
282 0 : &tag2p = tags[as.prev.fr2*numtags + i].matrix;
283 0 : matrix4x3 tagp;
284 0 : tagp.lerp(tag1p, tag2p, as.prev.t);
285 0 : tag.lerp(tagp, tag, as.interp);
286 : }
287 0 : tag.d.mul(p->model->locationsize().w * sizescale);
288 0 : matrix = matrix4(tag);
289 0 : }
290 :
291 0 : void vertmodel::vertmeshgroup::genvbo(vbocacheentry &vc)
292 : {
293 0 : if(!vc.vbuf)
294 : {
295 0 : glGenBuffers(1, &vc.vbuf);
296 : }
297 0 : if(ebuf)
298 : {
299 0 : return;
300 : }
301 :
302 0 : std::vector<uint> idxs;
303 0 : std::vector<std::vector<animmodel::Mesh *>::iterator> rendermeshes = getrendermeshes();
304 0 : vlen = 0;
305 0 : if(numframes>1)
306 : {
307 0 : vertsize = sizeof(vvert);
308 :
309 0 : for(auto i : rendermeshes)
310 : {
311 0 : vlen += static_cast<vertmesh *>(*i)->genvbo(idxs, vlen);
312 : }
313 0 : delete[] vdata;
314 0 : vdata = new uchar[vlen*vertsize];
315 0 : for(auto i : rendermeshes)
316 : {
317 0 : static_cast<vertmesh *>(*i)->fillverts(reinterpret_cast<vvert *>(vdata));
318 : }
319 : }
320 : else
321 : {
322 0 : vertsize = sizeof(vvertg);
323 0 : gle::bindvbo(vc.vbuf);
324 0 : size_t numverts = 0,
325 0 : htlen = 128;
326 0 : for(auto i : rendermeshes)
327 : {
328 0 : numverts += static_cast<vertmesh *>(*i)->numverts;
329 : }
330 0 : while(htlen < numverts)
331 : {
332 0 : htlen *= 2;
333 : }
334 0 : if(numverts*4 > htlen*3)
335 : {
336 0 : htlen *= 2;
337 : }
338 0 : int *htdata = new int[htlen];
339 0 : std::memset(htdata, -1, htlen*sizeof(int));
340 0 : std::vector<vvertg> vverts;
341 0 : for(auto i : rendermeshes)
342 : {
343 0 : vlen += static_cast<vertmesh *>(*i)->genvbo(idxs, vlen, vverts, htdata, htlen);
344 : }
345 0 : glBufferData(GL_ARRAY_BUFFER, vverts.size()*sizeof(vvertg), vverts.data(), GL_STATIC_DRAW);
346 0 : delete[] htdata;
347 0 : htdata = nullptr;
348 0 : gle::clearvbo();
349 0 : }
350 :
351 0 : glGenBuffers(1, &ebuf);
352 0 : gle::bindebo(ebuf);
353 0 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxs.size()*sizeof(uint), idxs.data(), GL_STATIC_DRAW);
354 0 : gle::clearebo();
355 0 : }
356 :
357 0 : void vertmodel::vertmeshgroup::bindvbo(const AnimState *as, const part *p, const vbocacheentry &vc)
358 : {
359 0 : if(numframes>1)
360 : {
361 0 : bindvbo<vvert>(as, p, vc);
362 : }
363 : else
364 : {
365 0 : bindvbo<vvertg>(as, p, vc);
366 : }
367 0 : }
368 :
369 0 : void *vertmodel::vertmeshgroup::animkey()
370 : {
371 0 : return this;
372 : }
373 :
374 0 : void vertmodel::vertmeshgroup::cleanup()
375 : {
376 0 : for(size_t i = 0; i < maxvbocache; ++i)
377 : {
378 0 : vbocacheentry &c = vbocache[i];
379 0 : if(c.vbuf)
380 : {
381 0 : glDeleteBuffers(1, &c.vbuf);
382 0 : c.vbuf = 0;
383 : }
384 0 : c.as.cur.fr1 = -1;
385 : }
386 0 : if(ebuf)
387 : {
388 0 : glDeleteBuffers(1, &ebuf);
389 0 : ebuf = 0;
390 : }
391 0 : }
392 :
393 0 : void vertmodel::vertmeshgroup::preload()
394 : {
395 0 : if(numframes > 1)
396 : {
397 0 : return;
398 : }
399 0 : if(!vbocache[0].vbuf)
400 : {
401 0 : genvbo(vbocache[0]);
402 : }
403 : }
404 :
405 0 : void vertmodel::vertmeshgroup::render(const AnimState *as, float, const vec &, const vec &, dynent *, part *p)
406 : {
407 0 : if(as->cur.anim & Anim_NoRender)
408 : {
409 0 : for(part::linkedpart &l : p->links)
410 : {
411 0 : calctagmatrix(p, l.tag, *as, l.matrix);
412 : }
413 0 : return;
414 : }
415 0 : vbocacheentry *vc = nullptr;
416 0 : if(numframes<=1)
417 : {
418 0 : vc = vbocache.data();
419 : }
420 : else
421 : {
422 0 : for(size_t i = 0; i < maxvbocache; ++i)
423 : {
424 0 : vbocacheentry &c = vbocache[i];
425 0 : if(!c.vbuf)
426 : {
427 0 : continue;
428 : }
429 0 : if(c.as==*as)
430 : {
431 0 : vc = &c;
432 0 : break;
433 : }
434 : }
435 0 : if(!vc)
436 : {
437 0 : for(size_t i = 0; i < maxvbocache; ++i)
438 : {
439 0 : vc = &vbocache[i];
440 0 : if(!vc->vbuf || vc->millis < lastmillis)
441 : {
442 : break;
443 : }
444 : }
445 : }
446 : }
447 0 : if(!vc->vbuf)
448 : {
449 0 : genvbo(*vc);
450 : }
451 0 : if(numframes>1)
452 : {
453 0 : if(vc->as!=*as)
454 : {
455 0 : vc->as = *as;
456 0 : vc->millis = lastmillis;
457 0 : auto rendermeshes = getrendermeshes();
458 0 : for(auto i : rendermeshes)
459 : {
460 0 : static_cast<vertmesh *>(*i)->interpverts(*as, reinterpret_cast<vvert *>(vdata));
461 : }
462 0 : gle::bindvbo(vc->vbuf);
463 0 : glBufferData(GL_ARRAY_BUFFER, vlen*vertsize, vdata, GL_STREAM_DRAW);
464 0 : }
465 0 : vc->millis = lastmillis;
466 : }
467 0 : bindvbo(as, p, *vc);
468 0 : LOOP_RENDER_MESHES(vertmesh, m,
469 : {
470 : p->skins[i].bind(m, as); //not a skeletal model, do not need to include trailing params
471 : m.render();
472 : });
473 0 : for(part::linkedpart &l : p->links)
474 : {
475 0 : calctagmatrix(p, l.tag, *as, l.matrix);
476 : }
477 : }
|