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
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 0 : void calcsurfaces(cube &c, const ivec &co, int size, int usefacemask, int preview = 0)
104 : {
105 0 : std::array<surfaceinfo, 6> surfaces;
106 : vertinfo litverts[6*2*Face_MaxVerts];
107 0 : int numlitverts = 0;
108 0 : surfaces.fill(surfaceinfo());
109 0 : for(int i = 0; i < 6; ++i) //for each face of the cube
110 : {
111 0 : int usefaces = usefacemask&0xF;
112 0 : usefacemask >>= 4;
113 0 : if(!usefaces)
114 : {
115 0 : if(!c.ext)
116 : {
117 0 : continue;
118 : }
119 0 : surfaceinfo &surf = c.ext->surfaces[i];
120 0 : int numverts = surf.totalverts();
121 0 : if(numverts)
122 : {
123 0 : std::memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
124 0 : surf.verts = numlitverts;
125 0 : numlitverts += numverts;
126 : }
127 0 : continue;
128 0 : }
129 :
130 0 : VSlot &vslot = lookupvslot(c.texture[i], false),
131 0 : *layer = vslot.layer && !(c.material&Mat_Alpha) ? &lookupvslot(vslot.layer, false) : nullptr;
132 0 : Shader *shader = vslot.slot->shader;
133 0 : int shadertype = shader->type;
134 0 : if(layer)
135 : {
136 0 : shadertype |= layer->slot->shader->type;
137 : }
138 0 : surfaceinfo &surf = surfaces[i];
139 0 : vertinfo *curlitverts = &litverts[numlitverts];
140 0 : int numverts = c.ext ? c.ext->surfaces[i].numverts&Face_MaxVerts : 0;
141 0 : ivec mo(co);
142 0 : int msz = size,
143 0 : convex = 0;
144 0 : if(numverts)
145 : {
146 0 : const vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
147 0 : for(int j = 0; j < numverts; ++j)
148 : {
149 0 : curlitverts[j].set(verts[j].getxyz());
150 : }
151 0 : if(c.merged&(1<<i))
152 : {
153 0 : msz = 1<<calcmergedsize(mo, size, verts, numverts);
154 0 : mo.mask(~(msz-1));
155 0 : if(!(surf.numverts&Face_MaxVerts))
156 : {
157 0 : surf.verts = numlitverts;
158 0 : surf.numverts |= numverts;
159 0 : numlitverts += numverts;
160 : }
161 : }
162 0 : else if(!flataxisface(c, i))
163 : {
164 0 : convex = faceconvexity(verts, numverts, size);
165 : }
166 : }
167 : else
168 : {
169 0 : std::array<ivec, 4> v;
170 0 : genfaceverts(c, i, v);
171 0 : if(!flataxisface(c, i))
172 : {
173 0 : convex = faceconvexity(v);
174 : }
175 0 : int order = usefaces&4 || convex < 0 ? 1 : 0;
176 0 : ivec vo = ivec(co).mask(0xFFF).shl(3);
177 0 : curlitverts[numverts++].set(v[order].mul(size).add(vo));
178 0 : if(usefaces&1)
179 : {
180 0 : curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
181 : }
182 0 : curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
183 0 : if(usefaces&2)
184 : {
185 0 : curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
186 : }
187 : }
188 :
189 0 : vec pos[Face_MaxVerts],
190 0 : n[Face_MaxVerts],
191 0 : po(ivec(co).mask(~0xFFF));
192 0 : for(int j = 0; j < numverts; ++j)
193 : {
194 0 : pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
195 : }
196 :
197 0 : int smooth = vslot.slot->smooth;
198 0 : plane planes[2];
199 0 : int numplanes = 0;
200 0 : planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
201 0 : if(numverts < 4 || !convex)
202 : {
203 0 : for(int k = 0; k < numverts; ++k)
204 : {
205 0 : findnormal(pos[k], smooth, planes[0], n[k]);
206 : }
207 0 : }
208 : else
209 : {
210 0 : planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
211 0 : vec avg = vec(planes[0]).add(planes[1]).normalize();
212 0 : findnormal(pos[0], smooth, avg, n[0]);
213 0 : findnormal(pos[1], smooth, planes[0], n[1]);
214 0 : findnormal(pos[2], smooth, avg, n[2]);
215 0 : for(int k = 3; k < numverts; k++)
216 : {
217 0 : findnormal(pos[k], smooth, planes[1], n[k]);
218 : }
219 : }
220 0 : for(int k = 0; k < numverts; ++k)
221 : {
222 0 : curlitverts[k].norm = encodenormal(n[k]);
223 : }
224 0 : if(!(surf.numverts&Face_MaxVerts))
225 : {
226 0 : surf.verts = numlitverts;
227 0 : surf.numverts |= numverts;
228 0 : numlitverts += numverts;
229 : }
230 0 : if(preview)
231 : {
232 0 : surf.numverts |= preview;
233 0 : continue;
234 : }
235 0 : int surflayer = BlendLayer_Top;
236 0 : if(vslot.layer)
237 : {
238 0 : int x1 = curlitverts[numverts-1].x,
239 0 : y1 = curlitverts[numverts-1].y,
240 0 : x2 = x1,
241 0 : y2 = y1;
242 0 : for(int j = 0; j < numverts-1; ++j)
243 : {
244 0 : const vertinfo &v = curlitverts[j];
245 0 : x1 = std::min(x1, static_cast<int>(v.x));
246 0 : y1 = std::min(y1, static_cast<int>(v.y));
247 0 : x2 = std::max(x2, static_cast<int>(v.x));
248 0 : y2 = std::max(y2, static_cast<int>(v.y));
249 : }
250 0 : x2 = std::max(x2, x1+1);
251 0 : y2 = std::max(y2, y1+1);
252 0 : x1 = (x1>>3) + (co.x&~0xFFF);
253 0 : y1 = (y1>>3) + (co.y&~0xFFF);
254 0 : x2 = ((x2+7)>>3) + (co.x&~0xFFF);
255 0 : y2 = ((y2+7)>>3) + (co.y&~0xFFF);
256 : }
257 0 : surf.numverts |= surflayer;
258 : }
259 0 : if(preview)
260 : {
261 0 : setsurfaces(c, surfaces, litverts, numlitverts);
262 : }
263 : else
264 : {
265 0 : for(const surfaceinfo &surf : surfaces)
266 : {
267 0 : if(surf.used())
268 : {
269 0 : cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
270 0 : std::memcpy(ext->surfaces.data(), surfaces.data(), sizeof(ext->surfaces));
271 0 : std::memcpy(ext->verts(), litverts, numlitverts*sizeof(vertinfo));
272 0 : if(c.ext != ext)
273 : {
274 0 : setcubeext(c, ext);
275 : }
276 0 : break;
277 : }
278 : }
279 : }
280 0 : }
281 :
282 0 : void calcsurfaces(std::array<cube, 8> &c, const ivec &co, int size)
283 : {
284 0 : for(int i = 0; i < 8; ++i)
285 : {
286 0 : ivec o(i, co, size);
287 0 : if(c[i].children)
288 : {
289 0 : calcsurfaces(*(c[i].children), o, size >> 1);
290 : }
291 0 : else if(!(c[i].isempty()))
292 : {
293 0 : if(c[i].ext)
294 : {
295 0 : for(surfaceinfo &s : c[i].ext->surfaces)
296 : {
297 0 : s.clear();
298 : }
299 : }
300 0 : int usefacemask = 0;
301 0 : for(int j = 0; j < 6; ++j)
302 : {
303 0 : if(c[i].texture[j] != Default_Sky && (!(c[i].merged & (1 << j)) || (c[i].ext && c[i].ext->surfaces[j].numverts & Face_MaxVerts)))
304 : {
305 0 : usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
306 : }
307 : }
308 0 : if(usefacemask)
309 : {
310 0 : calcsurfaces(c[i], o, size, usefacemask);
311 : }
312 : }
313 : }
314 0 : }
315 : }
316 :
317 : //external functionality
318 :
319 0 : CVAR1R(ambient, 0x191919);
320 : FVARR(ambientscale, 0, 1, 16);
321 :
322 0 : CVAR1R(skylight, 0);
323 : FVARR(skylightscale, 0, 1, 16);
324 :
325 0 : CVAR1FR(sunlight, 0,
326 : {
327 : clearradiancehintscache();
328 : cleardeferredlightshaders();
329 : clearshadowcache();
330 : });
331 0 : FVARFR(sunlightscale, 0, 1, 16, clearradiancehintscache(););
332 :
333 : vec sunlightdir(0, 0, 1);
334 0 : FVARFR(sunlightyaw, 0, 0, 360, setsunlightdir());
335 0 : FVARFR(sunlightpitch, -90, 90, 90, setsunlightdir());
336 :
337 0 : void brightencube(cube &c)
338 : {
339 0 : if(!c.ext)
340 : {
341 0 : newcubeext(c, 0, false);
342 : }
343 0 : c.ext->surfaces.fill(surfaceinfo());
344 0 : }
345 :
346 0 : void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts)
347 : {
348 0 : int dstoffset = 0;
349 0 : if(!c.ext)
350 : {
351 0 : newcubeext(c, numsrcverts, true);
352 : }
353 : else
354 : {
355 0 : int numbefore = 0,
356 0 : beforeoffset = 0;
357 0 : for(int i = 0; i < orient; ++i)
358 : {
359 0 : const surfaceinfo &surf = c.ext->surfaces[i];
360 0 : int numverts = surf.totalverts();
361 0 : if(!numverts)
362 : {
363 0 : continue;
364 : }
365 0 : numbefore += numverts;
366 0 : beforeoffset = surf.verts + numverts;
367 : }
368 0 : int numafter = 0,
369 0 : afteroffset = c.ext->maxverts;
370 0 : for(int i = 5; i > orient; i--) //note reverse iteration
371 : {
372 0 : const surfaceinfo &surf = c.ext->surfaces[i];
373 0 : int numverts = surf.totalverts();
374 0 : if(!numverts)
375 : {
376 0 : continue;
377 : }
378 0 : numafter += numverts;
379 0 : afteroffset = surf.verts;
380 : }
381 0 : if(afteroffset - beforeoffset >= numsrcverts)
382 : {
383 0 : dstoffset = beforeoffset;
384 : }
385 : else
386 : {
387 0 : cubeext *ext = c.ext;
388 0 : if(numbefore + numsrcverts + numafter > c.ext->maxverts)
389 : {
390 0 : ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
391 0 : std::copy(ext->surfaces.begin(), ext->surfaces.end(), c.ext->surfaces.begin());
392 : }
393 0 : int offset = 0;
394 0 : if(numbefore == beforeoffset)
395 : {
396 0 : if(numbefore && c.ext != ext)
397 : {
398 0 : std::memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
399 : }
400 0 : offset = numbefore;
401 : }
402 : else
403 : {
404 0 : for(int i = 0; i < orient; ++i)
405 : {
406 0 : surfaceinfo &surf = ext->surfaces[i];
407 0 : int numverts = surf.totalverts();
408 0 : if(!numverts)
409 : {
410 0 : continue;
411 : }
412 0 : std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
413 0 : surf.verts = offset;
414 0 : offset += numverts;
415 : }
416 : }
417 0 : dstoffset = offset;
418 0 : offset += numsrcverts;
419 0 : if(numafter && offset > afteroffset)
420 : {
421 0 : offset += numafter;
422 0 : for(int i = 5; i > orient; i--) //note reverse iteration
423 : {
424 0 : surfaceinfo &surf = ext->surfaces[i];
425 0 : int numverts = surf.totalverts();
426 0 : if(!numverts)
427 : {
428 0 : continue;
429 : }
430 0 : offset -= numverts;
431 0 : std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
432 0 : surf.verts = offset;
433 : }
434 : }
435 0 : if(c.ext != ext)
436 : {
437 0 : setcubeext(c, ext);
438 : }
439 : }
440 : }
441 0 : surfaceinfo &dst = c.ext->surfaces[orient];
442 0 : dst = src;
443 0 : dst.verts = dstoffset;
444 0 : if(srcverts)
445 : {
446 0 : std::memcpy(c.ext->verts() + dstoffset, srcverts, numsrcverts*sizeof(vertinfo));
447 : }
448 0 : }
449 :
450 33 : bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th)
451 : {
452 33 : if((available < tw && available < th) || w < tw || h < th)
453 : {
454 9 : return false;
455 : }
456 24 : if(child1)
457 : {
458 21 : bool inserted = child1->insert(tx, ty, tw, th) ||
459 9 : child2->insert(tx, ty, tw, th);
460 12 : available = std::max(child1->available, child2->available);
461 12 : if(!available)
462 : {
463 3 : discardchildren();
464 : }
465 12 : return inserted;
466 : }
467 12 : if(w == tw && h == th)
468 : {
469 6 : available = 0;
470 6 : tx = x;
471 6 : ty = y;
472 6 : return true;
473 : }
474 :
475 6 : if(w - tw > h - th)
476 : {
477 4 : child1 = new PackNode(x, y, tw, h);
478 4 : child2 = new PackNode(x + tw, y, w - tw, h);
479 : }
480 : else
481 : {
482 2 : child1 = new PackNode(x, y, w, th);
483 2 : child2 = new PackNode(x, y + th, w, h - th);
484 : }
485 :
486 6 : bool inserted = child1->insert(tx, ty, tw, th);
487 6 : available = std::max(child1->available, child2->available);
488 6 : return inserted;
489 : }
490 :
491 0 : void PackNode::reserve(ushort tx, ushort ty, ushort tw, ushort th)
492 : {
493 0 : if(tx + tw <= x || tx >= x + w || ty + th <= y || ty >= y + h)
494 : {
495 0 : return;
496 : }
497 0 : if(child1)
498 : {
499 0 : child1->reserve(tx, ty, tw, th);
500 0 : child2->reserve(tx, ty, tw, th);
501 0 : available = std::max(child1->available, child2->available);
502 0 : return;
503 : }
504 0 : int dx1 = tx - x,
505 0 : dx2 = x + w - tx - tw,
506 0 : dx = std::max(dx1, dx2),
507 0 : dy1 = ty - y,
508 0 : dy2 = y + h - ty - th,
509 0 : dy = std::max(dy1, dy2),
510 : split;
511 0 : if(dx > dy)
512 : {
513 0 : if(dx1 > dx2)
514 : {
515 0 : split = std::min(dx1, static_cast<int>(w));
516 : }
517 : else
518 : {
519 0 : split = w - std::max(dx2, 0);
520 : }
521 0 : if(w - split <= 0)
522 : {
523 0 : w = split;
524 0 : available = std::min(w, h);
525 0 : if(dy > 0)
526 : {
527 0 : reserve(tx, ty, tw, th);
528 : }
529 0 : else if(tx <= x && tx + tw >= x + w)
530 : {
531 0 : available = 0;
532 : }
533 0 : return;
534 : }
535 0 : if(split <= 0)
536 : {
537 0 : x += split;
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 : child1 = new PackNode(x, y, split, h);
551 0 : child2 = new PackNode(x + split, y, w - split, h);
552 : }
553 : else
554 : {
555 0 : if(dy1 > dy2)
556 : {
557 0 : split = std::min(dy1, static_cast<int>(h));
558 : }
559 : else
560 : {
561 0 : split = h - std::max(dy2, 0);
562 : }
563 0 : if(h - split <= 0)
564 : {
565 0 : h = split;
566 0 : available = std::min(w, h);
567 0 : if(dx > 0)
568 : {
569 0 : reserve(tx, ty, tw, th);
570 : }
571 0 : else if(ty <= y && ty + th >= y + h)
572 : {
573 0 : available = 0;
574 : }
575 0 : return;
576 : }
577 0 : if(split <= 0)
578 : {
579 0 : y += split;
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 : child1 = new PackNode(x, y, w, split);
593 0 : child2 = new PackNode(x, y + split, w, h - split);
594 : }
595 0 : child1->reserve(tx, ty, tw, th);
596 0 : child2->reserve(tx, ty, tw, th);
597 0 : available = std::max(child1->available, child2->available);
598 : }
599 :
600 0 : VARF(lightcachesize, 4, 6, 12, clearlightcache());
601 :
602 0 : void clearlightcache(int id)
603 : {
604 0 : if(id >= 0)
605 : {
606 0 : const extentity &light = *entities::getents()[id];
607 0 : int radius = light.attr1;
608 0 : if(radius <= 0)
609 : {
610 0 : return;
611 : }
612 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++)
613 : {
614 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++)
615 : {
616 0 : lightcacheentry &lce = lightcache[lightcachehash(x, y)];
617 0 : if(lce.x != x || lce.y != y)
618 : {
619 0 : continue;
620 : }
621 0 : lce.x = -1;
622 : }
623 : }
624 0 : return;
625 : }
626 :
627 0 : for(lightcacheentry *lce = lightcache; lce < &lightcache[lightcacheentries]; lce++)
628 : {
629 0 : lce->x = -1;
630 : }
631 : }
632 :
633 0 : void cubeworld::calclight()
634 : {
635 0 : remip();
636 0 : clearsurfaces(*worldroot);
637 0 : calcnormals(filltjoints > 0);
638 0 : calcsurfaces(*worldroot, ivec(0, 0, 0), rootworld.mapsize() >> 1);
639 0 : clearnormals();
640 0 : allchanged();
641 0 : }
642 :
643 : VAR(fullbright, 0, 0, 1); //toggles rendering at fullbrightlevel light
644 : VAR(fullbrightlevel, 0, 160, 255); //grayscale shade for lighting when at fullbright
645 :
646 0 : void clearlights()
647 : {
648 0 : clearlightcache();
649 0 : clearshadowcache();
650 0 : cleardeferredlightshaders();
651 0 : resetsmoothgroups();
652 0 : }
653 :
654 0 : void initlights()
655 : {
656 0 : clearlightcache();
657 0 : clearshadowcache();
658 0 : loaddeferredlightshaders();
659 0 : }
|