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