Line data Source code
1 : // renderva.cpp: handles the occlusion and rendering of vertex arrays
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 "csm.h"
12 : #include "grass.h"
13 : #include "octarender.h"
14 : #include "radiancehints.h"
15 : #include "rendergl.h"
16 : #include "renderlights.h"
17 : #include "rendermodel.h"
18 : #include "renderva.h"
19 : #include "renderwindow.h"
20 : #include "rendersky.h"
21 : #include "shaderparam.h"
22 : #include "shader.h"
23 : #include "texture.h"
24 :
25 : #include "interface/control.h"
26 :
27 : #include "world/entities.h"
28 : #include "world/light.h"
29 : #include "world/octaedit.h"
30 : #include "world/octaworld.h"
31 : #include "world/raycube.h"
32 : #include "world/bih.h"
33 : #include "world/world.h"
34 :
35 :
36 : #include "model/model.h"
37 :
38 : VAR(oqfrags, 0, 8, 64); //occlusion query fragments
39 0 : CVARP(outlinecolor, 0); //color of edit mode outlines
40 :
41 : float shadowradius = 0,
42 : shadowbias = 0;
43 : size_t shadowside = 0;
44 : int shadowspot = 0;
45 : vec shadoworigin(0, 0, 0),
46 : shadowdir(0, 0, 0);
47 :
48 : vtxarray *visibleva = nullptr;
49 : vfc view;
50 :
51 : int deferquery = 0;
52 :
53 : struct shadowmesh
54 : {
55 : vec origin;
56 : float radius;
57 : vec spotloc;
58 : int spotangle;
59 : int type;
60 : std::array<int, 6> draws;
61 : };
62 :
63 : Occluder occlusionengine;
64 :
65 : /* internally relevant functionality */
66 : ///////////////////////////////////////
67 :
68 : namespace
69 : {
70 0 : void drawtris(GLsizei numindices, const GLvoid *indices, GLuint minvert, GLuint maxvert)
71 : {
72 0 : glDrawRangeElements(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices);
73 0 : glde++;
74 0 : }
75 :
76 0 : void drawvatris(const vtxarray &va, GLsizei numindices, int offset)
77 : {
78 0 : drawtris(numindices, (ushort *)0 + va.eoffset + offset, va.minvert, va.maxvert);
79 0 : }
80 :
81 0 : void drawvaskytris(const vtxarray &va)
82 : {
83 0 : drawtris(va.sky, (ushort *)0 + va.skyoffset, va.minvert, va.maxvert);
84 0 : }
85 :
86 : ///////// view frustrum culling ///////////////////////
87 :
88 0 : float vadist(const vtxarray &va, const vec &p)
89 : {
90 0 : return p.dist_to_bb(va.bbmin, va.bbmax);
91 : }
92 :
93 : constexpr int vasortsize = 64;
94 :
95 0 : void addvisibleva(vtxarray *va, std::array<vtxarray *, vasortsize> &vasort)
96 : {
97 0 : float dist = vadist(*va, camera1->o);
98 0 : va->distance = static_cast<int>(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
99 :
100 0 : int hash = std::clamp(static_cast<int>(dist*vasortsize/rootworld.mapsize()), 0, vasortsize-1);
101 0 : vtxarray **prev = &vasort[hash],
102 0 : *cur = vasort[hash];
103 :
104 0 : while(cur && va->distance >= cur->distance)
105 : {
106 0 : prev = &cur->next;
107 0 : cur = cur->next;
108 : }
109 :
110 0 : va->next = cur;
111 0 : *prev = va;
112 0 : }
113 :
114 0 : void sortvisiblevas(const std::array<vtxarray *, vasortsize> &vasort)
115 : {
116 0 : visibleva = nullptr;
117 0 : vtxarray **last = &visibleva;
118 0 : for(vtxarray *i : vasort)
119 : {
120 0 : if(i)
121 : {
122 0 : vtxarray *va = i;
123 0 : *last = va;
124 0 : while(va->next)
125 : {
126 0 : va = va->next;
127 : }
128 0 : last = &va->next;
129 : }
130 : }
131 0 : }
132 :
133 : template<bool fullvis, bool resetocclude>
134 0 : void findvisiblevas(std::vector<vtxarray *> &vas, std::array<vtxarray *, vasortsize> &vasort)
135 : {
136 0 : for(uint i = 0; i < vas.size(); i++)
137 : {
138 0 : vtxarray &v = *vas[i];
139 0 : int prevvfc = v.curvfc;
140 0 : v.curvfc = fullvis ? ViewFrustumCull_FullyVisible : view.isvisiblecube(v.o, v.size);
141 0 : if(v.curvfc != ViewFrustumCull_NotVisible)
142 : {
143 0 : bool resetchildren = prevvfc >= ViewFrustumCull_NotVisible || resetocclude;
144 0 : if(resetchildren)
145 : {
146 0 : v.occluded = !v.texs ? Occlude_Geom : Occlude_Nothing;
147 0 : v.query = nullptr;
148 : }
149 0 : addvisibleva(&v, vasort);
150 0 : if(v.children.size())
151 : {
152 0 : if(fullvis || v.curvfc == ViewFrustumCull_FullyVisible)
153 : {
154 0 : if(resetchildren)
155 : {
156 0 : findvisiblevas<true, true>(v.children, vasort);
157 : }
158 : else
159 : {
160 0 : findvisiblevas<true, false>(v.children, vasort);
161 : }
162 : }
163 0 : else if(resetchildren)
164 : {
165 0 : findvisiblevas<false, true>(v.children, vasort);
166 : }
167 : else
168 : {
169 0 : findvisiblevas<false, false>(v.children, vasort);
170 : }
171 : }
172 : }
173 : }
174 0 : }
175 :
176 0 : void findvisiblevas()
177 : {
178 : std::array<vtxarray *, vasortsize> vasort;
179 0 : vasort.fill(nullptr);
180 0 : findvisiblevas<false, false>(varoot, vasort);
181 0 : sortvisiblevas(vasort);
182 0 : }
183 :
184 : ///////// occlusion queries /////////////
185 :
186 0 : VARF(oqany, 0, 0, 2, occlusionengine.clearqueries()); //occlusion query settings: 0: GL_SAMPLES_PASSED, 1: GL_ANY_SAMPLES_PASSED, 2: GL_ANY_SAMPLES_PASSED_CONSERVATIVE
187 : VAR(oqwait, 0, 1, 1);
188 :
189 0 : GLenum querytarget()
190 : {
191 0 : return oqany ? (oqany > 1 && hasES3 ? GL_ANY_SAMPLES_PASSED_CONSERVATIVE : GL_ANY_SAMPLES_PASSED) : GL_SAMPLES_PASSED;
192 : }
193 :
194 : GLuint bbvbo = 0,
195 : bbebo = 0;
196 :
197 0 : void setupbb()
198 : {
199 0 : if(!bbvbo)
200 : {
201 0 : glGenBuffers(1, &bbvbo);
202 0 : gle::bindvbo(bbvbo);
203 0 : vec verts[8];
204 0 : for(int i = 0; i < 8; ++i)
205 : {
206 0 : verts[i] = vec(i&1, (i>>1)&1, (i>>2)&1);
207 : }
208 0 : glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
209 0 : gle::clearvbo();
210 : }
211 0 : if(!bbebo)
212 : {
213 0 : glGenBuffers(1, &bbebo);
214 0 : gle::bindebo(bbebo);
215 : GLushort tris[3*2*6];
216 : //======================================== GENFACEVERT GENFACEORIENT
217 : #define GENFACEORIENT(orient, v0, v1, v2, v3) do { \
218 : int offset = orient*3*2; \
219 : tris[offset + 0] = v0; \
220 : tris[offset + 1] = v1; \
221 : tris[offset + 2] = v2; \
222 : tris[offset + 3] = v0; \
223 : tris[offset + 4] = v2; \
224 : tris[offset + 5] = v3; \
225 : } while(0);
226 : #define GENFACEVERT(orient, vert, ox,oy,oz, rx,ry,rz) (ox | oy | oz)
227 0 : GENFACEVERTS(0, 1, 0, 2, 0, 4, , , , , , )
228 : #undef GENFACEORIENT
229 : #undef GENFACEVERT
230 : //==================================================================
231 0 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tris), tris, GL_STATIC_DRAW);
232 0 : gle::clearebo();
233 : }
234 0 : }
235 :
236 0 : void cleanupbb()
237 : {
238 0 : if(bbvbo)
239 : {
240 0 : glDeleteBuffers(1, &bbvbo);
241 0 : bbvbo = 0;
242 : }
243 0 : if(bbebo)
244 : {
245 0 : glDeleteBuffers(1, &bbebo);
246 0 : bbebo = 0;
247 : }
248 0 : }
249 :
250 : octaentities *visiblemms,
251 : **lastvisiblemms;
252 :
253 0 : void findvisiblemms(const std::vector<extentity *> &ents, bool doquery)
254 : {
255 0 : visiblemms = nullptr;
256 0 : lastvisiblemms = &visiblemms;
257 0 : for(vtxarray *va = visibleva; va; va = va->next)
258 : {
259 0 : if(va->occluded < Occlude_BB && va->curvfc < ViewFrustumCull_Fogged)
260 : {
261 0 : for(octaentities *oe : va->mapmodels)
262 : {
263 0 : if(view.isfoggedcube(oe->o, oe->size))
264 : {
265 0 : continue;
266 : }
267 0 : bool occluded = doquery && oe->query && oe->query->owner == oe && occlusionengine.checkquery(oe->query);
268 0 : if(occluded)
269 : {
270 0 : oe->distance = -1;
271 0 : oe->next = nullptr;
272 0 : *lastvisiblemms = oe;
273 0 : lastvisiblemms = &oe->next;
274 : }
275 : else
276 : {
277 0 : int visible = 0;
278 0 : for(const int &i : oe->mapmodels)
279 : {
280 0 : extentity &e = *ents[i];
281 0 : if(e.flags&EntFlag_NoVis)
282 : {
283 0 : continue;
284 : }
285 0 : e.flags |= EntFlag_Render;
286 0 : ++visible;
287 : }
288 0 : if(!visible)
289 : {
290 0 : continue;
291 : }
292 0 : oe->distance = static_cast<int>(camera1->o.dist_to_bb(oe->o, ivec(oe->o).add(oe->size)));
293 :
294 0 : octaentities **prev = &visiblemms, *cur = visiblemms;
295 0 : while(cur && cur->distance >= 0 && oe->distance > cur->distance)
296 : {
297 0 : prev = &cur->next;
298 0 : cur = cur->next;
299 : }
300 :
301 0 : if(*prev == nullptr)
302 : {
303 0 : lastvisiblemms = &oe->next;
304 : }
305 0 : oe->next = *prev;
306 0 : *prev = oe;
307 : }
308 : }
309 : }
310 : }
311 0 : }
312 :
313 : VAR(oqmm, 0, 4, 8); //`o`cclusion `q`uery `m`ap `m`odel
314 :
315 0 : void rendermapmodel(const extentity &e)
316 : {
317 0 : int anim = Anim_Mapmodel | Anim_Loop, basetime = 0;
318 0 : rendermapmodel(e.attr1, anim, e.o, e.attr2, e.attr3, e.attr4, Model_CullVFC | Model_CullDist, basetime, e.attr5 > 0 ? e.attr5/100.0f : 1.0f);
319 0 : }
320 :
321 0 : bool bbinsideva(const ivec &bo, const ivec &br, const vtxarray &va)
322 : {
323 0 : return bo.x >= va.bbmin.x && bo.y >= va.bbmin.y && bo.z >= va.bbmin.z &&
324 0 : br.x <= va.bbmax.x && br.y <= va.bbmax.y && br.z <= va.bbmax.z;
325 : }
326 :
327 0 : bool bboccluded(const ivec &bo, const ivec &br, const std::array<cube, 8> &c, const ivec &o, int size)
328 : {
329 0 : LOOP_OCTA_BOX(o, size, bo, br)
330 : {
331 0 : ivec co(i, o, size);
332 0 : if(c[i].ext && c[i].ext->va)
333 : {
334 0 : vtxarray *va = c[i].ext->va;
335 0 : if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, *va)))
336 : {
337 0 : continue;
338 : }
339 : }
340 0 : if(c[i].children && bboccluded(bo, br, *(c[i].children), co, size>>1))
341 : {
342 0 : continue;
343 : }
344 0 : return false;
345 : }
346 0 : return true;
347 : }
348 :
349 : VAR(dtoutline, 0, 1, 1); //`d`epth `t`est `outline`s
350 :
351 0 : int calcbbsidemask(const ivec &bbmin, const ivec &bbmax, const vec &lightpos, float lightradius, float bias)
352 : {
353 0 : vec pmin = vec(bbmin).sub(lightpos).div(lightradius),
354 0 : pmax = vec(bbmax).sub(lightpos).div(lightradius);
355 0 : int mask = 0x3F;
356 0 : float dp1 = pmax.x + pmax.y,
357 0 : dn1 = pmax.x - pmin.y,
358 0 : ap1 = std::fabs(dp1),
359 0 : an1 = std::fabs(dn1),
360 0 : dp2 = pmin.x + pmin.y,
361 0 : dn2 = pmin.x - pmax.y,
362 0 : ap2 = std::fabs(dp2),
363 0 : an2 = std::fabs(dn2);
364 0 : if(ap1 > bias*an1 && ap2 > bias*an2)
365 : {
366 0 : mask &= (3<<4)
367 0 : | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
368 0 : | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
369 : }
370 0 : if(an1 > bias*ap1 && an2 > bias*ap2)
371 : {
372 0 : mask &= (3<<4)
373 0 : | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
374 0 : | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
375 : }
376 0 : dp1 = pmax.y + pmax.z,
377 0 : dn1 = pmax.y - pmin.z,
378 0 : ap1 = std::fabs(dp1),
379 0 : an1 = std::fabs(dn1),
380 0 : dp2 = pmin.y + pmin.z,
381 0 : dn2 = pmin.y - pmax.z,
382 0 : ap2 = std::fabs(dp2),
383 0 : an2 = std::fabs(dn2);
384 0 : if(ap1 > bias*an1 && ap2 > bias*an2)
385 : {
386 0 : mask &= (3<<0)
387 0 : | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
388 0 : | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
389 : }
390 0 : if(an1 > bias*ap1 && an2 > bias*ap2)
391 : {
392 0 : mask &= (3<<0)
393 0 : | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
394 0 : | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
395 : }
396 0 : dp1 = pmax.z + pmax.x,
397 0 : dn1 = pmax.z - pmin.x,
398 0 : ap1 = std::fabs(dp1),
399 0 : an1 = std::fabs(dn1),
400 0 : dp2 = pmin.z + pmin.x,
401 0 : dn2 = pmin.z - pmax.x,
402 0 : ap2 = std::fabs(dp2),
403 0 : an2 = std::fabs(dn2);
404 0 : if(ap1 > bias*an1 && ap2 > bias*an2)
405 : {
406 0 : mask &= (3<<2)
407 0 : | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
408 0 : | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
409 : }
410 0 : if(an1 > bias*ap1 && an2 > bias*ap2)
411 : {
412 0 : mask &= (3<<2)
413 0 : | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
414 0 : | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
415 : }
416 0 : return mask;
417 : }
418 :
419 : VAR(smbbcull, 0, 1, 1);
420 : VAR(smdistcull, 0, 1, 1);
421 : VAR(smnodraw, 0, 0, 1);
422 :
423 : vtxarray *shadowva = nullptr;
424 :
425 0 : void addshadowva(vtxarray * const va, float dist, std::array<vtxarray *, vasortsize> &vasort)
426 : {
427 0 : va->rdistance = static_cast<int>(dist);
428 :
429 0 : int hash = std::clamp(static_cast<int>(dist*vasortsize/shadowradius), 0, vasortsize-1);
430 0 : vtxarray **prev = &vasort[hash],
431 0 : *cur = vasort[hash];
432 :
433 0 : while(cur && va->rdistance > cur->rdistance)
434 : {
435 0 : prev = &cur->rnext;
436 0 : cur = cur->rnext;
437 : }
438 :
439 0 : va->rnext = cur;
440 0 : *prev = va;
441 0 : }
442 :
443 0 : void sortshadowvas(std::array<vtxarray *, vasortsize> &vasort)
444 : {
445 0 : shadowva = nullptr;
446 0 : vtxarray **last = &shadowva;
447 0 : for(vtxarray *i : vasort)
448 : {
449 0 : if(i)
450 : {
451 0 : vtxarray *va = i;
452 0 : *last = va;
453 0 : while(va->rnext)
454 : {
455 0 : va = va->rnext;
456 : }
457 0 : last = &va->rnext;
458 : }
459 : }
460 0 : }
461 :
462 0 : void findcsmshadowvas(std::vector<vtxarray *> &vas, std::array<vtxarray *, vasortsize> &vasort)
463 : {
464 0 : for(vtxarray * const &v : vas)
465 : {
466 0 : ivec bbmin, bbmax;
467 0 : if(v->children.size() || v->mapmodels.size())
468 : {
469 0 : bbmin = v->bbmin;
470 0 : bbmax = v->bbmax;
471 : }
472 : else
473 : {
474 0 : bbmin = v->geommin;
475 0 : bbmax = v->geommax;
476 : }
477 0 : v->shadowmask = csm.calcbbcsmsplits(bbmin, bbmax);
478 0 : if(v->shadowmask)
479 : {
480 0 : float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias;
481 0 : addshadowva(v, dist, vasort);
482 0 : if(v->children.size())
483 : {
484 0 : findcsmshadowvas(v->children, vasort);
485 : }
486 : }
487 : }
488 0 : }
489 :
490 0 : void findrsmshadowvas(std::vector<vtxarray *> &vas, std::array<vtxarray *, vasortsize> &vasort)
491 : {
492 0 : for(vtxarray *v :vas)
493 : {
494 0 : ivec bbmin, bbmax;
495 0 : if(v->children.size() || v->mapmodels.size())
496 : {
497 0 : bbmin = v->bbmin;
498 0 : bbmax = v->bbmax;
499 : }
500 : else
501 : {
502 0 : bbmin = v->geommin;
503 0 : bbmax = v->geommax;
504 : }
505 0 : v->shadowmask = calcbbrsmsplits(bbmin, bbmax);
506 0 : if(v->shadowmask)
507 : {
508 0 : float dist = shadowdir.project_bb(bbmin, bbmax) - shadowbias;
509 0 : addshadowva(v, dist, vasort);
510 0 : if(v->children.size())
511 : {
512 0 : findrsmshadowvas(v->children, vasort);
513 : }
514 : }
515 : }
516 0 : }
517 :
518 0 : void findspotshadowvas(std::vector<vtxarray *> &vas, std::array<vtxarray *, vasortsize> &vasort)
519 : {
520 0 : for(vtxarray *v : vas)
521 : {
522 0 : float dist = vadist(*v, shadoworigin);
523 0 : if(dist < shadowradius || !smdistcull)
524 : {
525 0 : v->shadowmask = !smbbcull || (v->children.size() || v->mapmodels.size() ?
526 0 : bbinsidespot(shadoworigin, shadowdir, shadowspot, v->bbmin, v->bbmax) :
527 0 : bbinsidespot(shadoworigin, shadowdir, shadowspot, v->geommin, v->geommax)) ? 1 : 0;
528 0 : addshadowva(v, dist, vasort);
529 0 : if(v->children.size())
530 : {
531 0 : findspotshadowvas(v->children, vasort);
532 : }
533 : }
534 : }
535 0 : }
536 :
537 : octaentities *shadowmms = nullptr;
538 :
539 : struct geombatch
540 : {
541 : const elementset &es;
542 : VSlot &vslot;
543 : int offset;
544 : const vtxarray * const va;
545 : int next, batch;
546 :
547 0 : geombatch(const elementset &es, int offset, const vtxarray *va)
548 0 : : es(es), vslot(lookupvslot(es.texture)), offset(offset), va(va),
549 0 : next(-1), batch(-1)
550 0 : {}
551 :
552 : void renderbatch() const;
553 :
554 0 : int compare(const geombatch &b) const
555 : {
556 0 : if(va->vbuf < b.va->vbuf)
557 : {
558 0 : return -1;
559 : }
560 0 : if(va->vbuf > b.va->vbuf)
561 : {
562 0 : return 1;
563 : }
564 0 : if(es.attrs.layer&BlendLayer_Bottom)
565 : {
566 0 : if(!(b.es.attrs.layer&BlendLayer_Bottom))
567 : {
568 0 : return 1;
569 : }
570 0 : int x1 = va->o.x&~0xFFF,
571 0 : x2 = b.va->o.x&~0xFFF;
572 0 : if(x1 < x2)
573 : {
574 0 : return -1;
575 : }
576 0 : if(x1 > x2)
577 : {
578 0 : return 1;
579 : }
580 0 : int y1 = va->o.y&~0xFFF,
581 0 : y2 = b.va->o.y&~0xFFF;
582 0 : if(y1 < y2)
583 : {
584 0 : return -1;
585 : }
586 0 : if(y1 > y2)
587 : {
588 0 : return 1;
589 : }
590 : }
591 0 : else if(b.es.attrs.layer&BlendLayer_Bottom)
592 : {
593 0 : return -1;
594 : }
595 0 : if(vslot.slot->shader < b.vslot.slot->shader)
596 : {
597 0 : return -1;
598 : }
599 0 : if(vslot.slot->shader > b.vslot.slot->shader)
600 : {
601 0 : return 1;
602 : }
603 0 : if(es.texture < b.es.texture)
604 : {
605 0 : return -1;
606 : }
607 0 : if(es.texture > b.es.texture)
608 : {
609 0 : return 1;
610 : }
611 0 : if(vslot.slot->params.size() < b.vslot.slot->params.size())
612 : {
613 0 : return -1;
614 : }
615 0 : if(vslot.slot->params.size() > b.vslot.slot->params.size())
616 : {
617 0 : return 1;
618 : }
619 0 : if(es.attrs.orient < b.es.attrs.orient)
620 : {
621 0 : return -1;
622 : }
623 0 : if(es.attrs.orient > b.es.attrs.orient)
624 : {
625 0 : return 1;
626 : }
627 0 : return 0;
628 : }
629 : };
630 :
631 : class renderstate
632 : {
633 : public:
634 : bool colormask, depthmask;
635 : int alphaing;
636 : GLuint vbuf;
637 : bool vattribs, vquery;
638 : int globals;
639 :
640 : void disablevquery();
641 : void disablevbuf();
642 : void enablevquery();
643 : void cleanupgeom();
644 : void enablevattribs(bool all = true);
645 : void disablevattribs(bool all = true);
646 : void renderbatches(int pass);
647 : void renderzpass(const vtxarray &va);
648 : void invalidatetexgenorient();
649 : void invalidatealphascale();
650 : void cleartexgenmillis();
651 :
652 0 : renderstate() : colormask(true), depthmask(true), alphaing(0), vbuf(0), vattribs(false),
653 0 : vquery(false), globals(-1), alphascale(0), texgenorient(-1),
654 0 : texgenmillis(lastmillis), tmu(-1), colorscale(1, 1, 1),
655 0 : vslot(nullptr), texgenslot(nullptr), texgenvslot(nullptr),
656 0 : texgenscroll(0, 0), refractscale(0), refractcolor(1, 1, 1)
657 : {
658 0 : for(int k = 0; k < 7; ++k)
659 : {
660 0 : textures[k] = 0;
661 : }
662 0 : }
663 : private:
664 :
665 : float alphascale;
666 : int texgenorient, texgenmillis;
667 : int tmu;
668 : GLuint textures[7];
669 : vec colorscale;
670 : const VSlot *vslot;
671 : const Slot *texgenslot;
672 : const VSlot *texgenvslot;
673 : vec2 texgenscroll;
674 : float refractscale;
675 : vec refractcolor;
676 :
677 : void changetexgen(int orient, Slot &slot, VSlot &vslot);
678 : void changebatchtmus();
679 : void changeslottmus(int pass, Slot &newslot, VSlot &newvslot);
680 : void bindslottex(int type, const Texture *tex, GLenum target = GL_TEXTURE_2D);
681 : void changeshader(int pass, const geombatch &b);
682 :
683 : };
684 :
685 0 : void renderstate::invalidatetexgenorient()
686 : {
687 0 : texgenorient = -1;
688 0 : }
689 :
690 0 : void renderstate::invalidatealphascale()
691 : {
692 0 : alphascale = -1;
693 0 : }
694 :
695 0 : void renderstate::cleartexgenmillis()
696 : {
697 0 : texgenmillis = 0;
698 0 : }
699 :
700 0 : void renderstate::disablevbuf()
701 : {
702 0 : gle::clearvbo();
703 0 : gle::clearebo();
704 0 : vbuf = 0;
705 0 : }
706 :
707 0 : void renderstate::enablevquery()
708 : {
709 0 : if(colormask)
710 : {
711 0 : colormask = false;
712 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
713 : }
714 0 : if(depthmask)
715 : {
716 0 : depthmask = false;
717 0 : glDepthMask(GL_FALSE);
718 : }
719 0 : startbb(false);
720 0 : vquery = true;
721 0 : }
722 :
723 0 : void renderstate::disablevquery()
724 : {
725 0 : endbb(false);
726 0 : vquery = false;
727 0 : }
728 :
729 0 : void renderquery(renderstate &cur, const occludequery &query, const vtxarray &va, bool full = true)
730 : {
731 0 : if(!cur.vquery)
732 : {
733 0 : cur.enablevquery();
734 : }
735 0 : query.startquery();
736 0 : if(full)
737 : {
738 0 : drawbb(ivec(va.bbmin).sub(1), ivec(va.bbmax).sub(va.bbmin).add(2));
739 : }
740 : else
741 : {
742 0 : drawbb(va.geommin, ivec(va.geommax).sub(va.geommin));
743 : }
744 0 : occlusionengine.endquery();
745 0 : }
746 :
747 : enum RenderPass
748 : {
749 : RenderPass_GBuffer = 0,
750 : RenderPass_Z,
751 : RenderPass_Caustics,
752 : RenderPass_GBufferBlend,
753 : RenderPass_ReflectiveShadowMap,
754 : RenderPass_ReflectiveShadowMapBlend
755 : };
756 :
757 : std::vector<geombatch> geombatches;
758 : int firstbatch = -1,
759 : numbatches = 0;
760 :
761 0 : void mergetexs(const renderstate &cur, const vtxarray &va, elementset *texs = nullptr, int offset = 0)
762 : {
763 0 : int numtexs = 0;
764 0 : if(!texs)
765 : {
766 0 : texs = va.texelems;
767 0 : numtexs = va.texs;
768 0 : if(cur.alphaing)
769 : {
770 0 : texs += va.texs;
771 0 : offset += 3*(va.tris);
772 0 : numtexs = va.alphaback;
773 0 : if(cur.alphaing > 1)
774 : {
775 0 : numtexs += va.alphafront + va.refract;
776 : }
777 : }
778 : }
779 :
780 0 : if(firstbatch < 0)
781 : {
782 0 : firstbatch = geombatches.size();
783 0 : numbatches = numtexs;
784 0 : for(int i = 0; i < numtexs-1; ++i)
785 : {
786 0 : geombatches.emplace_back(texs[i], offset, &va);
787 0 : geombatches.back().next = i+1;
788 0 : offset += texs[i].length;
789 : }
790 0 : geombatches.emplace_back(texs[numtexs-1], offset, &va);
791 0 : return;
792 : }
793 :
794 0 : int prevbatch = -1,
795 0 : curbatch = firstbatch,
796 0 : curtex = 0;
797 : do
798 : {
799 0 : geombatches.emplace_back(texs[curtex], offset, &va);
800 0 : geombatch &b = geombatches.back();
801 0 : offset += texs[curtex].length;
802 0 : int dir = -1;
803 0 : while(curbatch >= 0)
804 : {
805 0 : dir = b.compare(geombatches[curbatch]);
806 0 : if(dir <= 0)
807 : {
808 0 : break;
809 : }
810 0 : prevbatch = curbatch;
811 0 : curbatch = geombatches[curbatch].next;
812 : }
813 0 : if(!dir)
814 : {
815 0 : int last = curbatch, next;
816 : for(;;)
817 : {
818 0 : next = geombatches[last].batch;
819 0 : if(next < 0)
820 : {
821 0 : break;
822 : }
823 0 : last = next;
824 : }
825 0 : if(last==curbatch)
826 : {
827 0 : b.batch = curbatch;
828 0 : b.next = geombatches[curbatch].next;
829 0 : if(prevbatch < 0)
830 : {
831 0 : firstbatch = geombatches.size()-1;
832 : }
833 : else
834 : {
835 0 : geombatches[prevbatch].next = geombatches.size()-1;
836 : }
837 0 : curbatch = geombatches.size()-1;
838 : }
839 : else
840 : {
841 0 : b.batch = next;
842 0 : geombatches[last].batch = geombatches.size()-1;
843 : }
844 : }
845 : else
846 : {
847 0 : numbatches++;
848 0 : b.next = curbatch;
849 0 : if(prevbatch < 0)
850 : {
851 0 : firstbatch = geombatches.size()-1;
852 : }
853 : else
854 : {
855 0 : geombatches[prevbatch].next = geombatches.size()-1;
856 : }
857 0 : prevbatch = geombatches.size()-1;
858 : }
859 0 : } while(++curtex < numtexs);
860 : }
861 :
862 0 : void renderstate::enablevattribs(bool all)
863 : {
864 0 : gle::enablevertex();
865 0 : if(all)
866 : {
867 0 : gle::enabletexcoord0();
868 0 : gle::enablenormal();
869 0 : gle::enabletangent();
870 : }
871 0 : vattribs = true;
872 0 : }
873 :
874 0 : void renderstate::disablevattribs(bool all)
875 : {
876 0 : gle::disablevertex();
877 0 : if(all)
878 : {
879 0 : gle::disabletexcoord0();
880 0 : gle::disablenormal();
881 0 : gle::disabletangent();
882 : }
883 0 : vattribs = false;
884 0 : }
885 :
886 0 : void changevbuf(renderstate &cur, int pass, const vtxarray &va)
887 : {
888 0 : gle::bindvbo(va.vbuf);
889 0 : gle::bindebo(va.ebuf);
890 0 : cur.vbuf = va.vbuf;
891 :
892 0 : vertex *vdata = nullptr;
893 0 : gle::vertexpointer(sizeof(vertex), vdata->pos.data());
894 0 : gle::vertexpointer(sizeof(vertex), vdata->pos.data());
895 :
896 0 : if(pass==RenderPass_GBuffer || pass==RenderPass_ReflectiveShadowMap)
897 : {
898 0 : gle::normalpointer(sizeof(vertex), vdata->norm.data(), GL_BYTE);
899 0 : gle::texcoord0pointer(sizeof(vertex), vdata->tc.data());
900 0 : gle::tangentpointer(sizeof(vertex), vdata->tangent.data(), GL_BYTE);
901 : }
902 0 : }
903 :
904 0 : void renderstate::changebatchtmus()
905 : {
906 0 : if(tmu != 0)
907 : {
908 0 : tmu = 0;
909 0 : glActiveTexture(GL_TEXTURE0);
910 : }
911 0 : }
912 :
913 0 : void renderstate::bindslottex(int type, const Texture *tex, GLenum target)
914 : {
915 0 : if(textures[type] != tex->id)
916 : {
917 0 : if(tmu != type)
918 : {
919 0 : tmu = type;
920 0 : glActiveTexture(GL_TEXTURE0 + type);
921 : }
922 0 : glBindTexture(target, textures[type] = tex->id);
923 : }
924 0 : }
925 :
926 0 : void renderstate::changeslottmus(int pass, Slot &newslot, VSlot &newvslot)
927 : {
928 0 : Texture *diffuse = newslot.sts.empty() ? notexture : newslot.sts[0].t;
929 0 : if(pass==RenderPass_GBuffer || pass==RenderPass_ReflectiveShadowMap)
930 : {
931 0 : bindslottex(Tex_Diffuse, diffuse);
932 :
933 0 : if(pass == RenderPass_GBuffer)
934 : {
935 0 : if(msaasamples)
936 : {
937 0 : GLOBALPARAMF(hashid, newvslot.index);
938 : }
939 0 : if(newslot.shader->type & Shader_Triplanar)
940 : {
941 0 : float scale = defaulttexscale/newvslot.scale;
942 0 : GLOBALPARAMF(texgenscale, scale/diffuse->xs, scale/diffuse->ys);
943 : }
944 : }
945 : }
946 :
947 0 : if(alphaing)
948 : {
949 0 : float alpha = alphaing > 1 ? newvslot.alphafront : newvslot.alphaback;
950 0 : if(alphascale != alpha)
951 : {
952 0 : alphascale = alpha;
953 0 : refractscale = 0;
954 0 : goto changecolorparams; //also run next if statement
955 : }
956 0 : if(colorscale != newvslot.colorscale)
957 : {
958 0 : changecolorparams:
959 0 : colorscale = newvslot.colorscale;
960 0 : GLOBALPARAMF(colorparams,
961 : alpha*newvslot.colorscale.x,
962 : alpha*newvslot.colorscale.y,
963 : alpha*newvslot.colorscale.z,
964 : alpha);
965 : }
966 0 : if(alphaing > 1 && newvslot.refractscale > 0 &&
967 0 : (refractscale != newvslot.refractscale || refractcolor != newvslot.refractcolor))
968 : {
969 0 : refractscale = newvslot.refractscale;
970 0 : refractcolor = newvslot.refractcolor;
971 0 : float refractscale = 0.5f/ldrscale*(1-alpha);
972 0 : GLOBALPARAMF(refractparams,
973 : newvslot.refractcolor.x*refractscale,
974 : newvslot.refractcolor.y*refractscale,
975 : newvslot.refractcolor.z*refractscale,
976 : newvslot.refractscale*viewh);
977 : }
978 : }
979 0 : else if(colorscale != newvslot.colorscale)
980 : {
981 0 : colorscale = newvslot.colorscale;
982 0 : GLOBALPARAMF(colorparams, newvslot.colorscale.x, newvslot.colorscale.y, newvslot.colorscale.z, 1);
983 : }
984 :
985 0 : for(const Slot::Tex &t : newslot.sts)
986 : {
987 0 : switch(t.type)
988 : {
989 0 : case Tex_Normal:
990 : case Tex_Glow:
991 : {
992 0 : bindslottex(t.type, t.t);
993 0 : break;
994 : }
995 : }
996 : }
997 0 : GLOBALPARAM(rotate, vec(newvslot.angle.y, newvslot.angle.z, diffuse->ratio()));
998 0 : if(tmu != 0)
999 : {
1000 0 : tmu = 0;
1001 0 : glActiveTexture(GL_TEXTURE0);
1002 : }
1003 0 : vslot = &newvslot;
1004 0 : }
1005 :
1006 0 : void renderstate::changetexgen(int orient, Slot &slot, VSlot &vslot)
1007 : {
1008 0 : if(texgenslot != &slot || texgenvslot != &vslot)
1009 : {
1010 0 : const Texture *curtex = !texgenslot || texgenslot->sts.empty() ? notexture : texgenslot->sts[0].t;
1011 0 : const Texture *tex = slot.sts.empty() ? notexture : slot.sts[0].t;
1012 0 : if(!texgenvslot || slot.sts.empty() ||
1013 0 : (curtex->xs != tex->xs || curtex->ys != tex->ys ||
1014 0 : texgenvslot->rotation != vslot.rotation || texgenvslot->scale != vslot.scale ||
1015 0 : texgenvslot->offset != vslot.offset || texgenvslot->scroll != vslot.scroll) ||
1016 0 : texgenvslot->angle != vslot.angle)
1017 : {
1018 0 : const texrotation &r = texrotations[vslot.rotation];
1019 0 : float xs = r.flipx ? -tex->xs : tex->xs,
1020 0 : ys = r.flipy ? -tex->ys : tex->ys;
1021 0 : vec2 scroll(vslot.scroll);
1022 0 : if(r.swapxy)
1023 : {
1024 0 : std::swap(scroll.x, scroll.y);
1025 : }
1026 0 : scroll.x *= texgenmillis*tex->xs/xs;
1027 0 : scroll.y *= texgenmillis*tex->ys/ys;
1028 0 : if(texgenscroll != scroll)
1029 : {
1030 0 : texgenscroll = scroll;
1031 0 : texgenorient = -1;
1032 : }
1033 : }
1034 0 : texgenslot = &slot;
1035 0 : texgenvslot = &vslot;
1036 : }
1037 :
1038 0 : if(texgenorient == orient)
1039 : {
1040 0 : return;
1041 : }
1042 0 : GLOBALPARAM(texgenscroll, texgenscroll);
1043 :
1044 0 : texgenorient = orient;
1045 : }
1046 :
1047 0 : void renderstate::changeshader(int pass, const geombatch &b)
1048 : {
1049 0 : VSlot &vslot = b.vslot;
1050 0 : Slot &slot = *vslot.slot;
1051 0 : if(pass == RenderPass_ReflectiveShadowMap)
1052 : {
1053 0 : if(b.es.attrs.layer&BlendLayer_Bottom)
1054 : {
1055 0 : rsmworldshader->setvariant(0, 0, slot, vslot);
1056 : }
1057 : else
1058 : {
1059 0 : rsmworldshader->set(slot, vslot);
1060 : }
1061 : }
1062 0 : else if(alphaing)
1063 : {
1064 0 : slot.shader->setvariant(alphaing > 1 && vslot.refractscale > 0 ? 1 : 0, 1, slot, vslot);
1065 : }
1066 0 : else if(b.es.attrs.layer&BlendLayer_Bottom)
1067 : {
1068 0 : slot.shader->setvariant(0, 0, slot, vslot);
1069 : }
1070 : else
1071 : {
1072 0 : slot.shader->set(slot, vslot);
1073 : }
1074 0 : globals = GlobalShaderParamState::nextversion;
1075 0 : }
1076 :
1077 : template<class T>
1078 0 : void updateshader(T &cur)
1079 : {
1080 0 : if(cur.globals != GlobalShaderParamState::nextversion)
1081 : {
1082 0 : if(Shader::lastshader)
1083 : {
1084 0 : Shader::lastshader->flushparams();
1085 : }
1086 0 : cur.globals = GlobalShaderParamState::nextversion;
1087 : }
1088 0 : }
1089 :
1090 0 : void geombatch::renderbatch() const
1091 : {
1092 0 : gbatches++;
1093 0 : for(const geombatch *curbatch = this;; curbatch = &geombatches[curbatch->batch])
1094 : {
1095 0 : ushort len = curbatch->es.length;
1096 0 : if(len)
1097 : {
1098 0 : drawtris(len, (ushort *)0 + curbatch->va->eoffset + curbatch->offset, curbatch->es.minvert, curbatch->es.maxvert);
1099 0 : vtris += len/3;
1100 : }
1101 0 : if(curbatch->batch < 0)
1102 : {
1103 0 : break;
1104 : }
1105 0 : }
1106 0 : }
1107 :
1108 0 : void resetbatches()
1109 : {
1110 0 : geombatches.clear();
1111 0 : firstbatch = -1;
1112 0 : numbatches = 0;
1113 0 : }
1114 :
1115 0 : void renderstate::renderbatches(int pass)
1116 : {
1117 0 : vslot = nullptr;
1118 0 : int curbatch = firstbatch;
1119 0 : if(curbatch >= 0)
1120 : {
1121 0 : if(!depthmask)
1122 : {
1123 0 : depthmask = true;
1124 0 : glDepthMask(GL_TRUE);
1125 : }
1126 0 : if(!colormask)
1127 : {
1128 0 : colormask = true;
1129 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1130 : }
1131 0 : if(!vattribs)
1132 : {
1133 0 : if(vquery)
1134 : {
1135 0 : disablevquery();
1136 : }
1137 0 : enablevattribs();
1138 : }
1139 : }
1140 0 : while(curbatch >= 0)
1141 : {
1142 0 : const geombatch &b = geombatches[curbatch];
1143 0 : curbatch = b.next;
1144 :
1145 0 : if(vbuf != b.va->vbuf)
1146 : {
1147 0 : changevbuf(*this, pass, *b.va);
1148 : }
1149 0 : if(pass == RenderPass_GBuffer || pass == RenderPass_ReflectiveShadowMap)
1150 : {
1151 0 : changebatchtmus();
1152 : }
1153 0 : if(vslot != &b.vslot)
1154 : {
1155 0 : changeslottmus(pass, *b.vslot.slot, b.vslot);
1156 0 : if(texgenorient != b.es.attrs.orient || (texgenorient < Orient_Any && texgenvslot != &b.vslot))
1157 : {
1158 0 : changetexgen(b.es.attrs.orient, *b.vslot.slot, b.vslot);
1159 : }
1160 0 : changeshader(pass, b);
1161 : }
1162 : else
1163 : {
1164 0 : if(texgenorient != b.es.attrs.orient)
1165 : {
1166 0 : changetexgen(b.es.attrs.orient, *b.vslot.slot, b.vslot);
1167 : }
1168 0 : updateshader(*this);
1169 : }
1170 :
1171 0 : b.renderbatch();
1172 : }
1173 :
1174 0 : resetbatches();
1175 0 : }
1176 :
1177 0 : void renderstate::renderzpass(const vtxarray &va)
1178 : {
1179 0 : if(!vattribs)
1180 : {
1181 0 : if(vquery)
1182 : {
1183 0 : disablevquery();
1184 : }
1185 0 : enablevattribs(false);
1186 : }
1187 0 : if(vbuf!=va.vbuf)
1188 : {
1189 0 : changevbuf(*this, RenderPass_Z, va);
1190 : }
1191 0 : if(!depthmask)
1192 : {
1193 0 : depthmask = true;
1194 0 : glDepthMask(GL_TRUE);
1195 : }
1196 0 : if(colormask)
1197 : {
1198 0 : colormask = false;
1199 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1200 : }
1201 0 : int firsttex = 0,
1202 0 : numtris = va.tris,
1203 0 : offset = 0;
1204 0 : if(alphaing)
1205 : {
1206 0 : firsttex += va.texs;
1207 0 : offset += 3*(va.tris);
1208 0 : numtris = va.alphabacktris + va.alphafronttris + va.refracttris;
1209 0 : xtravertsva += 3*numtris;
1210 : }
1211 : else
1212 : {
1213 0 : xtravertsva += va.verts;
1214 : }
1215 0 : nocolorshader->set();
1216 0 : drawvatris(va, 3*numtris, offset);
1217 0 : }
1218 :
1219 : VAR(batchgeom, 0, 1, 1);
1220 :
1221 0 : void renderva(renderstate &cur, const vtxarray &va, int pass = RenderPass_GBuffer, bool doquery = false)
1222 : {
1223 0 : switch(pass)
1224 : {
1225 0 : case RenderPass_GBuffer:
1226 0 : if(!cur.alphaing)
1227 : {
1228 0 : vverts += va.verts;
1229 : }
1230 0 : if(doquery && va.query)
1231 : {
1232 0 : if(geombatches.size())
1233 : {
1234 0 : cur.renderbatches(pass);
1235 : }
1236 0 : va.query->startquery();
1237 : }
1238 0 : mergetexs(cur, va);
1239 0 : if(doquery)
1240 : {
1241 0 : if(va.query)
1242 : {
1243 0 : if(geombatches.size())
1244 : {
1245 0 : cur.renderbatches(pass);
1246 : }
1247 0 : occlusionengine.endquery();
1248 : }
1249 : }
1250 0 : else if(!batchgeom && geombatches.size())
1251 : {
1252 0 : cur.renderbatches(pass);
1253 : }
1254 0 : break;
1255 :
1256 0 : case RenderPass_GBufferBlend:
1257 0 : if(doquery && va.query)
1258 : {
1259 0 : if(geombatches.size())
1260 : {
1261 0 : cur.renderbatches(RenderPass_GBuffer);
1262 : }
1263 0 : va.query->startquery();
1264 : }
1265 0 : mergetexs(cur, va, &va.texelems[va.texs], 3*va.tris);
1266 0 : if(doquery)
1267 : {
1268 0 : if(va.query)
1269 : {
1270 0 : if(geombatches.size())
1271 : {
1272 0 : cur.renderbatches(RenderPass_GBuffer);
1273 : }
1274 0 : occlusionengine.endquery();
1275 : }
1276 : }
1277 0 : else if(!batchgeom && geombatches.size())
1278 : {
1279 0 : cur.renderbatches(RenderPass_GBuffer);
1280 : }
1281 0 : break;
1282 :
1283 0 : case RenderPass_Caustics:
1284 0 : if(!cur.vattribs)
1285 : {
1286 0 : cur.enablevattribs(false);
1287 : }
1288 0 : if(cur.vbuf!=va.vbuf)
1289 : {
1290 0 : changevbuf(cur, pass, va);
1291 : }
1292 0 : drawvatris(va, 3*va.tris, 0);
1293 0 : xtravertsva += va.verts;
1294 0 : break;
1295 :
1296 0 : case RenderPass_Z:
1297 0 : if(doquery && va.query)
1298 : {
1299 0 : va.query->startquery();
1300 : }
1301 0 : cur.renderzpass(va);
1302 0 : if(doquery && va.query)
1303 : {
1304 0 : occlusionengine.endquery();
1305 : }
1306 0 : break;
1307 :
1308 0 : case RenderPass_ReflectiveShadowMap:
1309 0 : mergetexs(cur, va);
1310 0 : if(!batchgeom && geombatches.size())
1311 : {
1312 0 : cur.renderbatches(pass);
1313 : }
1314 0 : break;
1315 :
1316 0 : case RenderPass_ReflectiveShadowMapBlend:
1317 0 : mergetexs(cur, va, &va.texelems[va.texs], 3*va.tris);
1318 0 : if(!batchgeom && geombatches.size())
1319 : {
1320 0 : cur.renderbatches(RenderPass_ReflectiveShadowMap);
1321 : }
1322 0 : break;
1323 : }
1324 0 : }
1325 :
1326 0 : void setupgeom()
1327 : {
1328 0 : glActiveTexture(GL_TEXTURE0);
1329 0 : GLOBALPARAMF(colorparams, 1, 1, 1, 1);
1330 0 : }
1331 :
1332 0 : void renderstate::cleanupgeom()
1333 : {
1334 0 : if(vattribs)
1335 : {
1336 0 : disablevattribs();
1337 : }
1338 0 : if(vbuf)
1339 : {
1340 0 : disablevbuf();
1341 : }
1342 0 : }
1343 :
1344 : VAR(oqgeom, 0, 1, 1); //occlusion query geometry
1345 :
1346 : std::vector<const vtxarray *> alphavas;
1347 :
1348 0 : CVARP(explicitskycolor, 0x800080);
1349 :
1350 : struct decalbatch
1351 : {
1352 : const elementset &es;
1353 : DecalSlot &slot;
1354 : int offset;
1355 : const vtxarray &va;
1356 : int next, batch;
1357 :
1358 0 : decalbatch(const elementset &es, int offset, const vtxarray &va)
1359 0 : : es(es), slot(lookupdecalslot(es.texture)), offset(offset), va(va),
1360 0 : next(-1), batch(-1)
1361 0 : {}
1362 :
1363 : void renderdecalbatch();
1364 :
1365 0 : int compare(const decalbatch &b) const
1366 : {
1367 0 : if(va.vbuf < b.va.vbuf)
1368 : {
1369 0 : return -1;
1370 : }
1371 0 : if(va.vbuf > b.va.vbuf)
1372 : {
1373 0 : return 1;
1374 : }
1375 0 : if(slot.shader < b.slot.shader)
1376 : {
1377 0 : return -1;
1378 : }
1379 0 : if(slot.shader > b.slot.shader)
1380 : {
1381 0 : return 1;
1382 : }
1383 0 : if(es.texture < b.es.texture)
1384 : {
1385 0 : return -1;
1386 : }
1387 0 : if(es.texture > b.es.texture)
1388 : {
1389 0 : return 1;
1390 : }
1391 0 : if(slot.Slot::params.size() < b.slot.Slot::params.size())
1392 : {
1393 0 : return -1;
1394 : }
1395 0 : if(slot.Slot::params.size() > b.slot.Slot::params.size())
1396 : {
1397 0 : return 1;
1398 : }
1399 0 : if(es.reuse < b.es.reuse)
1400 : {
1401 0 : return -1;
1402 : }
1403 0 : if(es.reuse > b.es.reuse)
1404 : {
1405 0 : return 1;
1406 : }
1407 0 : return 0;
1408 : }
1409 : };
1410 :
1411 : std::vector<decalbatch> decalbatches;
1412 :
1413 : class decalrenderer
1414 : {
1415 : public:
1416 : GLuint vbuf;
1417 : int globals;
1418 :
1419 : void renderdecalbatches(int pass);
1420 :
1421 0 : decalrenderer() : vbuf(0), globals(-1), colorscale(1, 1, 1), tmu(-1), slot(nullptr)
1422 : {
1423 0 : for(int i = 0; i < 7; ++i)
1424 : {
1425 0 : textures[i] = 0;
1426 : }
1427 0 : }
1428 : private:
1429 : vec colorscale;
1430 : int tmu;
1431 : GLuint textures[7];
1432 : DecalSlot *slot;
1433 :
1434 : void changebatchtmus();
1435 : void bindslottex(int type, const Texture *tex, GLenum target = GL_TEXTURE_2D);
1436 : void changeslottmus(DecalSlot &slot);
1437 : void changeshader(int pass, const decalbatch &b);
1438 : };
1439 :
1440 0 : void mergedecals(const vtxarray &va)
1441 : {
1442 0 : elementset *texs = va.decalelems;
1443 0 : int numtexs = va.decaltexs,
1444 0 : offset = 0;
1445 :
1446 0 : if(firstbatch < 0)
1447 : {
1448 0 : firstbatch = decalbatches.size();
1449 0 : numbatches = numtexs;
1450 0 : for(int i = 0; i < numtexs-1; ++i)
1451 : {
1452 0 : decalbatches.emplace_back(decalbatch(texs[i], offset, va));
1453 0 : decalbatches.back().next = i+1;
1454 0 : offset += texs[i].length;
1455 : }
1456 0 : decalbatches.emplace_back(decalbatch(texs[numtexs-1], offset, va));
1457 0 : return;
1458 : }
1459 :
1460 0 : int prevbatch = -1,
1461 0 : curbatch = firstbatch,
1462 0 : curtex = 0;
1463 : do
1464 : {
1465 0 : decalbatch b = decalbatch(texs[curtex], offset, va);
1466 0 : offset += texs[curtex].length;
1467 0 : int dir = -1;
1468 0 : while(curbatch >= 0)
1469 : {
1470 0 : dir = b.compare(decalbatches[curbatch]);
1471 0 : if(dir <= 0)
1472 : {
1473 0 : break;
1474 : }
1475 0 : prevbatch = curbatch;
1476 0 : curbatch = decalbatches[curbatch].next;
1477 : }
1478 0 : if(!dir)
1479 : {
1480 0 : int last = curbatch, next;
1481 : for(;;)
1482 : {
1483 0 : next = decalbatches[last].batch;
1484 0 : if(next < 0)
1485 : {
1486 0 : break;
1487 : }
1488 0 : last = next;
1489 : }
1490 0 : if(last==curbatch)
1491 : {
1492 0 : b.batch = curbatch;
1493 0 : b.next = decalbatches[curbatch].next;
1494 0 : if(prevbatch < 0)
1495 : {
1496 0 : firstbatch = decalbatches.size()-1;
1497 : }
1498 : else
1499 : {
1500 0 : decalbatches[prevbatch].next = decalbatches.size()-1;
1501 : }
1502 0 : curbatch = decalbatches.size()-1;
1503 : }
1504 : else
1505 : {
1506 0 : b.batch = next;
1507 0 : decalbatches[last].batch = decalbatches.size()-1;
1508 : }
1509 : }
1510 : else
1511 : {
1512 0 : numbatches++;
1513 0 : b.next = curbatch;
1514 0 : if(prevbatch < 0)
1515 : {
1516 0 : firstbatch = decalbatches.size()-1;
1517 : }
1518 : else
1519 : {
1520 0 : decalbatches[prevbatch].next = decalbatches.size()-1;
1521 : }
1522 0 : prevbatch = decalbatches.size()-1;
1523 : }
1524 0 : decalbatches.push_back(b);
1525 0 : } while(++curtex < numtexs);
1526 : }
1527 :
1528 0 : void resetdecalbatches()
1529 : {
1530 0 : decalbatches.clear();
1531 0 : firstbatch = -1;
1532 0 : numbatches = 0;
1533 0 : }
1534 :
1535 0 : void changevbuf(decalrenderer &cur, const vtxarray &va)
1536 : {
1537 0 : gle::bindvbo(va.vbuf);
1538 0 : gle::bindebo(va.decalbuf);
1539 0 : cur.vbuf = va.vbuf;
1540 0 : vertex *vdata = nullptr;
1541 : //note inane bikeshedding: use of offset from dereferenced null ptr (aka 0)
1542 0 : gle::vertexpointer(sizeof(vertex), vdata->pos.data());
1543 0 : gle::normalpointer(sizeof(vertex), vdata->norm.data(), GL_BYTE, 4);
1544 0 : gle::texcoord0pointer(sizeof(vertex), vdata->tc.data(), GL_FLOAT, 3);
1545 0 : gle::tangentpointer(sizeof(vertex), vdata->tangent.data(), GL_BYTE);
1546 0 : }
1547 :
1548 0 : void decalrenderer::changebatchtmus()
1549 : {
1550 0 : if(tmu != 0)
1551 : {
1552 0 : tmu = 0;
1553 0 : glActiveTexture(GL_TEXTURE0);
1554 : }
1555 0 : }
1556 :
1557 0 : void decalrenderer::bindslottex(int type, const Texture *tex, GLenum target)
1558 : {
1559 0 : if(textures[type] != tex->id)
1560 : {
1561 0 : if(tmu != type)
1562 : {
1563 0 : tmu = type;
1564 0 : glActiveTexture(GL_TEXTURE0 + type);
1565 : }
1566 0 : glBindTexture(target, textures[type] = tex->id);
1567 : }
1568 0 : }
1569 :
1570 0 : void decalrenderer::changeslottmus(DecalSlot &dslot)
1571 : {
1572 0 : const Texture *diffuse = dslot.sts.empty() ? notexture : dslot.sts[0].t;
1573 0 : bindslottex(Tex_Diffuse, diffuse);
1574 0 : for(const Slot::Tex &t : dslot.sts)
1575 : {
1576 0 : switch(t.type)
1577 : {
1578 0 : case Tex_Normal:
1579 : case Tex_Glow:
1580 : {
1581 0 : bindslottex(t.type, t.t);
1582 0 : break;
1583 : }
1584 0 : case Tex_Spec:
1585 : {
1586 0 : if(t.combined < 0)
1587 : {
1588 0 : bindslottex(Tex_Glow, t.t);
1589 : }
1590 0 : break;
1591 : }
1592 : }
1593 : }
1594 0 : if(tmu != 0)
1595 : {
1596 0 : tmu = 0;
1597 0 : glActiveTexture(GL_TEXTURE0);
1598 : }
1599 0 : if(colorscale != dslot.colorscale)
1600 : {
1601 0 : colorscale = dslot.colorscale;
1602 0 : GLOBALPARAMF(colorparams, dslot.colorscale.x, dslot.colorscale.y, dslot.colorscale.z, 1);
1603 : }
1604 0 : slot = &dslot;
1605 0 : }
1606 :
1607 0 : void decalrenderer::changeshader(int pass, const decalbatch &b)
1608 : {
1609 0 : DecalSlot &slot = b.slot;
1610 0 : if(b.es.reuse)
1611 : {
1612 0 : VSlot &reuse = lookupvslot(b.es.reuse);
1613 0 : if(pass)
1614 : {
1615 0 : slot.shader->setvariant(0, 0, slot, reuse);
1616 : }
1617 : else
1618 : {
1619 0 : slot.shader->set(slot, reuse);
1620 : }
1621 : }
1622 0 : else if(pass)
1623 : {
1624 0 : slot.shader->setvariant(0, 0, slot);
1625 : }
1626 : else
1627 : {
1628 0 : slot.shader->set(slot);
1629 : }
1630 0 : globals = GlobalShaderParamState::nextversion;
1631 0 : }
1632 :
1633 0 : void decalbatch::renderdecalbatch()
1634 : {
1635 0 : gbatches++;
1636 0 : for(decalbatch *curbatch = this;; curbatch = &decalbatches[curbatch->batch])
1637 : {
1638 0 : ushort len = curbatch->es.length;
1639 0 : if(len)
1640 : {
1641 0 : drawtris(len, reinterpret_cast<ushort *>(curbatch->va.decaloffset) + curbatch->offset, curbatch->es.minvert, curbatch->es.maxvert);
1642 0 : vtris += len/3;
1643 : }
1644 0 : if(curbatch->batch < 0)
1645 : {
1646 0 : break;
1647 : }
1648 0 : }
1649 0 : }
1650 :
1651 0 : void decalrenderer::renderdecalbatches(int pass)
1652 : {
1653 0 : slot = nullptr;
1654 0 : int curbatch = firstbatch;
1655 0 : while(curbatch >= 0)
1656 : {
1657 0 : decalbatch &b = decalbatches[curbatch];
1658 0 : curbatch = b.next;
1659 :
1660 0 : if(pass && !b.slot.shader->numvariants(0))
1661 : {
1662 0 : continue;
1663 : }
1664 0 : if(vbuf != b.va.vbuf)
1665 : {
1666 0 : changevbuf(*this, b.va);
1667 : }
1668 0 : changebatchtmus();
1669 0 : if(slot != &b.slot)
1670 : {
1671 0 : changeslottmus(b.slot);
1672 0 : changeshader(pass, b);
1673 : }
1674 : else
1675 : {
1676 0 : updateshader(*this);
1677 : }
1678 :
1679 0 : b.renderdecalbatch();
1680 : }
1681 :
1682 0 : resetdecalbatches();
1683 0 : }
1684 :
1685 0 : void setupdecals()
1686 : {
1687 0 : gle::enablevertex();
1688 0 : gle::enablenormal();
1689 0 : gle::enabletexcoord0();
1690 0 : gle::enabletangent();
1691 :
1692 0 : glDepthMask(GL_FALSE);
1693 0 : glEnable(GL_BLEND);
1694 0 : enablepolygonoffset(GL_POLYGON_OFFSET_FILL);
1695 :
1696 0 : GLOBALPARAMF(colorparams, 1, 1, 1, 1);
1697 0 : }
1698 :
1699 0 : void cleanupdecals()
1700 : {
1701 0 : disablepolygonoffset(GL_POLYGON_OFFSET_FILL);
1702 0 : glDisable(GL_BLEND);
1703 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1704 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1705 0 : glDepthMask(GL_TRUE);
1706 0 : maskgbuffer("cnd");
1707 :
1708 0 : gle::disablevertex();
1709 0 : gle::disablenormal();
1710 0 : gle::disabletexcoord0();
1711 0 : gle::disabletangent();
1712 :
1713 0 : gle::clearvbo();
1714 0 : gle::clearebo();
1715 0 : }
1716 :
1717 : VAR(batchdecals, 0, 1, 1);
1718 :
1719 : struct shadowdraw
1720 : {
1721 : GLuint ebuf, vbuf;
1722 : int offset, tris, next;
1723 : GLuint minvert, maxvert;
1724 : };
1725 :
1726 : struct shadowverts
1727 : {
1728 : static constexpr int tablesize = 1<<13;
1729 : std::array<int, tablesize> table;
1730 : std::vector<vec> verts;
1731 : std::vector<int> chain;
1732 :
1733 1 : shadowverts() { clear(); }
1734 :
1735 1 : void clear()
1736 : {
1737 1 : table.fill(-1);
1738 1 : chain.clear();
1739 1 : verts.clear();
1740 1 : }
1741 :
1742 0 : int add(const vec &v)
1743 : {
1744 : auto vechash = std::hash<vec>();
1745 0 : uint h = vechash(v)&(tablesize-1);
1746 0 : for(int i = table[h]; i>=0; i = chain[i])
1747 : {
1748 0 : if(verts[i] == v)
1749 : {
1750 0 : return i;
1751 : }
1752 : }
1753 0 : if(verts.size() >= USHRT_MAX)
1754 : {
1755 0 : return -1;
1756 : }
1757 0 : verts.push_back(v);
1758 0 : chain.emplace_back(table[h]);
1759 0 : return table[h] = verts.size()-1;
1760 : }
1761 : } shadowverts;
1762 : std::array<std::vector<GLuint>, 6> shadowtris;
1763 : std::vector<GLuint> shadowvbos;
1764 : std::unordered_map<int, shadowmesh> shadowmeshes;
1765 : std::vector<shadowdraw> shadowdraws;
1766 :
1767 : struct shadowdrawinfo
1768 : {
1769 : int last;
1770 : GLuint minvert, maxvert;
1771 :
1772 0 : shadowdrawinfo() : last(-1)
1773 : {
1774 0 : reset();
1775 0 : }
1776 :
1777 0 : void reset()
1778 : {
1779 0 : minvert = USHRT_MAX;
1780 0 : maxvert = 0;
1781 0 : }
1782 : };
1783 :
1784 0 : void flushshadowmeshdraws(shadowmesh &m, int sides, std::array<shadowdrawinfo, 6> &draws)
1785 : {
1786 0 : int numindexes = 0;
1787 0 : for(int i = 0; i < sides; ++i)
1788 : {
1789 0 : numindexes += shadowtris[i].size();
1790 : }
1791 0 : if(!numindexes)
1792 : {
1793 0 : return;
1794 : }
1795 :
1796 0 : GLuint ebuf = 0,
1797 0 : vbuf = 0;
1798 0 : glGenBuffers(1, &ebuf);
1799 0 : glGenBuffers(1, &vbuf);
1800 0 : ushort *indexes = new ushort[numindexes];
1801 0 : int offset = 0;
1802 0 : for(int i = 0; i < sides; ++i)
1803 : {
1804 0 : if(shadowtris[i].size())
1805 : {
1806 0 : if(draws[i].last < 0)
1807 : {
1808 0 : m.draws[i] = shadowdraws.size();
1809 : }
1810 : else
1811 : {
1812 0 : shadowdraws[draws[i].last].next = shadowdraws.size();
1813 : }
1814 0 : draws[i].last = shadowdraws.size();
1815 :
1816 : shadowdraw d;
1817 0 : d.ebuf = ebuf;
1818 0 : d.vbuf = vbuf;
1819 0 : d.offset = offset;
1820 0 : d.tris = shadowtris[i].size()/3;
1821 0 : d.minvert = draws[i].minvert;
1822 0 : d.maxvert = draws[i].maxvert;
1823 0 : d.next = -1;
1824 0 : shadowdraws.push_back(d);
1825 :
1826 0 : std::memcpy(indexes + offset, shadowtris[i].data(), shadowtris[i].size()*sizeof(ushort));
1827 0 : offset += shadowtris[i].size();
1828 :
1829 0 : shadowtris[i].clear();
1830 0 : draws[i].reset();
1831 : }
1832 : }
1833 :
1834 0 : gle::bindebo(ebuf);
1835 0 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, numindexes*sizeof(ushort), indexes, GL_STATIC_DRAW);
1836 0 : gle::clearebo();
1837 0 : delete[] indexes;
1838 :
1839 0 : gle::bindvbo(vbuf);
1840 0 : glBufferData(GL_ARRAY_BUFFER, shadowverts.verts.size()*sizeof(vec), shadowverts.verts.data(), GL_STATIC_DRAW);
1841 0 : gle::clearvbo();
1842 0 : shadowverts.clear();
1843 :
1844 0 : shadowvbos.push_back(ebuf);
1845 0 : shadowvbos.push_back(vbuf);
1846 : }
1847 :
1848 0 : int calctrisidemask(const vec &p1, const vec &p2, const vec &p3, float bias)
1849 : {
1850 : // p1, p2, p3 are in the cubemap's local coordinate system
1851 : // bias = border/(size - border)
1852 0 : int mask = 0x3F;
1853 0 : float dp1 = p1.x + p1.y,
1854 0 : dn1 = p1.x - p1.y,
1855 0 : ap1 = std::fabs(dp1),
1856 0 : an1 = std::fabs(dn1),
1857 0 : dp2 = p2.x + p2.y,
1858 0 : dn2 = p2.x - p2.y,
1859 0 : ap2 = std::fabs(dp2),
1860 0 : an2 = std::fabs(dn2),
1861 0 : dp3 = p3.x + p3.y,
1862 0 : dn3 = p3.x - p3.y,
1863 0 : ap3 = std::fabs(dp3),
1864 0 : an3 = std::fabs(dn3);
1865 0 : if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1866 : {
1867 0 : mask &= (3<<4)
1868 0 : | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1869 0 : | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1870 0 : | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1871 : }
1872 0 : if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1873 0 : mask &= (3<<4)
1874 0 : | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1875 0 : | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1876 0 : | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1877 0 : dp1 = p1.y + p1.z,
1878 0 : dn1 = p1.y - p1.z,
1879 0 : ap1 = std::fabs(dp1),
1880 0 : an1 = std::fabs(dn1),
1881 0 : dp2 = p2.y + p2.z,
1882 0 : dn2 = p2.y - p2.z,
1883 0 : ap2 = std::fabs(dp2),
1884 0 : an2 = std::fabs(dn2),
1885 0 : dp3 = p3.y + p3.z,
1886 0 : dn3 = p3.y - p3.z,
1887 0 : ap3 = std::fabs(dp3),
1888 0 : an3 = std::fabs(dn3);
1889 0 : if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1890 : {
1891 0 : mask &= (3<<0)
1892 0 : | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1893 0 : | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1894 0 : | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1895 : }
1896 0 : if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1897 : {
1898 0 : mask &= (3<<0)
1899 0 : | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1900 0 : | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1901 0 : | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1902 : }
1903 0 : dp1 = p1.z + p1.x,
1904 0 : dn1 = p1.z - p1.x,
1905 0 : ap1 = std::fabs(dp1),
1906 0 : an1 = std::fabs(dn1),
1907 0 : dp2 = p2.z + p2.x,
1908 0 : dn2 = p2.z - p2.x,
1909 0 : ap2 = std::fabs(dp2),
1910 0 : an2 = std::fabs(dn2),
1911 0 : dp3 = p3.z + p3.x,
1912 0 : dn3 = p3.z - p3.x,
1913 0 : ap3 = std::fabs(dp3),
1914 0 : an3 = std::fabs(dn3);
1915 0 : if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1916 : {
1917 0 : mask &= (3<<2)
1918 0 : | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1919 0 : | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1920 0 : | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1921 : }
1922 0 : if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1923 : {
1924 0 : mask &= (3<<2)
1925 0 : | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1926 0 : | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1927 0 : | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1928 : }
1929 0 : return mask;
1930 : }
1931 :
1932 0 : void addshadowmeshtri(shadowmesh &m, int sides, std::array<shadowdrawinfo, 6> &draws, const vec &v0, const vec &v1, const vec &v2)
1933 : {
1934 0 : vec l0 = vec(v0).sub(shadoworigin);
1935 0 : float side = l0.scalartriple(vec(v1).sub(v0), vec(v2).sub(v0));
1936 0 : if(smcullside ? side > 0 : side < 0)
1937 : {
1938 0 : return;
1939 : }
1940 0 : vec l1 = vec(v1).sub(shadoworigin),
1941 0 : l2 = vec(v2).sub(shadoworigin);
1942 0 : if(l0.squaredlen() > shadowradius*shadowradius && l1.squaredlen() > shadowradius*shadowradius && l2.squaredlen() > shadowradius*shadowradius)
1943 : {
1944 0 : return;
1945 : }
1946 0 : int sidemask = 0;
1947 0 : switch(m.type)
1948 : {
1949 0 : case ShadowMap_Spot:
1950 : {
1951 0 : sidemask = bbinsidespot(shadoworigin, shadowdir, shadowspot, ivec(vec(v0).min(v1).min(v2)), ivec(vec(v0).max(v1).max(v2).add(1))) ? 1 : 0;
1952 0 : break;
1953 : }
1954 0 : case ShadowMap_CubeMap:
1955 : {
1956 0 : sidemask = calctrisidemask(l0.div(shadowradius), l1.div(shadowradius), l2.div(shadowradius), shadowbias);
1957 0 : break;
1958 : }
1959 : }
1960 0 : if(!sidemask)
1961 : {
1962 0 : return;
1963 : }
1964 0 : if(shadowverts.verts.size() + 3 >= USHRT_MAX)
1965 : {
1966 0 : flushshadowmeshdraws(m, sides, draws);
1967 : }
1968 0 : int i0 = shadowverts.add(v0),
1969 0 : i1 = shadowverts.add(v1),
1970 0 : i2 = shadowverts.add(v2);
1971 0 : GLuint minvert = std::min(i0, std::min(i1, i2)),
1972 0 : maxvert = std::max(i0, std::max(i1, i2));
1973 0 : for(int k = 0; k < sides; ++k)
1974 : {
1975 0 : if(sidemask&(1<<k))
1976 : {
1977 0 : shadowdrawinfo &d = draws[k];
1978 0 : d.minvert = std::min(d.minvert, minvert);
1979 0 : d.maxvert = std::max(d.maxvert, maxvert);
1980 0 : shadowtris[k].push_back(i0);
1981 0 : shadowtris[k].push_back(i1);
1982 0 : shadowtris[k].push_back(i2);
1983 : }
1984 : }
1985 : }
1986 :
1987 0 : void genshadowmeshtris(shadowmesh &m, int sides, std::array<shadowdrawinfo, 6> &draws, ushort *edata, int numtris, vertex *vdata)
1988 : {
1989 0 : for(int j = 0; j < 3*numtris; j += 3)
1990 : {
1991 0 : addshadowmeshtri(m, sides, draws, vdata[edata[j]].pos, vdata[edata[j+1]].pos, vdata[edata[j+2]].pos);
1992 : }
1993 0 : }
1994 :
1995 0 : void genshadowmeshmapmodels(shadowmesh &m, int sides, std::array<shadowdrawinfo, 6> &draws)
1996 : {
1997 0 : const std::vector<extentity *> &ents = entities::getents();
1998 0 : for(octaentities *oe = shadowmms; oe; oe = oe->rnext)
1999 : {
2000 0 : for(uint k = 0; k < oe->mapmodels.size(); k++)
2001 : {
2002 0 : extentity &e = *ents[oe->mapmodels[k]];
2003 0 : if(e.flags&(EntFlag_NoVis|EntFlag_NoShadow))
2004 : {
2005 0 : continue;
2006 : }
2007 0 : e.flags |= EntFlag_Render;
2008 : }
2009 : }
2010 0 : std::vector<triangle> tris;
2011 0 : for(octaentities *oe = shadowmms; oe; oe = oe->rnext)
2012 : {
2013 0 : for(const int &j : oe->mapmodels)
2014 : {
2015 0 : extentity &e = *ents[j];
2016 0 : if(!(e.flags&EntFlag_Render))
2017 : {
2018 0 : continue;
2019 : }
2020 0 : e.flags &= ~EntFlag_Render;
2021 0 : model *mm = loadmapmodel(e.attr1);
2022 0 : if(!mm || !mm->shadow || mm->animated() || (mm->alphashadow && mm->alphatested()))
2023 : {
2024 0 : continue;
2025 : }
2026 0 : matrix4x3 orient;
2027 0 : orient.identity();
2028 0 : if(e.attr2)
2029 : {
2030 0 : orient.rotate_around_z(sincosmod360(e.attr2));
2031 : }
2032 0 : if(e.attr3)
2033 : {
2034 0 : orient.rotate_around_x(sincosmod360(e.attr3));
2035 : }
2036 0 : if(e.attr4)
2037 : {
2038 0 : orient.rotate_around_y(sincosmod360(-e.attr4));
2039 : }
2040 0 : if(e.attr5 > 0)
2041 : {
2042 0 : orient.scale(e.attr5/100.0f);
2043 : }
2044 0 : orient.settranslation(e.o);
2045 0 : tris.clear();
2046 0 : mm->genshadowmesh(tris, orient);
2047 :
2048 0 : for(uint i = 0; i < tris.size(); i++)
2049 : {
2050 0 : triangle &t = tris[i];
2051 0 : addshadowmeshtri(m, sides, draws, t.a, t.b, t.c);
2052 : }
2053 :
2054 0 : e.flags |= EntFlag_ShadowMesh;
2055 : }
2056 : }
2057 0 : }
2058 :
2059 0 : void genshadowmesh(int idx, const extentity &e)
2060 : {
2061 0 : shadowmesh m;
2062 0 : m.type = calcshadowinfo(e, m.origin, m.radius, m.spotloc, m.spotangle, shadowbias);
2063 0 : if(!m.type)
2064 : {
2065 0 : return;
2066 : }
2067 0 : m.draws.fill(-1);
2068 :
2069 0 : shadowmapping = m.type;
2070 0 : shadoworigin = m.origin;
2071 0 : shadowradius = m.radius;
2072 0 : shadowdir = m.type == ShadowMap_Spot ? vec(m.spotloc).sub(m.origin).normalize() : vec(0, 0, 0);
2073 0 : shadowspot = m.spotangle;
2074 :
2075 0 : findshadowvas();
2076 0 : findshadowmms();
2077 :
2078 0 : int sides = m.type == ShadowMap_Spot ? 1 : 6;
2079 0 : std::array<shadowdrawinfo, 6> draws;
2080 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
2081 : {
2082 0 : if(va->shadowmask)
2083 : {
2084 0 : if(va->tris)
2085 : {
2086 0 : genshadowmeshtris(m, sides, draws, va->edata + va->eoffset, va->tris, va->vdata);
2087 : }
2088 0 : if(skyshadow && va->sky)
2089 : {
2090 0 : genshadowmeshtris(m, sides, draws, va->skydata + va->skyoffset, va->sky/3, va->vdata);
2091 : }
2092 : }
2093 : }
2094 0 : if(shadowmms)
2095 : {
2096 0 : genshadowmeshmapmodels(m, sides, draws);
2097 : }
2098 0 : flushshadowmeshdraws(m, sides, draws);
2099 :
2100 0 : shadowmeshes[idx] = m;
2101 :
2102 0 : shadowmapping = 0;
2103 : }
2104 :
2105 0 : VARF(smmesh, 0, 1, 1, { if(!smmesh) clearshadowmeshes(); });
2106 : }
2107 :
2108 : /* externally relevant functionality */
2109 : ///////////////////////////////////////
2110 :
2111 : // vfc - view frustum culling
2112 :
2113 0 : int vfc::isfoggedcube(const ivec &o, int size) const
2114 : {
2115 0 : for(int i = 0; i < 4; ++i)
2116 : {
2117 0 : if(o.dist(vfcP[i]) < -vfcDfar[i]*size)
2118 : {
2119 0 : return true;
2120 : }
2121 : }
2122 0 : float dist = o.dist(vfcP[4]);
2123 0 : return dist < -vfcDfar[4]*size || dist > vfcDfog - vfcDnear[4]*size;
2124 : }
2125 :
2126 0 : int vfc::isvisiblecube(const ivec &o, int size) const
2127 : {
2128 0 : int v = ViewFrustumCull_FullyVisible;
2129 : float dist;
2130 :
2131 0 : for(int i = 0; i < 5; ++i)
2132 : {
2133 0 : dist = o.dist(vfcP[i]);
2134 0 : if(dist < -vfcDfar[i]*size)
2135 : {
2136 0 : return ViewFrustumCull_NotVisible;
2137 : }
2138 0 : if(dist < -vfcDnear[i]*size)
2139 : {
2140 0 : v = ViewFrustumCull_PartlyVisible;
2141 : }
2142 : }
2143 :
2144 0 : dist -= vfcDfog;
2145 0 : if(dist > -vfcDnear[4]*size)
2146 : {
2147 0 : return ViewFrustumCull_Fogged;
2148 : }
2149 0 : if(dist > -vfcDfar[4]*size)
2150 : {
2151 0 : v = ViewFrustumCull_PartlyVisible;
2152 : }
2153 :
2154 0 : return v;
2155 : }
2156 :
2157 0 : void vfc::calcvfcD()
2158 : {
2159 0 : for(int i = 0; i < 5; ++i)
2160 : {
2161 0 : plane &p = vfcP[i];
2162 0 : vfcDnear[i] = vfcDfar[i] = 0;
2163 0 : for(int k = 0; k < 3; ++k)
2164 : {
2165 0 : if(p[k] > 0)
2166 : {
2167 0 : vfcDfar[i] += p[k];
2168 : }
2169 : else
2170 : {
2171 0 : vfcDnear[i] += p[k];
2172 : }
2173 : }
2174 : }
2175 0 : }
2176 :
2177 0 : void vfc::visiblecubes(bool cull)
2178 : {
2179 0 : if(cull)
2180 : {
2181 0 : setvfcP();
2182 0 : findvisiblevas();
2183 : }
2184 : else
2185 : {
2186 0 : for(int i = 0; i < 5; ++i)
2187 : {
2188 0 : vfcP[i].x = vfcP[i].y = vfcP[i].z = vfcP[i].offset = 0;
2189 : };
2190 0 : vfcDfog = farplane;
2191 0 : vfcDnear.fill(0);
2192 0 : vfcDfar.fill(0);
2193 0 : visibleva = nullptr;
2194 0 : for(uint i = 0; i < valist.size(); i++)
2195 : {
2196 0 : vtxarray *va = valist[i];
2197 0 : va->distance = 0;
2198 0 : va->curvfc = ViewFrustumCull_FullyVisible;
2199 0 : va->occluded = !va->texs ? Occlude_Geom : Occlude_Nothing;
2200 0 : va->query = nullptr;
2201 0 : va->next = visibleva;
2202 0 : visibleva = va;
2203 : }
2204 : }
2205 0 : }
2206 :
2207 0 : bool vfc::isfoggedsphere(float rad, const vec &cv) const
2208 : {
2209 0 : for(int i = 0; i < 4; ++i)
2210 : {
2211 0 : if(vfcP[i].dist(cv) < -rad)
2212 : {
2213 0 : return true;
2214 : }
2215 : }
2216 0 : float dist = vfcP[4].dist(cv);
2217 0 : return dist < -rad || dist > vfcDfog + rad; // true if abs(dist) is large
2218 : }
2219 :
2220 0 : int vfc::isvisiblesphere(float rad, const vec &cv) const
2221 : {
2222 0 : int v = ViewFrustumCull_FullyVisible;
2223 : float dist;
2224 :
2225 0 : for(int i = 0; i < 5; ++i)
2226 : {
2227 0 : dist = vfcP[i].dist(cv);
2228 0 : if(dist < -rad)
2229 : {
2230 0 : return ViewFrustumCull_NotVisible;
2231 : }
2232 0 : if(dist < rad)
2233 : {
2234 0 : v = ViewFrustumCull_PartlyVisible;
2235 : }
2236 : }
2237 :
2238 0 : dist -= vfcDfog;
2239 0 : if(dist > rad)
2240 : {
2241 0 : return ViewFrustumCull_Fogged; //ViewFrustumCull_NotVisible; // culling when fog is closer than size of world results in HOM
2242 : }
2243 0 : if(dist > -rad)
2244 : {
2245 0 : v = ViewFrustumCull_PartlyVisible;
2246 : }
2247 0 : return v;
2248 : }
2249 :
2250 0 : int vfc::isvisiblebb(const ivec &bo, const ivec &br) const
2251 : {
2252 0 : int v = ViewFrustumCull_FullyVisible;
2253 : float dnear, dfar;
2254 :
2255 0 : for(int i = 0; i < 5; ++i)
2256 : {
2257 0 : const plane &p = vfcP[i];
2258 0 : dnear = dfar = bo.dist(p);
2259 0 : if(p.x > 0)
2260 : {
2261 0 : dfar += p.x*br.x;
2262 : }
2263 : else
2264 : {
2265 0 : dnear += p.x*br.x;
2266 : }
2267 0 : if(p.y > 0)
2268 : {
2269 0 : dfar += p.y*br.y;
2270 : }
2271 : else
2272 : {
2273 0 : dnear += p.y*br.y;
2274 : }
2275 0 : if(p.z > 0)
2276 : {
2277 0 : dfar += p.z*br.z;
2278 : }
2279 : else
2280 : {
2281 0 : dnear += p.z*br.z;
2282 : }
2283 0 : if(dfar < 0)
2284 : {
2285 0 : return ViewFrustumCull_NotVisible;
2286 : }
2287 0 : if(dnear < 0)
2288 : {
2289 0 : v = ViewFrustumCull_PartlyVisible;
2290 : }
2291 : }
2292 :
2293 0 : if(dnear > vfcDfog)
2294 : {
2295 0 : return ViewFrustumCull_Fogged;
2296 : }
2297 0 : if(dfar > vfcDfog)
2298 : {
2299 0 : v = ViewFrustumCull_PartlyVisible;
2300 : }
2301 0 : return v;
2302 : }
2303 :
2304 0 : bool cubeworld::bboccluded(const ivec &bo, const ivec &br) const
2305 : {
2306 0 : int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z);
2307 0 : if(diff&~((1<<worldscale)-1))
2308 : {
2309 0 : return false;
2310 : }
2311 0 : int scale = worldscale-1;
2312 0 : if(diff&(1<<scale))
2313 : {
2314 0 : return ::bboccluded(bo, br, *worldroot, ivec(0, 0, 0), 1<<scale);
2315 : }
2316 0 : const cube *c = &(*worldroot)[OCTA_STEP(bo.x, bo.y, bo.z, scale)];
2317 0 : if(c->ext && c->ext->va)
2318 : {
2319 0 : vtxarray *va = c->ext->va;
2320 0 : if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, *va)))
2321 : {
2322 0 : return true;
2323 : }
2324 : }
2325 0 : scale--;
2326 0 : while(c->children && !(diff&(1<<scale)))
2327 : {
2328 0 : c = &(*c->children)[OCTA_STEP(bo.x, bo.y, bo.z, scale)];
2329 0 : if(c->ext && c->ext->va)
2330 : {
2331 0 : vtxarray *va = c->ext->va;
2332 0 : if(va->curvfc >= ViewFrustumCull_Fogged || (va->occluded >= Occlude_BB && bbinsideva(bo, br, *va)))
2333 : {
2334 0 : return true;
2335 : }
2336 : }
2337 0 : scale--;
2338 : }
2339 0 : if(c->children)
2340 : {
2341 0 : return ::bboccluded(bo, br, *(c->children), ivec(bo).mask(~((2<<scale)-1)), 1<<scale);
2342 : }
2343 0 : return false;
2344 : }
2345 :
2346 0 : void startbb(bool mask)
2347 : {
2348 0 : setupbb();
2349 0 : gle::bindvbo(bbvbo);
2350 0 : gle::bindebo(bbebo);
2351 0 : gle::vertexpointer(sizeof(vec), (const vec *)0);
2352 0 : gle::enablevertex();
2353 0 : SETSHADER(bbquery,);
2354 0 : if(mask)
2355 : {
2356 0 : glDepthMask(GL_FALSE);
2357 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2358 : }
2359 0 : }
2360 :
2361 0 : void endbb(bool mask)
2362 : {
2363 0 : gle::disablevertex();
2364 0 : gle::clearvbo();
2365 0 : gle::clearebo();
2366 0 : if(mask)
2367 : {
2368 0 : glDepthMask(GL_TRUE);
2369 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2370 : }
2371 0 : }
2372 :
2373 0 : void drawbb(const ivec &bo, const ivec &br)
2374 : {
2375 0 : LOCALPARAMF(bborigin, bo.x, bo.y, bo.z);
2376 0 : LOCALPARAMF(bbsize, br.x, br.y, br.z);
2377 0 : glDrawRangeElements(GL_TRIANGLES, 0, 8-1, 3*2*6, GL_UNSIGNED_SHORT, (ushort *)0);
2378 0 : xtraverts += 8;
2379 0 : }
2380 :
2381 0 : void vfc::setvfcP(const vec &bbmin, const vec &bbmax)
2382 : {
2383 0 : vec4<float> px = camprojmatrix.rowx(),
2384 0 : py = camprojmatrix.rowy(),
2385 0 : pz = camprojmatrix.rowz(),
2386 0 : pw = camprojmatrix.roww();
2387 0 : vfcP[0] = plane(vec4<float>(pw).mul(-bbmin.x).add(px)).normalize(); // left plane
2388 0 : vfcP[1] = plane(vec4<float>(pw).mul(bbmax.x).sub(px)).normalize(); // right plane
2389 0 : vfcP[2] = plane(vec4<float>(pw).mul(-bbmin.y).add(py)).normalize(); // bottom plane
2390 0 : vfcP[3] = plane(vec4<float>(pw).mul(bbmax.y).sub(py)).normalize(); // top plane
2391 0 : vfcP[4] = plane(vec4<float>(pw).add(pz)).normalize(); // near/far planes
2392 :
2393 0 : vfcDfog = std::min(calcfogcull(), static_cast<float>(farplane));
2394 0 : view.calcvfcD();
2395 0 : }
2396 :
2397 : //oq
2398 :
2399 0 : void Occluder::clearqueries()
2400 : {
2401 0 : for(queryframe &i : queryframes)
2402 : {
2403 0 : i.cleanup();
2404 : }
2405 0 : }
2406 :
2407 0 : void Occluder::flipqueries()
2408 : {
2409 0 : flipquery = (flipquery + 1) % maxqueryframes;
2410 0 : queryframes[flipquery].flip();
2411 0 : }
2412 :
2413 0 : void Occluder::endquery()
2414 : {
2415 0 : glEndQuery(querytarget());
2416 0 : }
2417 :
2418 0 : bool Occluder::checkquery(occludequery *query, bool nowait)
2419 : {
2420 0 : if(query->fragments < 0)
2421 : {
2422 0 : if(nowait || !oqwait)
2423 : {
2424 : GLint avail;
2425 0 : glGetQueryObjectiv(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
2426 0 : if(!avail)
2427 : {
2428 0 : return false;
2429 : }
2430 : }
2431 :
2432 : GLuint fragments;
2433 0 : glGetQueryObjectuiv(query->id, GL_QUERY_RESULT, &fragments);
2434 0 : query->fragments = querytarget() == GL_SAMPLES_PASSED || !fragments ? static_cast<int>(fragments) : oqfrags;
2435 : }
2436 0 : return query->fragments < oqfrags;
2437 : }
2438 :
2439 0 : void Occluder::resetqueries()
2440 : {
2441 0 : for(queryframe &i : queryframes)
2442 : {
2443 0 : i.reset();
2444 : }
2445 0 : }
2446 :
2447 1 : int Occluder::getnumqueries() const
2448 : {
2449 1 : return queryframes[flipquery].cur;
2450 : }
2451 :
2452 0 : void Occluder::queryframe::flip()
2453 : {
2454 0 : for(int i = 0; i < cur; ++i)
2455 : {
2456 0 : queries[i].owner = nullptr;
2457 : }
2458 0 : for(; defer > 0 && max < maxquery; defer--)
2459 : {
2460 0 : queries[max].owner = nullptr;
2461 0 : queries[max].fragments = -1;
2462 0 : glGenQueries(1, &queries[max++].id);
2463 : }
2464 0 : cur = defer = 0;
2465 0 : }
2466 :
2467 0 : occludequery *Occluder::queryframe::newquery(const void *owner)
2468 : {
2469 0 : if(cur >= max)
2470 : {
2471 0 : if(max >= maxquery)
2472 : {
2473 0 : return nullptr;
2474 : }
2475 0 : if(deferquery)
2476 : {
2477 0 : if(max + defer < maxquery)
2478 : {
2479 0 : defer++;
2480 : }
2481 0 : return nullptr;
2482 : }
2483 0 : glGenQueries(1, &queries[max++].id);
2484 : }
2485 0 : occludequery *query = &queries[cur++];
2486 0 : query->owner = owner;
2487 0 : query->fragments = -1;
2488 0 : return query;
2489 : }
2490 :
2491 0 : void Occluder::queryframe::reset()
2492 : {
2493 0 : for(int i = 0; i < max; ++i)
2494 : {
2495 0 : queries[i].owner = nullptr;
2496 : }
2497 0 : }
2498 :
2499 0 : void Occluder::queryframe::cleanup()
2500 : {
2501 0 : for(int i = 0; i < max; ++i)
2502 : {
2503 0 : glDeleteQueries(1, &queries[i].id);
2504 0 : queries[i].owner = nullptr;
2505 : }
2506 0 : cur = max = defer = 0;
2507 0 : }
2508 :
2509 0 : void occludequery::startquery() const
2510 : {
2511 0 : glBeginQuery(querytarget(), this->id);
2512 0 : }
2513 :
2514 0 : void rendermapmodels()
2515 : {
2516 : static int skipoq = 0;
2517 0 : bool doquery = !drawtex && oqfrags && oqmm;
2518 0 : const std::vector<extentity *> &ents = entities::getents();
2519 0 : findvisiblemms(ents, doquery);
2520 :
2521 0 : for(octaentities *oe = visiblemms; oe; oe = oe->next)
2522 : {
2523 0 : if(oe->distance>=0)
2524 : {
2525 0 : bool rendered = false;
2526 0 : for(uint i = 0; i < oe->mapmodels.size(); i++)
2527 : {
2528 0 : extentity &e = *ents[oe->mapmodels[i]];
2529 0 : if(!(e.flags&EntFlag_Render))
2530 : {
2531 0 : continue;
2532 : }
2533 0 : if(!rendered)
2534 : {
2535 0 : rendered = true;
2536 0 : oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? occlusionengine.newquery(oe) : nullptr;
2537 0 : if(oe->query)
2538 : {
2539 0 : occlusionengine.setupmodelquery(oe->query);
2540 : }
2541 : }
2542 0 : rendermapmodel(e);
2543 0 : e.flags &= ~EntFlag_Render;
2544 : }
2545 0 : if(rendered && oe->query)
2546 : {
2547 0 : occlusionengine.endmodelquery();
2548 : }
2549 : }
2550 : }
2551 0 : rendermapmodelbatches();
2552 0 : clearbatchedmapmodels();
2553 :
2554 0 : bool queried = false;
2555 0 : for(octaentities *oe = visiblemms; oe; oe = oe->next)
2556 : {
2557 0 : if(oe->distance<0)
2558 : {
2559 0 : oe->query = doquery && !camera1->o.insidebb(oe->bbmin, oe->bbmax, 1) ? occlusionengine.newquery(oe) : nullptr;
2560 0 : if(!oe->query)
2561 : {
2562 0 : continue;
2563 : }
2564 0 : if(!queried)
2565 : {
2566 0 : startbb();
2567 0 : queried = true;
2568 : }
2569 0 : oe->query->startquery();
2570 0 : drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin));
2571 0 : occlusionengine.endquery();
2572 : }
2573 : }
2574 0 : if(queried)
2575 : {
2576 0 : endbb();
2577 : }
2578 0 : }
2579 :
2580 0 : void renderoutline()
2581 : {
2582 0 : ldrnotextureshader->set();
2583 :
2584 0 : gle::enablevertex();
2585 :
2586 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2587 0 : gle::color(outlinecolor);
2588 :
2589 0 : enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
2590 :
2591 0 : if(!dtoutline)
2592 : {
2593 0 : glDisable(GL_DEPTH_TEST);
2594 : }
2595 0 : vtxarray *prev = nullptr;
2596 0 : for(vtxarray *va = visibleva; va; va = va->next)
2597 : {
2598 0 : if(va->occluded < Occlude_BB)
2599 : {
2600 0 : if((!va->texs || va->occluded >= Occlude_Geom) && !va->alphaback && !va->alphafront && !va->refracttris)
2601 : {
2602 0 : continue;
2603 : }
2604 0 : if(!prev || va->vbuf != prev->vbuf)
2605 : {
2606 0 : gle::bindvbo(va->vbuf);
2607 0 : gle::bindebo(va->ebuf);
2608 0 : const vertex *ptr = 0;
2609 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data());
2610 : }
2611 0 : if(va->texs && va->occluded < Occlude_Geom)
2612 : {
2613 0 : drawvatris(*va, 3*va->tris, 0);
2614 0 : xtravertsva += va->verts;
2615 : }
2616 0 : if(va->alphaback || va->alphafront || va->refract)
2617 : {
2618 0 : drawvatris(*va, 3*(va->alphabacktris + va->alphafronttris + va->refracttris), 3*(va->tris));
2619 0 : xtravertsva += 3*(va->alphabacktris + va->alphafronttris + va->refracttris);
2620 : }
2621 0 : prev = va;
2622 : }
2623 : }
2624 0 : if(!dtoutline)
2625 : {
2626 0 : glEnable(GL_DEPTH_TEST);
2627 : }
2628 0 : disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
2629 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2630 0 : gle::clearvbo();
2631 0 : gle::clearebo();
2632 0 : gle::disablevertex();
2633 0 : }
2634 :
2635 0 : bool renderexplicitsky(bool outline)
2636 : {
2637 0 : vtxarray *prev = nullptr;
2638 0 : for(vtxarray *va = visibleva; va; va = va->next)
2639 : {
2640 0 : if(va->sky && va->occluded < Occlude_BB &&
2641 0 : ((va->skymax.x >= 0 && view.isvisiblebb(va->skymin, ivec(va->skymax).sub(va->skymin)) != ViewFrustumCull_NotVisible) ||
2642 0 : !insideworld(camera1->o)))
2643 : {
2644 0 : if(!prev || va->vbuf != prev->vbuf)
2645 : {
2646 0 : if(!prev)
2647 : {
2648 0 : gle::enablevertex();
2649 0 : if(outline)
2650 : {
2651 0 : ldrnotextureshader->set();
2652 0 : gle::color(explicitskycolor);
2653 0 : glDepthMask(GL_FALSE);
2654 0 : enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
2655 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2656 : }
2657 0 : else if(editmode)
2658 : {
2659 0 : maskgbuffer("d");
2660 0 : SETSHADER(depth,);
2661 : }
2662 : else
2663 : {
2664 0 : nocolorshader->set();
2665 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2666 : }
2667 : }
2668 0 : gle::bindvbo(va->vbuf);
2669 0 : gle::bindebo(va->skybuf);
2670 0 : const vertex *ptr = 0;
2671 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data());
2672 : }
2673 0 : drawvaskytris(*va);
2674 0 : xtraverts += va->sky;
2675 0 : prev = va;
2676 : }
2677 : }
2678 0 : if(!prev)
2679 : {
2680 0 : return false;
2681 : }
2682 0 : if(outline)
2683 : {
2684 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2685 0 : disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
2686 0 : glDepthMask(GL_TRUE);
2687 : }
2688 0 : else if(editmode)
2689 : {
2690 0 : maskgbuffer("cnd");
2691 : }
2692 : else
2693 : {
2694 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2695 : }
2696 0 : gle::disablevertex();
2697 0 : gle::clearvbo();
2698 0 : gle::clearebo();
2699 0 : return true;
2700 : }
2701 :
2702 0 : void cubeworld::cleanupva()
2703 : {
2704 0 : clearvas(*worldroot);
2705 0 : occlusionengine.clearqueries();
2706 0 : cleanupbb();
2707 0 : cleanupgrass();
2708 0 : }
2709 :
2710 0 : GBuffer::AlphaInfo GBuffer::findalphavas()
2711 : {
2712 0 : alphavas.clear();
2713 : AlphaInfo a;
2714 0 : a.alphafrontsx1 = a.alphafrontsy1 = a.alphabacksx1 = a.alphabacksy1 = a.alpharefractsx1 = a.alpharefractsy1 = 1;
2715 0 : a.alphafrontsx2 = a.alphafrontsy2 = a.alphabacksx2 = a.alphabacksy2 = a.alpharefractsx2 = a.alpharefractsy2 = -1;
2716 0 : int alphabackvas = 0,
2717 0 : alpharefractvas = 0;
2718 0 : std::memset(alphatiles, 0, sizeof(alphatiles));
2719 0 : for(vtxarray *va = visibleva; va; va = va->next)
2720 : {
2721 0 : if(va->alphabacktris || va->alphafronttris || va->refracttris)
2722 : {
2723 0 : if(va->occluded >= Occlude_BB)
2724 : {
2725 0 : continue;
2726 : }
2727 0 : if(va->curvfc==ViewFrustumCull_Fogged)
2728 : {
2729 0 : continue;
2730 : }
2731 0 : float sx1 = -1,
2732 0 : sx2 = 1,
2733 0 : sy1 = -1,
2734 0 : sy2 = 1;
2735 0 : if(!calcbbscissor(va->alphamin, va->alphamax, sx1, sy1, sx2, sy2))
2736 : {
2737 0 : continue;
2738 : }
2739 0 : alphavas.push_back(va);
2740 0 : masktiles(alphatiles, sx1, sy1, sx2, sy2);
2741 0 : a.alphafrontsx1 = std::min(a.alphafrontsx1, sx1);
2742 0 : a.alphafrontsy1 = std::min(a.alphafrontsy1, sy1);
2743 0 : a.alphafrontsx2 = std::max(a.alphafrontsx2, sx2);
2744 0 : a.alphafrontsy2 = std::max(a.alphafrontsy2, sy2);
2745 0 : if(va->alphabacktris)
2746 : {
2747 0 : alphabackvas++;
2748 0 : a.alphabacksx1 = std::min(a.alphabacksx1, sx1);
2749 0 : a.alphabacksy1 = std::min(a.alphabacksy1, sy1);
2750 0 : a.alphabacksx2 = std::max(a.alphabacksx2, sx2);
2751 0 : a.alphabacksy2 = std::max(a.alphabacksy2, sy2);
2752 : }
2753 0 : if(va->refracttris)
2754 : {
2755 0 : if(!calcbbscissor(va->refractmin, va->refractmax, sx1, sy1, sx2, sy2))
2756 : {
2757 0 : continue;
2758 : }
2759 0 : alpharefractvas++;
2760 0 : a.alpharefractsx1 = std::min(a.alpharefractsx1, sx1);
2761 0 : a.alpharefractsy1 = std::min(a.alpharefractsy1, sy1);
2762 0 : a.alpharefractsx2 = std::max(a.alpharefractsx2, sx2);
2763 0 : a.alpharefractsy2 = std::max(a.alpharefractsy2, sy2);
2764 : }
2765 : }
2766 : }
2767 0 : a.hasalphavas = (alpharefractvas ? 4 : 0) | (alphavas.size() ? 2 : 0) | (alphabackvas ? 1 : 0);
2768 0 : return a;
2769 : }
2770 :
2771 0 : void renderrefractmask()
2772 : {
2773 0 : gle::enablevertex();
2774 :
2775 0 : const vtxarray *prev = nullptr;
2776 0 : for(const vtxarray *va : alphavas)
2777 : {
2778 0 : if(!va->refracttris)
2779 : {
2780 0 : continue;
2781 : }
2782 0 : if(!prev || va->vbuf != prev->vbuf)
2783 : {
2784 0 : gle::bindvbo(va->vbuf);
2785 0 : gle::bindebo(va->ebuf);
2786 0 : const vertex *ptr = 0;
2787 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data());
2788 : }
2789 0 : drawvatris(*va, 3*va->refracttris, 3*(va->tris + va->alphabacktris + va->alphafronttris));
2790 0 : xtravertsva += 3*va->refracttris;
2791 0 : prev = va;
2792 : }
2793 :
2794 0 : gle::clearvbo();
2795 0 : gle::clearebo();
2796 0 : gle::disablevertex();
2797 0 : }
2798 :
2799 0 : void renderalphageom(int side)
2800 : {
2801 0 : resetbatches();
2802 :
2803 0 : renderstate cur;
2804 0 : cur.alphaing = side;
2805 0 : cur.invalidatealphascale();
2806 :
2807 0 : setupgeom();
2808 :
2809 0 : if(side == 2)
2810 : {
2811 0 : for(const vtxarray *i : alphavas)
2812 : {
2813 0 : renderva(cur, *i, RenderPass_GBuffer);
2814 : }
2815 0 : if(geombatches.size())
2816 : {
2817 0 : cur.renderbatches(RenderPass_GBuffer);
2818 : }
2819 : }
2820 : else
2821 : {
2822 0 : glCullFace(GL_FRONT);
2823 0 : for(const vtxarray *i : alphavas)
2824 : {
2825 0 : if(i->alphabacktris)
2826 : {
2827 0 : renderva(cur, *i, RenderPass_GBuffer);
2828 : }
2829 : }
2830 0 : if(geombatches.size())
2831 : {
2832 0 : cur.renderbatches(RenderPass_GBuffer);
2833 : }
2834 0 : glCullFace(GL_BACK);
2835 : }
2836 :
2837 0 : cur.cleanupgeom();
2838 0 : }
2839 :
2840 0 : void GBuffer::rendergeom()
2841 : {
2842 0 : bool doOQ = oqfrags && oqgeom && !drawtex,
2843 0 : multipassing = false;
2844 0 : renderstate cur;
2845 :
2846 0 : if(doOQ)
2847 : {
2848 0 : for(vtxarray *va = visibleva; va; va = va->next)
2849 : {
2850 0 : if(va->texs)
2851 : {
2852 0 : if(!camera1->o.insidebb(va->o, va->size, 2))
2853 : {
2854 0 : if(va->parent && va->parent->occluded >= Occlude_BB)
2855 : {
2856 0 : va->query = nullptr;
2857 0 : va->occluded = Occlude_Parent;
2858 0 : continue;
2859 : }
2860 0 : va->occluded = va->query && va->query->owner == va && occlusionengine.checkquery(va->query) ?
2861 0 : std::min(va->occluded+1, static_cast<int>(Occlude_BB)) :
2862 : Occlude_Nothing;
2863 0 : va->query = occlusionengine.newquery(va);
2864 0 : if(!va->query || !va->occluded)
2865 : {
2866 0 : va->occluded = Occlude_Nothing;
2867 : }
2868 0 : if(va->occluded >= Occlude_Geom)
2869 : {
2870 0 : if(va->query)
2871 : {
2872 0 : if(cur.vattribs)
2873 : {
2874 0 : cur.disablevattribs(false);
2875 : }
2876 0 : if(cur.vbuf)
2877 : {
2878 0 : cur.disablevbuf();
2879 : }
2880 0 : renderquery(cur, *va->query, *va);
2881 : }
2882 0 : continue;
2883 : }
2884 : }
2885 : else
2886 : {
2887 0 : va->query = nullptr;
2888 0 : va->occluded = Occlude_Nothing;
2889 0 : if(va->occluded >= Occlude_Geom)
2890 : {
2891 0 : continue;
2892 : }
2893 : }
2894 0 : renderva(cur, *va, RenderPass_Z, true);
2895 : }
2896 : }
2897 :
2898 0 : if(cur.vquery)
2899 : {
2900 0 : cur.disablevquery();
2901 : }
2902 0 : if(cur.vattribs)
2903 : {
2904 0 : cur.disablevattribs(false);
2905 : }
2906 0 : if(cur.vbuf)
2907 : {
2908 0 : cur.disablevbuf();
2909 : }
2910 0 : glFlush();
2911 0 : if(cur.colormask)
2912 : {
2913 0 : cur.colormask = false;
2914 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2915 : }
2916 0 : if(cur.depthmask)
2917 : {
2918 0 : cur.depthmask = false;
2919 0 : glDepthMask(GL_FALSE);
2920 : }
2921 0 : workinoq();
2922 0 : if(!cur.colormask)
2923 : {
2924 0 : cur.colormask = true;
2925 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2926 : }
2927 0 : if(!cur.depthmask)
2928 : {
2929 0 : cur.depthmask = true;
2930 0 : glDepthMask(GL_TRUE);
2931 : }
2932 0 : if(!multipassing)
2933 : {
2934 0 : multipassing = true;
2935 0 : glDepthFunc(GL_LEQUAL);
2936 : }
2937 0 : cur.invalidatetexgenorient();
2938 0 : setupgeom();
2939 0 : resetbatches();
2940 0 : for(vtxarray *va = visibleva; va; va = va->next)
2941 : {
2942 0 : if(va->texs && va->occluded < Occlude_Geom)
2943 : {
2944 0 : renderva(cur, *va, RenderPass_GBuffer);
2945 : }
2946 : }
2947 0 : if(geombatches.size())
2948 : {
2949 0 : cur.renderbatches(RenderPass_GBuffer);
2950 0 : glFlush();
2951 : }
2952 0 : for(vtxarray *va = visibleva; va; va = va->next)
2953 : {
2954 0 : if(va->texs && va->occluded >= Occlude_Geom)
2955 : {
2956 0 : if((va->parent && va->parent->occluded >= Occlude_BB) || (va->query && occlusionengine.checkquery(va->query)))
2957 : {
2958 0 : va->occluded = Occlude_BB;
2959 0 : continue;
2960 : }
2961 : else
2962 : {
2963 0 : va->occluded = Occlude_Nothing;
2964 0 : if(va->occluded >= Occlude_Geom)
2965 : {
2966 0 : continue;
2967 : }
2968 : }
2969 :
2970 0 : renderva(cur, *va, RenderPass_GBuffer);
2971 : }
2972 : }
2973 0 : if(geombatches.size())
2974 : {
2975 0 : cur.renderbatches(RenderPass_GBuffer);
2976 : }
2977 : }
2978 : else
2979 : {
2980 0 : setupgeom();
2981 0 : resetbatches();
2982 0 : for(vtxarray *va = visibleva; va; va = va->next)
2983 : {
2984 0 : if(va->texs)
2985 : {
2986 0 : va->query = nullptr;
2987 0 : va->occluded = Occlude_Nothing;
2988 0 : if(va->occluded >= Occlude_Geom)
2989 : {
2990 0 : continue;
2991 : }
2992 0 : renderva(cur, *va, RenderPass_GBuffer);
2993 : }
2994 : }
2995 0 : if(geombatches.size())
2996 : {
2997 0 : cur.renderbatches(RenderPass_GBuffer);
2998 : }
2999 : }
3000 0 : if(multipassing)
3001 : {
3002 0 : glDepthFunc(GL_LESS);
3003 : }
3004 0 : cur.cleanupgeom();
3005 0 : if(!doOQ)
3006 : {
3007 0 : glFlush();
3008 0 : if(cur.colormask)
3009 : {
3010 0 : cur.colormask = false;
3011 0 : glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3012 : }
3013 0 : if(cur.depthmask)
3014 : {
3015 0 : cur.depthmask = false;
3016 0 : glDepthMask(GL_FALSE);
3017 : }
3018 0 : workinoq();
3019 0 : if(!cur.colormask)
3020 : {
3021 0 : cur.colormask = true;
3022 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3023 : }
3024 0 : if(!cur.depthmask)
3025 : {
3026 0 : cur.depthmask = true;
3027 0 : glDepthMask(GL_TRUE);
3028 : }
3029 : }
3030 0 : }
3031 :
3032 0 : void renderdecals()
3033 : {
3034 : vtxarray *decalva;
3035 0 : for(decalva = visibleva; decalva; decalva = decalva->next)
3036 : {
3037 0 : if(decalva->decaltris && decalva->occluded < Occlude_BB)
3038 : {
3039 0 : break;
3040 : }
3041 : }
3042 0 : if(!decalva)
3043 : {
3044 0 : return;
3045 : }
3046 0 : decalrenderer cur;
3047 :
3048 0 : setupdecals();
3049 0 : resetdecalbatches();
3050 :
3051 0 : if(maxdualdrawbufs)
3052 : {
3053 0 : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC1_ALPHA);
3054 0 : maskgbuffer("c");
3055 0 : for(vtxarray *va = decalva; va; va = va->next)
3056 : {
3057 0 : if(va->decaltris && va->occluded < Occlude_BB)
3058 : {
3059 0 : mergedecals(*va);
3060 0 : if(!batchdecals && decalbatches.size())
3061 : {
3062 0 : cur.renderdecalbatches(0);
3063 : }
3064 : }
3065 : }
3066 0 : if(decalbatches.size())
3067 : {
3068 0 : cur.renderdecalbatches(0);
3069 : }
3070 0 : if(usepacknorm())
3071 : {
3072 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3073 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
3074 : }
3075 : else
3076 : {
3077 0 : glBlendFunc(GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_ALPHA);
3078 : }
3079 0 : maskgbuffer("n");
3080 0 : cur.vbuf = 0;
3081 0 : for(vtxarray *va = decalva; va; va = va->next)
3082 : {
3083 0 : if(va->decaltris && va->occluded < Occlude_BB)
3084 : {
3085 0 : mergedecals(*va);
3086 0 : if(!batchdecals && decalbatches.size())
3087 : {
3088 0 : cur.renderdecalbatches(1);
3089 : }
3090 : }
3091 : }
3092 0 : if(decalbatches.size())
3093 : {
3094 0 : cur.renderdecalbatches(1);
3095 : }
3096 : }
3097 : else
3098 : {
3099 0 : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3100 0 : glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
3101 0 : maskgbuffer("cn");
3102 0 : for(vtxarray *va = decalva; va; va = va->next)
3103 : {
3104 0 : if(va->decaltris && va->occluded < Occlude_BB)
3105 : {
3106 0 : mergedecals(*va);
3107 0 : if(!batchdecals && decalbatches.size())
3108 : {
3109 0 : cur.renderdecalbatches(0);
3110 : }
3111 : }
3112 : }
3113 0 : if(decalbatches.size())
3114 : {
3115 0 : cur.renderdecalbatches(0);
3116 : }
3117 : }
3118 0 : cleanupdecals();
3119 : }
3120 :
3121 : //shadowmeshes
3122 :
3123 1 : void clearshadowmeshes()
3124 : {
3125 1 : if(shadowvbos.size())
3126 : {
3127 0 : glDeleteBuffers(shadowvbos.size(), shadowvbos.data());
3128 0 : shadowvbos.clear();
3129 : }
3130 1 : if(shadowmeshes.size())
3131 : {
3132 0 : std::vector<extentity *> &ents = entities::getents();
3133 0 : for(uint i = 0; i < ents.size(); i++)
3134 : {
3135 0 : extentity &e = *ents[i];
3136 0 : if(e.flags&EntFlag_ShadowMesh)
3137 : {
3138 0 : e.flags &= ~EntFlag_ShadowMesh;
3139 : }
3140 : }
3141 : }
3142 1 : shadowmeshes.clear();
3143 1 : shadowdraws.clear();
3144 1 : }
3145 :
3146 0 : void genshadowmeshes()
3147 : {
3148 0 : clearshadowmeshes();
3149 :
3150 0 : if(!smmesh)
3151 : {
3152 0 : return;
3153 : }
3154 0 : renderprogress(0, "generating shadow meshes..");
3155 :
3156 0 : std::vector<extentity *> &ents = entities::getents();
3157 0 : for(uint i = 0; i < ents.size(); i++)
3158 : {
3159 0 : extentity &e = *ents[i];
3160 0 : if(e.type != EngineEnt_Light)
3161 : {
3162 0 : continue;
3163 : }
3164 0 : genshadowmesh(i, e);
3165 : }
3166 : }
3167 :
3168 0 : shadowmesh *findshadowmesh(int idx, const extentity &e)
3169 : {
3170 0 : auto itr = shadowmeshes.find(idx);
3171 0 : if(itr == shadowmeshes.end()
3172 0 : || (*itr).second.type != shadowmapping
3173 0 : || (*itr).second.origin != shadoworigin
3174 0 : || (*itr).second.radius < shadowradius)
3175 : {
3176 0 : return nullptr;
3177 : }
3178 0 : switch((*itr).second.type)
3179 : {
3180 0 : case ShadowMap_Spot:
3181 : {
3182 0 : if(!e.attached || e.attached->type != EngineEnt_Spotlight || (*itr).second.spotloc != e.attached->o || (*itr).second.spotangle < std::clamp(static_cast<int>(e.attached->attr1), 1, 89))
3183 : {
3184 0 : return nullptr;
3185 : }
3186 0 : break;
3187 : }
3188 : }
3189 0 : return &(*itr).second;
3190 : }
3191 :
3192 0 : void rendershadowmesh(const shadowmesh *m)
3193 : {
3194 0 : int draw = m->draws[shadowside];
3195 0 : if(draw < 0)
3196 : {
3197 0 : return;
3198 : }
3199 0 : SETSHADER(shadowmapworld,);
3200 0 : gle::enablevertex();
3201 0 : GLuint ebuf = 0,
3202 0 : vbuf = 0;
3203 0 : while(draw >= 0)
3204 : {
3205 0 : shadowdraw &d = shadowdraws[draw];
3206 0 : if(ebuf != d.ebuf)
3207 : {
3208 0 : gle::bindebo(d.ebuf);
3209 0 : ebuf = d.ebuf;
3210 : }
3211 0 : if(vbuf != d.vbuf)
3212 : {
3213 0 : gle::bindvbo(d.vbuf);
3214 0 : vbuf = d.vbuf; gle::vertexpointer(sizeof(vec), 0);
3215 : }
3216 0 : drawtris(3*d.tris, (ushort *)0 + d.offset, d.minvert, d.maxvert);
3217 0 : xtravertsva += 3*d.tris;
3218 0 : draw = d.next;
3219 : }
3220 0 : gle::disablevertex();
3221 0 : gle::clearebo();
3222 0 : gle::clearvbo();
3223 : }
3224 :
3225 : //external api functions
3226 0 : int calcspheresidemask(const vec &p, float radius, float bias)
3227 : {
3228 : // p is in the cubemap's local coordinate system
3229 : // bias = border/(size - border)
3230 0 : float dxyp = p.x + p.y,
3231 0 : dxyn = p.x - p.y,
3232 0 : axyp = std::fabs(dxyp),
3233 0 : axyn = std::fabs(dxyn),
3234 0 : dyzp = p.y + p.z,
3235 0 : dyzn = p.y - p.z,
3236 0 : ayzp = std::fabs(dyzp),
3237 0 : ayzn = std::fabs(dyzn),
3238 0 : dzxp = p.z + p.x,
3239 0 : dzxn = p.z - p.x,
3240 0 : azxp = std::fabs(dzxp),
3241 0 : azxn = std::fabs(dzxn);
3242 0 : int mask = 0x3F;
3243 0 : radius *= SQRT2;
3244 0 : if(axyp > bias*axyn + radius)
3245 : {
3246 0 : mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
3247 : }
3248 0 : if(axyn > bias*axyp + radius)
3249 : {
3250 0 : mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
3251 : }
3252 0 : if(ayzp > bias*ayzn + radius)
3253 : {
3254 0 : mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
3255 : }
3256 0 : if(ayzn > bias*ayzp + radius)
3257 : {
3258 0 : mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
3259 : }
3260 0 : if(azxp > bias*azxn + radius)
3261 : {
3262 0 : mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
3263 : }
3264 0 : if(azxn > bias*azxp + radius)
3265 : {
3266 0 : mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
3267 : }
3268 0 : return mask;
3269 : }
3270 :
3271 0 : int vfc::cullfrustumsides(const vec &lightpos, float lightradius, float size, float border)
3272 : {
3273 0 : int sides = 0x3F,
3274 0 : masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
3275 0 : float scale = (size - 2*border)/size,
3276 0 : bias = border / static_cast<float>(size - border);
3277 : // check if cone enclosing side would cross frustum plane
3278 0 : scale = 2 / (scale*scale + 2);
3279 0 : for(int i = 0; i < 5; ++i)
3280 : {
3281 0 : if(vfcP[i].dist(lightpos) <= -0.03125f)
3282 : {
3283 0 : vec n = vec(vfcP[i]).div(lightradius);
3284 0 : float len = scale*n.squaredlen();
3285 0 : if(n.x*n.x > len)
3286 : {
3287 0 : sides &= n.x < 0 ? ~(1<<0) : ~(2 << 0);
3288 : }
3289 0 : if(n.y*n.y > len)
3290 : {
3291 0 : sides &= n.y < 0 ? ~(1<<2) : ~(2 << 2);
3292 : }
3293 0 : if(n.z*n.z > len)
3294 : {
3295 0 : sides &= n.z < 0 ? ~(1<<4) : ~(2 << 4);
3296 : }
3297 : }
3298 : }
3299 0 : if (vfcP[4].dist(lightpos) >= vfcDfog + 0.03125f)
3300 : {
3301 0 : vec n = vec(vfcP[4]).div(lightradius);
3302 0 : float len = scale*n.squaredlen();
3303 0 : if(n.x*n.x > len)
3304 : {
3305 0 : sides &= n.x >= 0 ? ~(1<<0) : ~(2 << 0);
3306 : }
3307 0 : if(n.y*n.y > len)
3308 : {
3309 0 : sides &= n.y >= 0 ? ~(1<<2) : ~(2 << 2);
3310 : }
3311 0 : if(n.z*n.z > len)
3312 : {
3313 0 : sides &= n.z >= 0 ? ~(1<<4) : ~(2 << 4);
3314 : }
3315 : }
3316 : // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
3317 : // check if frustum corners/origin cross plane sides
3318 : // infinite version, assumes frustum corners merely give direction and extend to infinite distance
3319 0 : vec p = vec(camera1->o).sub(lightpos).div(lightradius);
3320 0 : float dp = p.x + p.y,
3321 0 : dn = p.x - p.y,
3322 0 : ap = std::fabs(dp),
3323 0 : an = std::fabs(dn);
3324 0 : masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
3325 0 : masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
3326 0 : dp = p.y + p.z, dn = p.y - p.z,
3327 0 : ap = std::fabs(dp),
3328 0 : an = std::fabs(dn);
3329 0 : masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
3330 0 : masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
3331 0 : dp = p.z + p.x,
3332 0 : dn = p.z - p.x,
3333 0 : ap = std::fabs(dp),
3334 0 : an = std::fabs(dn);
3335 0 : masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
3336 0 : masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
3337 0 : for(int i = 0; i < 4; ++i)
3338 : {
3339 0 : vec n;
3340 0 : switch(i)
3341 : {
3342 0 : case 0:
3343 : {
3344 0 : n.cross(vfcP[0], vfcP[2]);
3345 0 : break;
3346 : }
3347 0 : case 1:
3348 : {
3349 0 : n.cross(vfcP[3], vfcP[0]);
3350 0 : break;
3351 : }
3352 0 : case 2:
3353 : {
3354 0 : n.cross(vfcP[2], vfcP[1]);
3355 0 : break;
3356 : }
3357 0 : case 3:
3358 : {
3359 0 : n.cross(vfcP[1], vfcP[3]);
3360 0 : break;
3361 : }
3362 : }
3363 0 : dp = n.x + n.y,
3364 0 : dn = n.x - n.y,
3365 0 : ap = std::fabs(dp),
3366 0 : an = std::fabs(dn);
3367 0 : if(ap > 0)
3368 : {
3369 0 : masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
3370 : }
3371 0 : if(an > 0)
3372 : {
3373 0 : masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
3374 : }
3375 0 : dp = n.y + n.z,
3376 0 : dn = n.y - n.z,
3377 0 : ap = std::fabs(dp),
3378 0 : an = std::fabs(dn);
3379 0 : if(ap > 0)
3380 : {
3381 0 : masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
3382 : }
3383 0 : if(an > 0)
3384 : {
3385 0 : masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
3386 : }
3387 0 : dp = n.z + n.x,
3388 0 : dn = n.z - n.x,
3389 0 : ap = std::fabs(dp),
3390 0 : an = std::fabs(dn);
3391 0 : if(ap > 0)
3392 : {
3393 0 : masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
3394 : }
3395 0 : if(an > 0)
3396 : {
3397 0 : masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
3398 : }
3399 : }
3400 0 : return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
3401 : }
3402 :
3403 0 : static void findshadowvas(std::vector<vtxarray *> &vas, std::array<vtxarray *, vasortsize> &vasort)
3404 : {
3405 0 : for(vtxarray *&v : vas)
3406 : {
3407 0 : float dist = vadist(*v, shadoworigin);
3408 0 : if(dist < shadowradius || !smdistcull)
3409 : {
3410 0 : v->shadowmask = !smbbcull ? 0x3F : (v->children.size() || v->mapmodels.size() ?
3411 0 : calcbbsidemask(v->bbmin, v->bbmax, shadoworigin, shadowradius, shadowbias) :
3412 0 : calcbbsidemask(v->geommin, v->geommax, shadoworigin, shadowradius, shadowbias));
3413 0 : addshadowva(v, dist, vasort);
3414 0 : if(v->children.size())
3415 : {
3416 0 : findshadowvas(v->children, vasort);
3417 : }
3418 : }
3419 : }
3420 0 : }
3421 :
3422 0 : void renderrsmgeom(bool dyntex)
3423 : {
3424 0 : renderstate cur;
3425 0 : if(!dyntex)
3426 : {
3427 0 : cur.cleartexgenmillis();
3428 : }
3429 0 : setupgeom();
3430 0 : if(skyshadow)
3431 : {
3432 0 : cur.enablevattribs(false);
3433 0 : SETSHADER(rsmsky,);
3434 0 : vtxarray *prev = nullptr;
3435 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3436 : {
3437 0 : if(va->sky)
3438 : {
3439 0 : if(!prev || va->vbuf != prev->vbuf)
3440 : {
3441 0 : gle::bindvbo(va->vbuf);
3442 0 : gle::bindebo(va->skybuf);
3443 0 : const vertex *ptr = nullptr; //note: offset of nullptr is technically UB
3444 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data());
3445 : }
3446 0 : drawvaskytris(*va);
3447 0 : xtravertsva += va->sky/3;
3448 0 : prev = va;
3449 : }
3450 : }
3451 0 : if(cur.vattribs)
3452 : {
3453 0 : cur.disablevattribs(false);
3454 : }
3455 : }
3456 0 : resetbatches();
3457 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3458 : {
3459 0 : if(va->texs)
3460 : {
3461 0 : renderva(cur, *va, RenderPass_ReflectiveShadowMap);
3462 : }
3463 : }
3464 0 : if(geombatches.size())
3465 : {
3466 0 : cur.renderbatches(RenderPass_ReflectiveShadowMap);
3467 : }
3468 0 : cur.cleanupgeom();
3469 0 : }
3470 :
3471 0 : void dynamicshadowvabounds(int mask, vec &bbmin, vec &bbmax)
3472 : {
3473 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3474 : {
3475 0 : if(va->shadowmask&mask && va->dyntexs)
3476 : {
3477 0 : bbmin.min(vec(va->geommin));
3478 0 : bbmax.max(vec(va->geommax));
3479 : }
3480 : }
3481 0 : }
3482 :
3483 0 : void findshadowmms()
3484 : {
3485 0 : shadowmms = nullptr;
3486 0 : octaentities **lastmms = &shadowmms;
3487 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3488 : {
3489 0 : for(uint j = 0; j < va->mapmodels.size(); j++)
3490 : {
3491 0 : octaentities *oe = va->mapmodels[j];
3492 0 : switch(shadowmapping)
3493 : {
3494 0 : case ShadowMap_Reflect:
3495 : {
3496 0 : break;
3497 : }
3498 0 : case ShadowMap_Cascade:
3499 : {
3500 0 : if(!csm.calcbbcsmsplits(oe->bbmin, oe->bbmax))
3501 : {
3502 0 : continue;
3503 : }
3504 0 : break;
3505 : }
3506 0 : case ShadowMap_CubeMap:
3507 : {
3508 0 : if(smdistcull && shadoworigin.dist_to_bb(oe->bbmin, oe->bbmax) >= shadowradius)
3509 : {
3510 0 : continue;
3511 : }
3512 0 : break;
3513 : }
3514 0 : case ShadowMap_Spot:
3515 : {
3516 0 : if(smdistcull && shadoworigin.dist_to_bb(oe->bbmin, oe->bbmax) >= shadowradius)
3517 : {
3518 0 : continue;
3519 : }
3520 0 : if(smbbcull && !bbinsidespot(shadoworigin, shadowdir, shadowspot, oe->bbmin, oe->bbmax))
3521 : {
3522 0 : continue;
3523 : }
3524 0 : break;
3525 : }
3526 : }
3527 0 : oe->rnext = nullptr;
3528 0 : *lastmms = oe;
3529 0 : lastmms = &oe->rnext;
3530 : }
3531 : }
3532 0 : }
3533 :
3534 0 : void rendershadowmapworld()
3535 : {
3536 0 : SETSHADER(shadowmapworld,);
3537 :
3538 0 : gle::enablevertex();
3539 :
3540 0 : vtxarray *prev = nullptr;
3541 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3542 : {
3543 0 : if(va->tris && va->shadowmask&(1<<shadowside))
3544 : {
3545 0 : if(!prev || va->vbuf != prev->vbuf)
3546 : {
3547 0 : gle::bindvbo(va->vbuf);
3548 0 : gle::bindebo(va->ebuf);
3549 0 : const vertex *ptr = 0;
3550 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data());
3551 : }
3552 0 : if(!smnodraw)
3553 : {
3554 0 : drawvatris(*va, 3*va->tris, 0);
3555 : }
3556 0 : xtravertsva += va->verts;
3557 0 : prev = va;
3558 : }
3559 : }
3560 0 : if(skyshadow)
3561 : {
3562 0 : prev = nullptr;
3563 0 : for(vtxarray *va = shadowva; va; va = va->rnext)
3564 : {
3565 0 : if(va->sky && va->shadowmask&(1<<shadowside))
3566 : {
3567 0 : if(!prev || va->vbuf != prev->vbuf)
3568 : {
3569 0 : gle::bindvbo(va->vbuf);
3570 0 : gle::bindebo(va->skybuf);
3571 0 : const vertex *ptr = 0;
3572 0 : gle::vertexpointer(sizeof(vertex), ptr->pos.data()); //note offset from nullptr
3573 : }
3574 0 : if(!smnodraw)
3575 : {
3576 0 : drawvaskytris(*va);
3577 : }
3578 0 : xtravertsva += va->sky/3;
3579 0 : prev = va;
3580 : }
3581 : }
3582 : }
3583 :
3584 0 : gle::clearvbo();
3585 0 : gle::clearebo();
3586 0 : gle::disablevertex();
3587 0 : }
3588 :
3589 0 : void batchshadowmapmodels(bool skipmesh)
3590 : {
3591 0 : if(!shadowmms)
3592 : {
3593 0 : return;
3594 : }
3595 0 : int nflags = EntFlag_NoVis|EntFlag_NoShadow;
3596 0 : if(skipmesh)
3597 : {
3598 0 : nflags |= EntFlag_ShadowMesh;
3599 : }
3600 0 : const std::vector<extentity *> &ents = entities::getents();
3601 0 : for(octaentities *oe = shadowmms; oe; oe = oe->rnext)
3602 : {
3603 0 : for(const int &k : oe->mapmodels)
3604 : {
3605 0 : extentity &e = *ents[k];
3606 0 : if(e.flags&nflags)
3607 : {
3608 0 : continue;
3609 : }
3610 0 : e.flags |= EntFlag_Render;
3611 : }
3612 : }
3613 0 : for(octaentities *oe = shadowmms; oe; oe = oe->rnext)
3614 : {
3615 0 : for(const int &j : oe->mapmodels)
3616 : {
3617 0 : extentity &e = *ents[j];
3618 0 : if(!(e.flags&EntFlag_Render))
3619 : {
3620 0 : continue;
3621 : }
3622 0 : rendermapmodel(e);
3623 0 : e.flags &= ~EntFlag_Render;
3624 : }
3625 : }
3626 : }
3627 :
3628 0 : void findshadowvas()
3629 : {
3630 : std::array<vtxarray *, vasortsize> vasort;
3631 0 : vasort.fill(nullptr);
3632 0 : switch(shadowmapping)
3633 : {
3634 0 : case ShadowMap_Reflect:
3635 : {
3636 0 : findrsmshadowvas(varoot, vasort);
3637 0 : break;
3638 : }
3639 0 : case ShadowMap_CubeMap:
3640 : {
3641 0 : findshadowvas(varoot, vasort);
3642 0 : break;
3643 : }
3644 0 : case ShadowMap_Cascade:
3645 : {
3646 0 : findcsmshadowvas(varoot, vasort);
3647 0 : break;
3648 : }
3649 0 : case ShadowMap_Spot:
3650 : {
3651 0 : findspotshadowvas(varoot, vasort);
3652 0 : break;
3653 : }
3654 : }
3655 0 : sortshadowvas(vasort);
3656 0 : }
|