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