Line data Source code
1 : /**
2 : * @file world light interaction functions
3 : *
4 : * while renderlights in /render handles the deferred rendering of point lights
5 : * on the world, light.cpp handles how lights behave in the world
6 : *
7 : * includes sunlight variables (direction/color of no-parallax sun lighting)
8 : * world light entity packing for the renderer to use
9 : */
10 : #include "../libprimis-headers/cube.h"
11 : #include "../../shared/geomexts.h"
12 : #include "../../shared/glexts.h"
13 :
14 : #include "light.h"
15 : #include "octaworld.h"
16 : #include "raycube.h"
17 : #include "world.h"
18 :
19 : #include "interface/console.h"
20 : #include "interface/input.h"
21 :
22 : #include "render/radiancehints.h"
23 : #include "render/renderlights.h"
24 : #include "render/normal.h"
25 : #include "render/octarender.h"
26 : #include "render/shaderparam.h"
27 : #include "render/texture.h"
28 :
29 : namespace
30 : {
31 0 : void setsunlightdir()
32 : {
33 0 : sunlightdir = vec(sunlightyaw/RAD, sunlightpitch/RAD);
34 0 : for(int k = 0; k < 3; ++k)
35 : {
36 0 : if(std::fabs(sunlightdir[k]) < 1e-5f)
37 : {
38 0 : sunlightdir[k] = 0;
39 : }
40 : }
41 0 : sunlightdir.normalize();
42 0 : clearradiancehintscache();
43 0 : }
44 :
45 0 : void setsurfaces(cube &c, std::array<surfaceinfo, 6> surfs, const vertinfo *verts, int numverts)
46 : {
47 0 : if(!c.ext || c.ext->maxverts < numverts)
48 : {
49 0 : newcubeext(c, numverts, false);
50 : }
51 0 : std::copy(c.ext->surfaces.begin(), c.ext->surfaces.end(), surfs.begin());
52 0 : std::memcpy(c.ext->verts(), verts, numverts*sizeof(vertinfo));
53 0 : }
54 :
55 0 : void clearsurfaces(std::array<cube, 8> &c)
56 : {
57 0 : for(int i = 0; i < 8; ++i)
58 : {
59 0 : if(c[i].ext)
60 : {
61 0 : for(int j = 0; j < 6; ++j)
62 : {
63 0 : surfaceinfo &surf = c[i].ext->surfaces[j];
64 0 : if(!surf.used())
65 : {
66 0 : continue;
67 : }
68 0 : surf.clear();
69 0 : int numverts = surf.numverts&Face_MaxVerts;
70 0 : if(numverts)
71 : {
72 0 : if(!(c[i].merged&(1<<j)))
73 : {
74 0 : surf.numverts &= ~Face_MaxVerts;
75 0 : continue;
76 : }
77 0 : vertinfo *verts = c[i].ext->verts() + surf.verts;
78 0 : for(int k = 0; k < numverts; ++k)
79 : {
80 0 : vertinfo &v = verts[k];
81 0 : v.norm = 0;
82 : }
83 : }
84 : }
85 : }
86 0 : if(c[i].children)
87 : {
88 0 : clearsurfaces(*(c[i].children));
89 : }
90 : }
91 0 : }
92 :
93 : constexpr int lightcacheentries = 1024;
94 :
95 : struct lightcacheentry final
96 : {
97 : int x, y;
98 : };
99 :
100 : std::array<lightcacheentry, lightcacheentries> lightcache;
101 :
102 0 : int lightcachehash(int x, int y)
103 : {
104 0 : return (((((x)^(y))<<5) + (((x)^(y))>>5)) & (lightcacheentries - 1));
105 : }
106 :
107 : /**
108 : * @brief Takes a 3d vec3 and transforms it into a packed ushort vector
109 : *
110 : * The output ushort is in base 360 and has yaw in the first place and pitch in the second place.
111 : * The second place has pitch as a range from 0 to 90; since this is a normal
112 : * vector, no magnitude is needed.
113 : *
114 : * @param n the normal to encode
115 : *
116 : * @return the packed normal vector
117 : */
118 0 : ushort encodenormal(const vec &n)
119 : {
120 0 : if(n.iszero())
121 : {
122 0 : return 0;
123 : }
124 0 : const int yaw = static_cast<int>(-std::atan2(n.x, n.y)*RAD), //arctangent in degrees
125 0 : pitch = static_cast<int>(std::asin(n.z)*RAD); //arcsin in degrees
126 0 : return static_cast<ushort>(std::clamp(pitch + 90, 0, 180)*360 + (yaw < 0 ? yaw%360 + 360 : yaw%360) + 1);
127 : }
128 :
129 0 : void calcsurfaces(cube &c, const ivec &co, int size, int usefacemask, int preview = 0)
130 : {
131 0 : std::array<surfaceinfo, 6> surfaces;
132 : std::array<vertinfo, 6*2*Face_MaxVerts> litverts;
133 0 : int numlitverts = 0;
134 0 : surfaces.fill(surfaceinfo());
135 0 : for(int i = 0; i < 6; ++i) //for each face of the cube
136 : {
137 0 : int usefaces = usefacemask&0xF;
138 0 : usefacemask >>= 4;
139 0 : if(!usefaces)
140 : {
141 0 : if(!c.ext)
142 : {
143 0 : continue;
144 : }
145 0 : surfaceinfo &surf = c.ext->surfaces[i];
146 0 : int numverts = surf.totalverts();
147 0 : if(numverts)
148 : {
149 0 : std::memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
150 0 : surf.verts = numlitverts;
151 0 : numlitverts += numverts;
152 : }
153 0 : continue;
154 0 : }
155 :
156 0 : VSlot &vslot = lookupvslot(c.texture[i], false),
157 0 : *layer = vslot.layer && !(c.material&Mat_Alpha) ? &lookupvslot(vslot.layer, false) : nullptr;
158 0 : Shader *shader = vslot.slot->shader;
159 0 : int shadertype = shader->type;
160 0 : if(layer)
161 : {
162 0 : shadertype |= layer->slot->shader->type;
163 : }
164 0 : surfaceinfo &surf = surfaces[i];
165 0 : vertinfo *curlitverts = &litverts[numlitverts];
166 0 : int numverts = c.ext ? c.ext->surfaces[i].numverts&Face_MaxVerts : 0;
167 0 : ivec mo(co);
168 0 : int msz = size,
169 0 : convex = 0;
170 0 : if(numverts)
171 : {
172 0 : const vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
173 0 : for(int j = 0; j < numverts; ++j)
174 : {
175 0 : curlitverts[j].set(verts[j].getxyz());
176 : }
177 0 : if(c.merged&(1<<i))
178 : {
179 0 : msz = 1<<calcmergedsize(mo, size, verts, numverts);
180 0 : mo.mask(~(msz-1));
181 0 : if(!(surf.numverts&Face_MaxVerts))
182 : {
183 0 : surf.verts = numlitverts;
184 0 : surf.numverts |= numverts;
185 0 : numlitverts += numverts;
186 : }
187 : }
188 0 : else if(!flataxisface(c, i))
189 : {
190 0 : convex = faceconvexity(verts, numverts, size);
191 : }
192 : }
193 : else
194 : {
195 0 : std::array<ivec, 4> v;
196 0 : genfaceverts(c, i, v);
197 0 : if(!flataxisface(c, i))
198 : {
199 0 : convex = faceconvexity(v);
200 : }
201 0 : int order = usefaces&4 || convex < 0 ? 1 : 0;
202 0 : ivec vo = ivec(co).mask(0xFFF).shl(3);
203 0 : curlitverts[numverts++].set(v[order].mul(size).add(vo));
204 0 : if(usefaces&1)
205 : {
206 0 : curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
207 : }
208 0 : curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
209 0 : if(usefaces&2)
210 : {
211 0 : curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
212 : }
213 : }
214 :
215 0 : std::array<vec, Face_MaxVerts> pos,
216 0 : n;
217 0 : vec po(ivec(co).mask(~0xFFF));
218 0 : for(int j = 0; j < numverts; ++j)
219 : {
220 0 : pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
221 : }
222 :
223 0 : int smooth = vslot.slot->smooth;
224 0 : std::array<plane, 2> planes;
225 0 : int numplanes = 0;
226 0 : planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
227 0 : if(numverts < 4 || !convex)
228 : {
229 0 : for(int k = 0; k < numverts; ++k)
230 : {
231 0 : findnormal(pos[k], smooth, planes[0], n[k]);
232 : }
233 0 : }
234 : else
235 : {
236 0 : planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
237 0 : vec avg = vec(planes[0]).add(planes[1]).normalize();
238 0 : findnormal(pos[0], smooth, avg, n[0]);
239 0 : findnormal(pos[1], smooth, planes[0], n[1]);
240 0 : findnormal(pos[2], smooth, avg, n[2]);
241 0 : for(int k = 3; k < numverts; k++)
242 : {
243 0 : findnormal(pos[k], smooth, planes[1], n[k]);
244 : }
245 : }
246 0 : for(int k = 0; k < numverts; ++k)
247 : {
248 0 : curlitverts[k].norm = encodenormal(n[k]);
249 : }
250 0 : if(!(surf.numverts&Face_MaxVerts))
251 : {
252 0 : surf.verts = numlitverts;
253 0 : surf.numverts |= numverts;
254 0 : numlitverts += numverts;
255 : }
256 0 : if(preview)
257 : {
258 0 : surf.numverts |= preview;
259 0 : continue;
260 : }
261 0 : int surflayer = BlendLayer_Top;
262 0 : if(vslot.layer)
263 : {
264 0 : int x1 = curlitverts[numverts-1].x,
265 0 : y1 = curlitverts[numverts-1].y,
266 0 : x2 = x1,
267 0 : y2 = y1;
268 0 : for(int j = 0; j < numverts-1; ++j)
269 : {
270 0 : const vertinfo &v = curlitverts[j];
271 0 : x1 = std::min(x1, static_cast<int>(v.x));
272 0 : y1 = std::min(y1, static_cast<int>(v.y));
273 0 : x2 = std::max(x2, static_cast<int>(v.x));
274 0 : y2 = std::max(y2, static_cast<int>(v.y));
275 : }
276 0 : x2 = std::max(x2, x1+1);
277 0 : y2 = std::max(y2, y1+1);
278 0 : x1 = (x1>>3) + (co.x&~0xFFF);
279 0 : y1 = (y1>>3) + (co.y&~0xFFF);
280 0 : x2 = ((x2+7)>>3) + (co.x&~0xFFF);
281 0 : y2 = ((y2+7)>>3) + (co.y&~0xFFF);
282 : }
283 0 : surf.numverts |= surflayer;
284 : }
285 0 : if(preview)
286 : {
287 0 : setsurfaces(c, surfaces, litverts.data(), numlitverts);
288 : }
289 : else
290 : {
291 0 : for(const surfaceinfo &surf : surfaces)
292 : {
293 0 : if(surf.used())
294 : {
295 0 : cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
296 0 : std::memcpy(ext->surfaces.data(), surfaces.data(), sizeof(ext->surfaces));
297 0 : std::memcpy(ext->verts(), litverts.data(), numlitverts*sizeof(vertinfo));
298 0 : if(c.ext != ext)
299 : {
300 0 : setcubeext(c, ext);
301 : }
302 0 : break;
303 : }
304 : }
305 : }
306 0 : }
307 :
308 0 : void calcsurfaces(std::array<cube, 8> &c, const ivec &co, int size)
309 : {
310 0 : for(int i = 0; i < 8; ++i)
311 : {
312 0 : ivec o(i, co, size);
313 0 : if(c[i].children)
314 : {
315 0 : calcsurfaces(*(c[i].children), o, size >> 1);
316 : }
317 0 : else if(!(c[i].isempty()))
318 : {
319 0 : if(c[i].ext)
320 : {
321 0 : for(surfaceinfo &s : c[i].ext->surfaces)
322 : {
323 0 : s.clear();
324 : }
325 : }
326 0 : int usefacemask = 0;
327 0 : for(int j = 0; j < 6; ++j)
328 : {
329 0 : if(c[i].texture[j] != Default_Sky && (!(c[i].merged & (1 << j)) || (c[i].ext && c[i].ext->surfaces[j].numverts & Face_MaxVerts)))
330 : {
331 0 : usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
332 : }
333 : }
334 0 : if(usefacemask)
335 : {
336 0 : calcsurfaces(c[i], o, size, usefacemask);
337 : }
338 : }
339 : }
340 0 : }
341 : }
342 :
343 : //external functionality
344 :
345 0 : CVAR1R(ambient, 0x191919);
346 : FVARR(ambientscale, 0, 1, 16);
347 :
348 0 : CVAR1R(skylight, 0);
349 : FVARR(skylightscale, 0, 1, 16);
350 :
351 0 : CVAR1FR(sunlight, 0,
352 : {
353 : clearradiancehintscache();
354 : cleardeferredlightshaders();
355 : clearshadowcache();
356 : });
357 0 : FVARFR(sunlightscale, 0, 1, 16, clearradiancehintscache(););
358 :
359 : vec sunlightdir(0, 0, 1);
360 0 : FVARFR(sunlightyaw, 0, 0, 360, setsunlightdir());
361 0 : FVARFR(sunlightpitch, -90, 90, 90, setsunlightdir());
362 :
363 0 : void brightencube(cube &c)
364 : {
365 0 : if(!c.ext)
366 : {
367 0 : newcubeext(c, 0, false);
368 : }
369 0 : c.ext->surfaces.fill(surfaceinfo());
370 0 : }
371 :
372 0 : void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts)
373 : {
374 0 : int dstoffset = 0;
375 0 : if(!c.ext)
376 : {
377 0 : newcubeext(c, numsrcverts, true);
378 : }
379 : else
380 : {
381 0 : int numbefore = 0,
382 0 : beforeoffset = 0;
383 0 : for(int i = 0; i < orient; ++i)
384 : {
385 0 : const surfaceinfo &surf = c.ext->surfaces[i];
386 0 : int numverts = surf.totalverts();
387 0 : if(!numverts)
388 : {
389 0 : continue;
390 : }
391 0 : numbefore += numverts;
392 0 : beforeoffset = surf.verts + numverts;
393 : }
394 0 : int numafter = 0,
395 0 : afteroffset = c.ext->maxverts;
396 0 : for(int i = 5; i > orient; i--) //note reverse iteration
397 : {
398 0 : const surfaceinfo &surf = c.ext->surfaces[i];
399 0 : int numverts = surf.totalverts();
400 0 : if(!numverts)
401 : {
402 0 : continue;
403 : }
404 0 : numafter += numverts;
405 0 : afteroffset = surf.verts;
406 : }
407 0 : if(afteroffset - beforeoffset >= numsrcverts)
408 : {
409 0 : dstoffset = beforeoffset;
410 : }
411 : else
412 : {
413 0 : cubeext *ext = c.ext;
414 0 : if(numbefore + numsrcverts + numafter > c.ext->maxverts)
415 : {
416 0 : ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
417 0 : std::copy(ext->surfaces.begin(), ext->surfaces.end(), c.ext->surfaces.begin());
418 : }
419 0 : int offset = 0;
420 0 : if(numbefore == beforeoffset)
421 : {
422 0 : if(numbefore && c.ext != ext)
423 : {
424 0 : std::memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
425 : }
426 0 : offset = numbefore;
427 : }
428 : else
429 : {
430 0 : for(int i = 0; i < orient; ++i)
431 : {
432 0 : surfaceinfo &surf = ext->surfaces[i];
433 0 : int numverts = surf.totalverts();
434 0 : if(!numverts)
435 : {
436 0 : continue;
437 : }
438 0 : std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
439 0 : surf.verts = offset;
440 0 : offset += numverts;
441 : }
442 : }
443 0 : dstoffset = offset;
444 0 : offset += numsrcverts;
445 0 : if(numafter && offset > afteroffset)
446 : {
447 0 : offset += numafter;
448 0 : for(int i = 5; i > orient; i--) //note reverse iteration
449 : {
450 0 : surfaceinfo &surf = ext->surfaces[i];
451 0 : int numverts = surf.totalverts();
452 0 : if(!numverts)
453 : {
454 0 : continue;
455 : }
456 0 : offset -= numverts;
457 0 : std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
458 0 : surf.verts = offset;
459 : }
460 : }
461 0 : if(c.ext != ext)
462 : {
463 0 : setcubeext(c, ext);
464 : }
465 : }
466 : }
467 0 : surfaceinfo &dst = c.ext->surfaces[orient];
468 0 : dst = src;
469 0 : dst.verts = dstoffset;
470 0 : if(srcverts)
471 : {
472 0 : std::memcpy(c.ext->verts() + dstoffset, srcverts, numsrcverts*sizeof(vertinfo));
473 : }
474 0 : }
475 :
476 33 : bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th)
477 : {
478 33 : if((available < tw && available < th) || w < tw || h < th)
479 : {
480 9 : return false;
481 : }
482 24 : if(child1)
483 : {
484 21 : bool inserted = child1->insert(tx, ty, tw, th) ||
485 9 : child2->insert(tx, ty, tw, th);
486 12 : available = std::max(child1->available, child2->available);
487 12 : if(!available)
488 : {
489 3 : discardchildren();
490 : }
491 12 : return inserted;
492 : }
493 12 : if(w == tw && h == th)
494 : {
495 6 : available = 0;
496 6 : tx = x;
497 6 : ty = y;
498 6 : return true;
499 : }
500 :
501 6 : if(w - tw > h - th)
502 : {
503 4 : child1 = new PackNode(x, y, tw, h);
504 4 : child2 = new PackNode(x + tw, y, w - tw, h);
505 : }
506 : else
507 : {
508 2 : child1 = new PackNode(x, y, w, th);
509 2 : child2 = new PackNode(x, y + th, w, h - th);
510 : }
511 :
512 6 : bool inserted = child1->insert(tx, ty, tw, th);
513 6 : available = std::max(child1->available, child2->available);
514 6 : return inserted;
515 : }
516 :
517 0 : void PackNode::reserve(ushort tx, ushort ty, ushort tw, ushort th)
518 : {
519 0 : if(tx + tw <= x || tx >= x + w || ty + th <= y || ty >= y + h)
520 : {
521 0 : return;
522 : }
523 0 : if(child1)
524 : {
525 0 : child1->reserve(tx, ty, tw, th);
526 0 : child2->reserve(tx, ty, tw, th);
527 0 : available = std::max(child1->available, child2->available);
528 0 : return;
529 : }
530 0 : int dx1 = tx - x,
531 0 : dx2 = x + w - tx - tw,
532 0 : dx = std::max(dx1, dx2),
533 0 : dy1 = ty - y,
534 0 : dy2 = y + h - ty - th,
535 0 : dy = std::max(dy1, dy2),
536 : split;
537 0 : if(dx > dy)
538 : {
539 0 : if(dx1 > dx2)
540 : {
541 0 : split = std::min(dx1, static_cast<int>(w));
542 : }
543 : else
544 : {
545 0 : split = w - std::max(dx2, 0);
546 : }
547 0 : if(w - split <= 0)
548 : {
549 0 : w = split;
550 0 : available = std::min(w, h);
551 0 : if(dy > 0)
552 : {
553 0 : reserve(tx, ty, tw, th);
554 : }
555 0 : else if(tx <= x && tx + tw >= x + w)
556 : {
557 0 : available = 0;
558 : }
559 0 : return;
560 : }
561 0 : if(split <= 0)
562 : {
563 0 : x += split;
564 0 : w -= split;
565 0 : available = std::min(w, h);
566 0 : if(dy > 0)
567 : {
568 0 : reserve(tx, ty, tw, th);
569 : }
570 0 : else if(tx <= x && tx + tw >= x + w)
571 : {
572 0 : available = 0;
573 : }
574 0 : return;
575 : }
576 0 : child1 = new PackNode(x, y, split, h);
577 0 : child2 = new PackNode(x + split, y, w - split, h);
578 : }
579 : else
580 : {
581 0 : if(dy1 > dy2)
582 : {
583 0 : split = std::min(dy1, static_cast<int>(h));
584 : }
585 : else
586 : {
587 0 : split = h - std::max(dy2, 0);
588 : }
589 0 : if(h - split <= 0)
590 : {
591 0 : h = split;
592 0 : available = std::min(w, h);
593 0 : if(dx > 0)
594 : {
595 0 : reserve(tx, ty, tw, th);
596 : }
597 0 : else if(ty <= y && ty + th >= y + h)
598 : {
599 0 : available = 0;
600 : }
601 0 : return;
602 : }
603 0 : if(split <= 0)
604 : {
605 0 : y += split;
606 0 : h -= split;
607 0 : available = std::min(w, h);
608 0 : if(dx > 0)
609 : {
610 0 : reserve(tx, ty, tw, th);
611 : }
612 0 : else if(ty <= y && ty + th >= y + h)
613 : {
614 0 : available = 0;
615 : }
616 0 : return;
617 : }
618 0 : child1 = new PackNode(x, y, w, split);
619 0 : child2 = new PackNode(x, y + split, w, h - split);
620 : }
621 0 : child1->reserve(tx, ty, tw, th);
622 0 : child2->reserve(tx, ty, tw, th);
623 0 : available = std::max(child1->available, child2->available);
624 : }
625 :
626 0 : static VARF(lightcachesize, 4, 6, 12, clearlightcache());
627 :
628 0 : void clearlightcache(int id)
629 : {
630 0 : if(id >= 0)
631 : {
632 0 : const extentity &light = *entities::getents()[id];
633 0 : int radius = light.attr1;
634 0 : if(radius <= 0)
635 : {
636 0 : return;
637 : }
638 0 : for(int x = static_cast<int>(std::max(light.o.x-radius, 0.0f))>>lightcachesize, ex = static_cast<int>(std::min(light.o.x+radius, rootworld.mapsize()-1.0f))>>lightcachesize; x <= ex; x++)
639 : {
640 0 : for(int y = static_cast<int>(std::max(light.o.y-radius, 0.0f))>>lightcachesize, ey = static_cast<int>(std::min(light.o.y+radius, rootworld.mapsize()-1.0f))>>lightcachesize; y <= ey; y++)
641 : {
642 0 : lightcacheentry &lce = lightcache[lightcachehash(x, y)];
643 0 : if(lce.x != x || lce.y != y)
644 : {
645 0 : continue;
646 : }
647 0 : lce.x = -1;
648 : }
649 : }
650 0 : return;
651 : }
652 :
653 0 : for(lightcacheentry &lce : lightcache)
654 : {
655 0 : lce.x = -1;
656 : }
657 : }
658 :
659 0 : void cubeworld::calclight()
660 : {
661 0 : remip();
662 0 : clearsurfaces(*worldroot);
663 0 : calcnormals(filltjoints > 0);
664 0 : calcsurfaces(*worldroot, ivec(0, 0, 0), rootworld.mapsize() >> 1);
665 0 : clearnormals();
666 0 : allchanged();
667 0 : }
668 :
669 0 : void clearlights()
670 : {
671 0 : clearlightcache();
672 0 : clearshadowcache();
673 0 : cleardeferredlightshaders();
674 0 : resetsmoothgroups();
675 0 : }
676 :
677 0 : void initlights()
678 : {
679 0 : clearlightcache();
680 0 : clearshadowcache();
681 0 : loaddeferredlightshaders();
682 0 : }
|