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