Line data Source code
1 : // octarender.cpp: fill vertex arrays with different cube surfaces.
2 : #include "../libprimis-headers/cube.h"
3 : #include "../../shared/geomexts.h"
4 : #include "../../shared/glemu.h"
5 : #include "../../shared/glexts.h"
6 :
7 : #include "grass.h"
8 : #include "octarender.h"
9 : #include "rendergl.h"
10 : #include "renderlights.h"
11 : #include "renderparticles.h"
12 : #include "rendersky.h"
13 : #include "renderva.h"
14 : #include "shader.h"
15 : #include "shaderparam.h"
16 : #include "texture.h"
17 : #include "vacollect.h"
18 :
19 : #include "interface/menus.h"
20 :
21 : #include "world/entities.h"
22 : #include "world/light.h"
23 : #include "world/material.h"
24 : #include "world/octaworld.h"
25 : #include "world/world.h"
26 :
27 :
28 : /* global variables */
29 : //////////////////////
30 :
31 : int allocva = 0,
32 : wtris = 0,
33 : wverts = 0,
34 : vtris = 0,
35 : vverts = 0,
36 : glde = 0,
37 : gbatches = 0;
38 :
39 :
40 : /**
41 : * @brief List of all vertex arrays
42 : *
43 : * A vector that carries identically all elements also in the various varoot objects.
44 : * The entries in the vector will first be the children of varoot[0] followed by
45 : * varoot[0] itself, followed by the same for the other VAs in varoot. The last
46 : * element should always be `varoot[7]`.
47 : */
48 : std::vector<vtxarray *> valist;
49 :
50 : /**
51 : * @brief List of top level vertex arrays
52 : *
53 : * A vector containing the highest-level vertex array objects.
54 : * There will always be at least eight VAs in varoot, corresponding to the eight
55 : * subdivisions of the worldroot cube.
56 : *
57 : * If the eight subdivisions of the worldroot cube are larger than `vamaxsize`,
58 : * these cubes will not host the root VA; children of these cubes will be assigned
59 : * the root VAs by dropping through child nodes until the cube is no larger than
60 : * `vamaxsize`. For a worldroot 4x the linear size of `vamaxsize` this will yield 64
61 : * entries in varoot; for a worldroot 8x the linear size, this will yield 512 entries
62 : * and so on.
63 : */
64 : std::vector<vtxarray *> varoot;
65 :
66 : ivec worldmin(0, 0, 0),
67 : worldmax(0, 0, 0);
68 :
69 : std::vector<tjoint> tjoints;
70 :
71 0 : VARFP(filltjoints, 0, 1, 1, rootworld.allchanged()); //eliminate "sparklies" by filling in geom t-joints
72 :
73 : /* internally relevant functionality */
74 : ///////////////////////////////////////
75 :
76 : //edgegroup: struct used for tjoint joining (to reduce sparklies between geom faces)
77 : struct EdgeGroup final
78 : {
79 : ivec slope, origin;
80 : int axis;
81 :
82 : EdgeGroup();
83 :
84 0 : bool operator==(const EdgeGroup &y) const
85 : {
86 0 : return slope==y.slope && origin==y.origin;
87 : }
88 : };
89 :
90 0 : EdgeGroup::EdgeGroup()
91 : {
92 0 : axis = 0;
93 0 : }
94 :
95 : template<>
96 : struct std::hash<EdgeGroup> final
97 : {
98 0 : size_t operator()(const EdgeGroup &g) const
99 : {
100 0 : return g.slope.x^g.slope.y^g.slope.z^g.origin.x^g.origin.y^g.origin.z;
101 : }
102 : };
103 :
104 : namespace
105 : {
106 : enum
107 : {
108 : CubeEdge_Start = 1<<0,
109 : CubeEdge_End = 1<<1,
110 : CubeEdge_Flip = 1<<2,
111 : CubeEdge_Dup = 1<<3
112 : };
113 :
114 : struct CubeEdge final
115 : {
116 : cube *c;
117 : int next, offset;
118 : ushort size;
119 : uchar index, flags;
120 : };
121 :
122 : std::vector<CubeEdge> cubeedges;
123 : std::unordered_map<EdgeGroup, int> edgegroups;
124 :
125 0 : void gencubeedges(cube &c, const ivec &co, int size)
126 : {
127 0 : std::array<ivec, Face_MaxVerts> pos;
128 : int vis;
129 0 : for(int i = 0; i < 6; ++i)
130 : {
131 0 : if((vis = visibletris(c, i, co, size)))
132 : {
133 0 : int numverts = c.ext ? c.ext->surfaces[i].numverts&Face_MaxVerts : 0;
134 0 : if(numverts)
135 : {
136 0 : const vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
137 0 : ivec vo = ivec(co).mask(~0xFFF).shl(3);
138 0 : for(int j = 0; j < numverts; ++j)
139 : {
140 0 : const vertinfo &v = verts[j];
141 0 : pos[j] = ivec(v.x, v.y, v.z).add(vo);
142 : }
143 : }
144 0 : else if(c.merged&(1<<i))
145 : {
146 0 : continue;
147 : }
148 : else
149 : {
150 0 : std::array <ivec, 4> v;
151 0 : genfaceverts(c, i, v);
152 0 : int order = vis&4 || (!flataxisface(c, i) && faceconvexity(v) < 0) ? 1 : 0;
153 0 : ivec vo = ivec(co).shl(3);
154 0 : pos[numverts++] = v[order].mul(size).add(vo);
155 0 : if(vis&1)
156 : {
157 0 : pos[numverts++] = v[order+1].mul(size).add(vo);
158 : }
159 0 : pos[numverts++] = v[order+2].mul(size).add(vo);
160 0 : if(vis&2)
161 : {
162 0 : pos[numverts++] = v[(order+3)&3].mul(size).add(vo);
163 : }
164 : }
165 0 : for(int j = 0; j < numverts; ++j)
166 : {
167 0 : int e1 = j,
168 0 : e2 = j+1 < numverts ? j+1 : 0;
169 0 : ivec d = pos[e2];
170 0 : d.sub(pos[e1]);
171 0 : if(!d)
172 : {
173 0 : continue;
174 : }
175 : //axistemp1/2 used in `axis` only
176 : // x = 0, y = 1, z = 2, `int axis` is the largest component of `d` using
177 : // axistemp1/2 to determine if x,y > z and then if x > y
178 0 : int axistemp1 = std::abs(d.x) > std::abs(d.z) ? 0 : 2,
179 0 : axistemp2 = std::abs(d.y) > std::abs(d.z) ? 1 : 2,
180 0 : axis = std::abs(d.x) > std::abs(d.y) ? axistemp1 : axistemp2;
181 0 : if(d[axis] < 0)
182 : {
183 0 : d.neg();
184 0 : std::swap(e1, e2);
185 : }
186 0 : reduceslope(d);
187 0 : int t1 = pos[e1][axis]/d[axis],
188 0 : t2 = pos[e2][axis]/d[axis];
189 0 : EdgeGroup g;
190 0 : g.origin = ivec(pos[e1]).sub(ivec(d).mul(t1));
191 0 : g.slope = d;
192 0 : g.axis = axis;
193 : CubeEdge ce;
194 0 : ce.c = &c;
195 0 : ce.offset = t1;
196 0 : ce.size = t2 - t1;
197 0 : ce.index = i*(Face_MaxVerts+1)+j;
198 0 : ce.flags = CubeEdge_Start | CubeEdge_End | (e1!=j ? CubeEdge_Flip : 0);
199 0 : ce.next = -1;
200 0 : bool insert = true;
201 0 : std::unordered_map<EdgeGroup, int>::iterator exists = edgegroups.find(g);
202 0 : if(exists != edgegroups.end())
203 : {
204 0 : int prev = -1,
205 0 : cur = (*exists).second;
206 0 : while(cur >= 0)
207 : {
208 0 : CubeEdge &p = cubeedges[cur];
209 0 : if(p.flags&CubeEdge_Dup ?
210 0 : ce.offset>=p.offset && ce.offset+ce.size<=p.offset+p.size :
211 0 : ce.offset==p.offset && ce.size==p.size)
212 : {
213 0 : p.flags |= CubeEdge_Dup;
214 0 : insert = false;
215 0 : break;
216 : }
217 0 : else if(ce.offset >= p.offset)
218 : {
219 0 : if(ce.offset == p.offset+p.size)
220 : {
221 0 : ce.flags &= ~CubeEdge_Start;
222 : }
223 0 : prev = cur;
224 0 : cur = p.next;
225 : }
226 : else
227 : {
228 0 : break;
229 : }
230 : }
231 0 : if(insert)
232 : {
233 0 : ce.next = cur;
234 0 : while(cur >= 0)
235 : {
236 0 : const CubeEdge &p = cubeedges[cur];
237 0 : if(ce.offset+ce.size==p.offset)
238 : {
239 0 : ce.flags &= ~CubeEdge_End;
240 0 : break;
241 : }
242 0 : cur = p.next;
243 : }
244 0 : if(prev>=0)
245 : {
246 0 : cubeedges[prev].next = cubeedges.size();
247 : }
248 : else
249 : {
250 0 : (*exists).second = cubeedges.size();
251 : }
252 : }
253 : }
254 : else
255 : {
256 0 : edgegroups[g] = cubeedges.size();
257 : }
258 0 : if(insert)
259 : {
260 0 : cubeedges.push_back(ce);
261 : }
262 : }
263 : }
264 : }
265 0 : }
266 :
267 0 : void gencubeedges(std::array<cube, 8> &c, const ivec &co = ivec(0, 0, 0), int size = rootworld.mapsize()>>1)
268 : {
269 0 : neighborstack[++neighbordepth] = &c[0];
270 0 : for(int i = 0; i < 8; ++i)
271 : {
272 0 : ivec o(i, co, size);
273 0 : if(c[i].ext)
274 : {
275 0 : c[i].ext->tjoints = -1;
276 : }
277 0 : if(c[i].children)
278 : {
279 0 : gencubeedges(*(c[i].children), o, size>>1);
280 : }
281 0 : else if(!(c[i].isempty()))
282 : {
283 0 : gencubeedges(c[i], o, size);
284 : }
285 : }
286 0 : --neighbordepth;
287 0 : }
288 :
289 0 : void addtjoint(const EdgeGroup &g, const CubeEdge &e, int offset)
290 : {
291 0 : const int vcoord = (g.slope[g.axis]*offset + g.origin[g.axis]) & 0x7FFF;
292 0 : tjoint tj = tjoint();
293 0 : tj.offset = vcoord / g.slope[g.axis];
294 0 : tj.edge = e.index;
295 0 : int prev = -1,
296 0 : cur = ext(*e.c).tjoints;
297 0 : while(cur >= 0)
298 : {
299 0 : const tjoint &o = tjoints[cur];
300 0 : if(tj.edge < o.edge || (tj.edge==o.edge && (e.flags&CubeEdge_Flip ? tj.offset > o.offset : tj.offset < o.offset)))
301 : {
302 : break;
303 : }
304 0 : prev = cur;
305 0 : cur = o.next;
306 : }
307 0 : tj.next = cur;
308 0 : tjoints.push_back(tj);
309 0 : if(prev < 0)
310 : {
311 0 : e.c->ext->tjoints = tjoints.size()-1;
312 : }
313 : else
314 : {
315 0 : tjoints[prev].next = tjoints.size()-1;
316 : }
317 0 : }
318 :
319 :
320 : /**
321 : * @brief Calls lookupvslot for textures associated with the VA list
322 : *
323 : * Searches the VA list for all associated texture indices and calls lookupvslot
324 : * for each one found. Only calls once even if multiple VAs share the same
325 : * texture.
326 : */
327 0 : void precachetextures()
328 : {
329 0 : std::vector<int> texs;
330 0 : for(size_t i = 0; i < valist.size(); i++)
331 : {
332 0 : const vtxarray *va = valist[i];
333 0 : for(int j = 0; j < va->texs; ++j)
334 : {
335 0 : int tex = va->texelems[j].texture;
336 0 : if(std::find(texs.begin(), texs.end(), tex) == texs.end())
337 : {
338 0 : texs.push_back(tex);
339 : }
340 : }
341 : }
342 0 : for(size_t i = 0; i < texs.size(); i++)
343 : {
344 0 : lookupvslot(texs[i]);
345 : }
346 0 : }
347 : }
348 :
349 : /* externally relevant functionality */
350 : ///////////////////////////////////////
351 :
352 0 : void findtjoints(int cur, const EdgeGroup &g)
353 : {
354 0 : int active = -1;
355 0 : while(cur >= 0)
356 : {
357 0 : CubeEdge &e = cubeedges[cur];
358 0 : int prevactive = -1,
359 0 : curactive = active;
360 0 : while(curactive >= 0)
361 : {
362 0 : const CubeEdge &a = cubeedges[curactive];
363 0 : if(a.offset+a.size <= e.offset)
364 : {
365 0 : if(prevactive >= 0)
366 : {
367 0 : cubeedges[prevactive].next = a.next;
368 : }
369 : else
370 : {
371 0 : active = a.next;
372 : }
373 : }
374 : else
375 : {
376 0 : prevactive = curactive;
377 0 : if(!(a.flags&CubeEdge_Dup))
378 : {
379 0 : if(e.flags&CubeEdge_Start && e.offset > a.offset && e.offset < a.offset+a.size)
380 : {
381 0 : addtjoint(g, a, e.offset);
382 : }
383 0 : if(e.flags&CubeEdge_End && e.offset+e.size > a.offset && e.offset+e.size < a.offset+a.size)
384 : {
385 0 : addtjoint(g, a, e.offset+e.size);
386 : }
387 : }
388 0 : if(!(e.flags&CubeEdge_Dup))
389 : {
390 0 : if(a.flags&CubeEdge_Start && a.offset > e.offset && a.offset < e.offset+e.size)
391 : {
392 0 : addtjoint(g, e, a.offset);
393 : }
394 0 : if(a.flags&CubeEdge_End && a.offset+a.size > e.offset && a.offset+a.size < e.offset+e.size)
395 : {
396 0 : addtjoint(g, e, a.offset+a.size);
397 : }
398 : }
399 : }
400 0 : curactive = a.next;
401 : }
402 0 : int next = e.next;
403 0 : e.next = active;
404 0 : active = cur;
405 0 : cur = next;
406 : }
407 0 : }
408 :
409 0 : void reduceslope(ivec &n)
410 : {
411 0 : int mindim = -1,
412 0 : minval = 64;
413 0 : for(int i = 0; i < 3; ++i)
414 : {
415 0 : if(n[i])
416 : {
417 0 : int val = std::abs(n[i]);
418 0 : if(mindim < 0 || val < minval)
419 : {
420 0 : mindim = i;
421 0 : minval = val;
422 : }
423 : }
424 : }
425 0 : if(!(n[R[mindim]]%minval) && !(n[C[mindim]]%minval))
426 : {
427 0 : n.div(minval);
428 : }
429 0 : while(!((n.x|n.y|n.z)&1))
430 : {
431 0 : n.shr(1); //shift right 1 to reduce slope
432 : }
433 0 : }
434 :
435 0 : void guessnormals(const vec *pos, int numverts, vec *normals)
436 : {
437 0 : vec n1, n2;
438 0 : n1.cross(pos[0], pos[1], pos[2]);
439 0 : if(numverts != 4)
440 : {
441 0 : n1.normalize();
442 0 : for(int k = 0; k < numverts; ++k)
443 : {
444 0 : normals[k] = n1;
445 : }
446 0 : return;
447 : }
448 0 : n2.cross(pos[0], pos[2], pos[3]);
449 0 : if(n1.iszero())
450 : {
451 0 : n2.normalize();
452 0 : for(int k = 0; k < 4; ++k)
453 : {
454 0 : normals[k] = n2;
455 : }
456 0 : return;
457 : }
458 : else
459 : {
460 0 : n1.normalize();
461 : }
462 0 : if(n2.iszero())
463 : {
464 0 : for(int k = 0; k < 4; ++k)
465 : {
466 0 : normals[k] = n1;
467 : }
468 0 : return;
469 : }
470 : else
471 : {
472 0 : n2.normalize();
473 : }
474 0 : vec avg = vec(n1).add(n2).normalize();
475 0 : normals[0] = avg;
476 0 : normals[1] = n1;
477 0 : normals[2] = avg;
478 0 : normals[3] = n2;
479 : }
480 :
481 : //va external fxns
482 :
483 0 : void destroyva(vtxarray *va, bool reparent)
484 : {
485 0 : wverts -= va->verts;
486 0 : wtris -= va->tris + va->alphabacktris + va->alphafronttris + va->refracttris + va->decaltris;
487 0 : allocva--;
488 0 : std::vector<vtxarray *>::iterator itr = std::find(valist.begin(), valist.end(), va);
489 0 : if(itr != valist.end())
490 : {
491 0 : valist.erase(itr);
492 : }
493 0 : if(!va->parent)
494 : {
495 0 : std::vector<vtxarray *>::iterator itr2 = std::find(valist.begin(), valist.end(), va);
496 0 : if(itr2 != valist.end())
497 : {
498 0 : valist.erase(itr2);
499 : }
500 : }
501 0 : if(reparent)
502 : {
503 0 : if(va->parent)
504 : {
505 0 : std::vector<vtxarray *>::iterator itr = std::find(va->parent->children.begin(), va->parent->children.end(), va);
506 0 : if(itr != va->parent->children.end())
507 : {
508 0 : va->parent->children.erase(itr);
509 : }
510 : }
511 0 : for(size_t i = 0; i < va->children.size(); i++)
512 : {
513 0 : vtxarray *child = va->children[i];
514 0 : child->parent = va->parent;
515 0 : if(child->parent)
516 : {
517 0 : child->parent->children.push_back(child);
518 : }
519 : }
520 : }
521 0 : if(va->vbuf)
522 : {
523 0 : destroyvbo(va->vbuf);
524 : }
525 0 : if(va->ebuf)
526 : {
527 0 : destroyvbo(va->ebuf);
528 : }
529 0 : if(va->skybuf)
530 : {
531 0 : destroyvbo(va->skybuf);
532 : }
533 0 : if(va->decalbuf)
534 : {
535 0 : destroyvbo(va->decalbuf);
536 : }
537 0 : if(va->texelems)
538 : {
539 0 : delete[] va->texelems;
540 : }
541 0 : if(va->decalelems)
542 : {
543 0 : delete[] va->decalelems;
544 : }
545 0 : delete va;
546 0 : }
547 :
548 0 : void clearvas(std::array<cube, 8> &c)
549 : {
550 0 : for(int i = 0; i < 8; ++i)
551 : {
552 0 : if(c[i].ext)
553 : {
554 0 : if(c[i].ext->va)
555 : {
556 0 : destroyva(c[i].ext->va, false);
557 : }
558 0 : c[i].ext->va = nullptr;
559 0 : c[i].ext->tjoints = -1;
560 : }
561 0 : if(c[i].children)
562 : {
563 0 : clearvas(*c[i].children);
564 : }
565 : }
566 0 : }
567 :
568 0 : void vtxarray::updatevabb(bool force)
569 : {
570 0 : if(!force && bbmin.x >= 0)
571 : {
572 0 : return;
573 : }
574 0 : bbmin = geommin;
575 0 : bbmax = geommax;
576 0 : bbmin.min(watermin);
577 0 : bbmax.max(watermax);
578 0 : bbmin.min(glassmin);
579 0 : bbmax.max(glassmax);
580 0 : for(vtxarray *child : children)
581 : {
582 0 : child->updatevabb(force);
583 0 : bbmin.min(child->bbmin);
584 0 : bbmax.max(child->bbmax);
585 : }
586 0 : for(const octaentities *oe : mapmodels)
587 : {
588 0 : bbmin.min(oe->bbmin);
589 0 : bbmax.max(oe->bbmax);
590 : }
591 0 : for(const octaentities *oe : decals)
592 : {
593 0 : bbmin.min(oe->bbmin);
594 0 : bbmax.max(oe->bbmax);
595 : }
596 0 : bbmin.max(o);
597 0 : bbmax.min(ivec(o).add(size));
598 0 : worldmin.min(bbmin);
599 0 : worldmax.max(bbmax);
600 : }
601 :
602 : //update vertex array bounding boxes recursively from the root va object down to all children
603 0 : void updatevabbs(bool force)
604 : {
605 0 : if(force)
606 : {
607 0 : worldmin = ivec(rootworld.mapsize(), rootworld.mapsize(), rootworld.mapsize());
608 0 : worldmax = ivec(0, 0, 0);
609 0 : for(size_t i = 0; i < varoot.size(); i++)
610 : {
611 0 : varoot[i]->updatevabb(true);
612 : }
613 0 : if(worldmin.x >= worldmax.x)
614 : {
615 0 : worldmin = ivec(0, 0, 0);
616 0 : worldmax = ivec(rootworld.mapsize(), rootworld.mapsize(), rootworld.mapsize());
617 : }
618 : }
619 : else
620 : {
621 0 : for(size_t i = 0; i < varoot.size(); i++)
622 : {
623 0 : varoot[i]->updatevabb();
624 : }
625 : }
626 0 : }
627 :
628 0 : void cubeworld::findtjoints()
629 : {
630 0 : gencubeedges(*worldroot);
631 0 : tjoints.clear();
632 0 : for(auto &[k, t] : edgegroups)
633 : {
634 0 : ::findtjoints(t, k);
635 : }
636 0 : cubeedges.clear();
637 0 : edgegroups.clear();
638 0 : }
639 :
640 1 : void cubeworld::allchanged(bool load)
641 : {
642 1 : if(!worldroot)
643 : {
644 1 : return;
645 : }
646 0 : if(mainmenu)
647 : {
648 0 : load = false;
649 : }
650 0 : if(load)
651 : {
652 0 : initlights();
653 : }
654 0 : clearvas(*worldroot);
655 0 : occlusionengine.resetqueries();
656 0 : resetclipplanes();
657 0 : entitiesinoctanodes();
658 0 : tjoints.clear();
659 0 : if(filltjoints)
660 : {
661 0 : findtjoints();
662 : }
663 0 : octarender();
664 0 : if(load)
665 : {
666 0 : precachetextures();
667 : }
668 0 : setupmaterials();
669 0 : clearshadowcache();
670 0 : updatevabbs(true);
671 0 : if(load)
672 : {
673 0 : genshadowmeshes();
674 0 : seedparticles();
675 : }
676 : }
677 :
678 0 : void initoctarendercmds()
679 : {
680 0 : addcommand("recalc", reinterpret_cast<identfun>(+[](){rootworld.allchanged(true);}), "", Id_Command);
681 0 : }
|