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