Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / patch_lightmap.cpp
blob7a47085dd682b16da1da9cdc53437766daefd2c5
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "std3d.h"
21 #include "nel/3d/patch.h"
22 #include "nel/3d/tessellation.h"
23 #include "nel/3d/bezier_patch.h"
24 #include "nel/3d/zone.h"
25 #include "nel/3d/landscape.h"
26 #include "nel/misc/vector.h"
27 #include "nel/misc/common.h"
28 #include "nel/3d/patchuv_locator.h"
29 #include "nel/3d/vegetable_manager.h"
30 #include "nel/misc/fast_floor.h"
31 #include "nel/3d/light_influence_interpolator.h"
32 #include "nel/3d/patchdlm_context.h"
34 using namespace std;
35 using namespace NLMISC;
37 #ifdef DEBUG_NEW
38 #define new DEBUG_NEW
39 #endif
41 namespace NL3D
45 // ***************************************************************************
46 // Precalc table used to decompress shadow map
47 // NB: if you want to change thoses values, see unpackLumelBlock, cause hardcoded.
48 static const uint NL3DDecompressLumelFactor0Case0[8]=
50 7, 0, 6, 5, 4, 3, 2, 1
52 static const uint NL3DDecompressLumelFactor1Case0[8]=
54 0, 7, 1, 2, 3, 4, 5, 6
56 static const uint NL3DDecompressLumelFactor0Case1[6]=
58 5, 0, 4, 3, 2, 1,
60 static const uint NL3DDecompressLumelFactor1Case1[6]=
62 0, 5, 1, 2, 3, 4,
64 // ***************************************************************************
65 void CPatch::unpackLumelBlock (uint8 *dest, const uint8 *src)
67 // Take the two alpha values
68 uint alpha0=src[0];
69 uint alpha1=src[1];
71 // precompute the 8 possible values, for each possible code.
72 // ------------------
73 uint8 values[8];
74 // Case 0
75 if (alpha0>alpha1)
77 // unrolled, and hardcoded for faster compute
78 values[0]= alpha0;
79 values[1]= alpha1;
80 values[2]= (uint8) ( (alpha0*219 + alpha1*37 ) >>8 ) ; // 6*256/7
81 values[3]= (uint8) ( (alpha0*183 + alpha1*73 ) >>8 ) ; // 5*256/7
82 values[4]= (uint8) ( (alpha0*146 + alpha1*110) >>8 ) ; // 4*256/7
83 values[5]= (uint8) ( (alpha0*110 + alpha1*146) >>8 ) ; // 3*256/7
84 values[6]= (uint8) ( (alpha0*73 + alpha1*183) >>8 ) ; // 2*256/7
85 values[7]= (uint8) ( (alpha0*37 + alpha1*219) >>8 ) ; // 1*256/7
87 // Case 1
88 else
90 // unrolled, and hardcoded for faster compute
91 values[0]= alpha0;
92 values[1]= alpha1;
93 values[2]= (uint8) ( (alpha0*205 + alpha1*51 ) >>8 ) ; // 4*256/5
94 values[3]= (uint8) ( (alpha0*154 + alpha1*102) >>8 ) ; // 3*256/5
95 values[4]= (uint8) ( (alpha0*102 + alpha1*154) >>8 ) ; // 2*256/5
96 values[5]= (uint8) ( (alpha0*51 + alpha1*205) >>8 ) ; // 1*256/5
97 values[6]= 0;
98 values[7]= 255;
102 // For each pixel, set the value according to the code
103 // ------------------
104 uint block8Pixs[2];
105 // Split the 48 bits data in 2 24 bits pass.
106 block8Pixs[0]= ((uint)src[2]<<16) + ((uint)src[3]<<8) + ((uint)src[4]) ;
107 block8Pixs[1]= ((uint)src[5]<<16) + ((uint)src[6]<<8) + ((uint)src[7]) ;
109 // write all lumels
110 for(uint i=0; i<2; i++)
112 uint blockPix= block8Pixs[i];
113 // parse the 8 pixs, and write seq to dest
114 for(uint n=8; n>0; n--, dest++)
116 uint code= (blockPix>>21)&0x7;
118 // read LUT, and store
119 *dest= values[code];
121 // shift the block
122 blockPix<<= 3;
128 // ***************************************************************************
129 inline uint8 getUnpackLumelBlock (const uint8 *src, uint pixel)
131 // Offset of the bit
132 pixel*=3;
133 uint offset=(pixel>>3)+2;
134 uint bits=pixel&7;
136 // Uncompress 16 codes
137 uint code;
139 // Get the code
140 if (bits<=5)
141 code=(src[offset]>>(5-bits))&0x7;
142 else
143 code= ( (src[offset]<<(bits-5)) | (src[offset+1]>>(13-bits)) )&0x7;
145 // Case 0
146 if (src[0]>src[1])
148 // Decompress the data
149 return (uint8)((NL3DDecompressLumelFactor0Case0[code]*src[0]+NL3DDecompressLumelFactor1Case0[code]*src[1])/7);
151 // Case 1
152 else
154 // Decompress the data
155 if (code<6)
156 return (uint8)((NL3DDecompressLumelFactor0Case1[code]*src[0]+NL3DDecompressLumelFactor1Case1[code]*src[1])/5);
157 else if (code==6)
158 return 0;
159 else
160 return 255;
164 // ***************************************************************************
165 void CPatch::unpackShadowMap (uint8 *pLumelDest)
167 // Input of compresed data
168 uint8 *compressedData=&CompressedLumels[0];
170 // Number of lumel by lines
171 uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
173 // Number of block in a line
174 nlassert ((lumelCount&0x3)==0);
175 uint numLumelBlock=lumelCount>>2;
177 // Number of line
178 uint lineCount=OrderT*NL_LUMEL_BY_TILE;
180 // Number of block line
181 nlassert ((lineCount&0x3)==0);
182 uint numLineBlock=lineCount>>2;
184 // Destination lumel block size
185 uint lumelDestBlockSize=4;
187 // Destination lumel line block size
188 uint lumelDestLineBlockSize=lumelCount*lumelDestBlockSize;
190 // Each line block
191 for (uint lineBlock=0; lineBlock<numLineBlock; lineBlock++)
193 uint countVx4=16;
195 // Block pointer
196 uint8 *blockLine=pLumelDest;
198 // Each lumel block
199 for (uint lumelBlock=0; lumelBlock<numLumelBlock; lumelBlock++)
201 // *** Unpack the block
202 uint countU=4;
204 // Destination lumel
205 uint8 *blockDest=blockLine;
207 // Temp block
208 uint8 block[4*4];
210 // Block unpacking...
211 unpackLumelBlock (block, compressedData);
213 // Copy the lumels
214 for (uint v=0; v<countVx4; v+=4)
216 for (uint u=0; u<countU; u++)
218 // Copy the lumel
219 blockDest[u]=block[v+u];
222 // Next line
223 blockDest+=lumelCount;
226 // Next source block
227 compressedData+=NL_BLOCK_LUMEL_COMPRESSED_SIZE;
229 // Next block on the line
230 blockLine+=lumelDestBlockSize;
233 // Next line of block
234 pLumelDest+=lumelDestLineBlockSize;
238 // ***************************************************************************
239 uint CPatch::evalLumelBlock (const uint8 *original, const uint8 *unCompressed, uint width, uint height)
241 // Sum
242 uint sum=0;
244 // Eval error for each..
245 for (uint v=0; v<height; v++)
246 for (uint u=0; u<width; u++)
248 sum += abs((sint)original[v*4+u]-(sint)unCompressed[v*4+u]);
251 // return the sum
252 return sum;
255 // ***************************************************************************
256 void CPatch::packLumelBlock (uint8 *dest, const uint8 *source, uint8 alpha0, uint8 alpha1)
258 // Precalc the height values..
259 uint8 value[8];
261 // For each value
262 uint i;
263 for (i=0; i<8; i++)
265 // Case 0 or 1 ?
266 if (alpha0>alpha1)
267 // Case 0
268 value[i]=(NL3DDecompressLumelFactor0Case0[i]*alpha0+NL3DDecompressLumelFactor1Case0[i]*alpha1)/7;
269 else
271 if (i<6)
272 value[i]=(NL3DDecompressLumelFactor0Case1[i]*alpha0+NL3DDecompressLumelFactor1Case1[i]*alpha1)/5;
273 else if (i==6)
274 value[i]=0;
275 else
276 value[i]=255;
280 // Store alpha value
281 dest[0]=alpha0;
282 dest[1]=alpha1;
284 // Clear dest codes
285 for (i=0; i<6; i++)
287 // Clear the code
288 dest[2+i]=0;
291 // For each original select the best
292 uint codeOffset=2;
293 sint codeShift=5;
294 for (i=0; i<16; i++)
296 // Best dist and code
297 uint bestDist=10000;
298 uint8 bestCode=0;
300 // Calc distance
301 for (uint code=0; code<8; code++)
303 // Distance from original value
304 uint dist=abs ((sint)(source[i])-(sint)(value[code]));
306 // The best ?
307 if (dist<bestDist)
309 // New best
310 bestDist=dist;
311 bestCode=code;
314 // Perfect, stop searching
315 if (dist==0)
316 break;
319 // Store the best
320 if (codeShift>=0)
321 dest[codeOffset]|=bestCode<<codeShift;
322 else
324 dest[codeOffset]|=bestCode>>(-codeShift);
325 dest[codeOffset+1]|=bestCode<<(8+codeShift);
329 // Next shift
330 codeShift-=3;
331 if (codeShift<=-3)
333 codeOffset++;
334 codeShift+=8;
339 // ***************************************************************************
340 void CPatch::getTileTileColors(uint ts, uint tt, CRGBA corners[4])
342 for(sint i=0;i<4;i++)
344 CTileColor &tcol= TileColors[ (tt+(i>>1))*(OrderS+1) + (ts+(i&1)) ];
345 CRGBA &col= corners[i];
346 col.set565 (tcol.Color565);
351 // ***************************************************************************
352 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
353 inline void bilinearColor(CRGBA corners[4], uint x, uint y, uint &R, uint &G, uint &B)
355 // Fast bilinear and modulate.
356 // hardcoded for 4 pixels.
357 nlassert(NL_LUMEL_BY_TILE==4);
359 // expand to be on center of pixel=> 1,3,5 or 7.
360 x= (x<<1)+1;
361 y= (y<<1)+1;
362 uint x1= 8-x;
363 uint y1= 8-y;
365 // compute weight factors.
366 uint xy= x*y;
367 uint x1y= x1*y;
368 uint xy1= x*y1;
369 uint x1y1= x1*y1;
371 // bilinear
372 // pix left top.
373 R = corners[0].R * x1y1;
374 G = corners[0].G * x1y1;
375 B = corners[0].B * x1y1;
376 // pix right top.
377 R+= corners[1].R * xy1;
378 G+= corners[1].G * xy1;
379 B+= corners[1].B * xy1;
380 // pix left bottom.
381 R+= corners[2].R * x1y;
382 G+= corners[2].G * x1y;
383 B+= corners[2].B * x1y;
384 // pix right bottom.
385 R+= corners[3].R * xy;
386 G+= corners[3].G * xy;
387 B+= corners[3].B * xy;
392 // ***************************************************************************
393 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
394 inline void bilinearColorAndModulate(CRGBA corners[4], uint x, uint y, CRGBA &res)
396 uint R, G, B;
397 bilinearColor(corners, x, y, R, G, B);
399 // modulate with input.
400 R *= res.R;
401 G *= res.G;
402 B *= res.B;
404 // R,G,B are on 14 bits
405 res.R = R >> 14;
406 res.G = G >> 14;
407 res.B = B >> 14;
411 // ***************************************************************************
412 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
413 inline void bilinearColorAndModulatex2(CRGBA corners[4], uint x, uint y, CRGBA &res)
415 uint R, G, B;
416 bilinearColor(corners, x, y, R, G, B);
418 // modulate with input.
419 R *= res.R;
420 G *= res.G;
421 B *= res.B;
423 // result not >> 14 but >> 13 and clamp from 0 to 255
424 R = R >> 13;
425 G = G >> 13;
426 B = B >> 13;
428 res.R = min (R, 255U);
429 res.G = min (G, 255U);
430 res.B = min (B, 255U);
434 // ***************************************************************************
435 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
436 inline void bilinearColorDiv2AndAdd(CRGBA corners[4], uint x, uint y, CRGBA &res)
438 uint R,G,B;
439 bilinearColor(corners, x, y, R, G, B);
441 // add with input. Resulting TLI must be on 7 bits.
442 R= (R>>7) + res.R;
443 G= (G>>7) + res.G;
444 B= (B>>7) + res.B;
446 R= min(R, 255U);
447 G= min(G, 255U);
448 B= min(B, 255U);
450 // result.
451 res.R= R;
452 res.G= G;
453 res.B= B;
457 // ***************************************************************************
458 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
459 inline void bilinearColorAndAdd(CRGBA corners[4], uint x, uint y, CRGBA &res)
461 uint R,G,B;
462 bilinearColor(corners, x, y, R, G, B);
464 // add with input. Resulting TLI must be on 7 bits.
465 R= (R>>6) + res.R;
466 G= (G>>6) + res.G;
467 B= (B>>6) + res.B;
469 R= min(R, 255U);
470 G= min(G, 255U);
471 B= min(B, 255U);
473 // result.
474 res.R= R;
475 res.G= G;
476 res.B= B;
481 // ***************************************************************************
482 void CPatch::modulateTileLightmapWithTileColors(uint ts, uint tt, CRGBA *dest, uint stride)
484 // Get the tileColors around this tile
485 CRGBA corners[4];
486 getTileTileColors(ts, tt, corners);
488 // For all lumel, bilinear.
489 uint x, y;
490 for(y=0; y<NL_LUMEL_BY_TILE; y++)
492 for(x=0; x<NL_LUMEL_BY_TILE; x++)
494 // compute this pixel, and modulate
495 bilinearColorAndModulatex2(corners, x, y, dest[y*stride + x]);
501 // ***************************************************************************
502 void CPatch::modulateTileLightmapEdgeWithTileColors(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
504 // Get the tileColors around this tile
505 CRGBA corners[4];
506 getTileTileColors(ts, tt, corners);
508 // get coordinate according to edge.
509 uint x=0,y=0;
510 switch(edge)
512 case 0: x= 0; break;
513 case 1: y= NL_LUMEL_BY_TILE-1; break;
514 case 2: x= NL_LUMEL_BY_TILE-1; break;
515 case 3: y= 0; break;
518 // For all lumel of the edge, bilinear.
519 uint i;
520 for(i=0; i<NL_LUMEL_BY_TILE; i++)
522 // if vertical edge
523 if( (edge&1)==0 ) y= i;
524 // else horizontal edge
525 else x= i;
527 // manage inverse.
528 uint where;
529 if(inverse) where= (NL_LUMEL_BY_TILE-1)-i;
530 else where= i;
531 // compute this pixel, and modulate
532 bilinearColorAndModulatex2(corners, x, y, dest[where*stride]);
537 // ***************************************************************************
538 void CPatch::modulateTileLightmapPixelWithTileColors(uint ts, uint tt, uint s, uint t, CRGBA *dest)
540 // Get the tileColors around this tile
541 CRGBA corners[4];
542 getTileTileColors(ts, tt, corners);
544 // compute this pixel, and modulate
545 bilinearColorAndModulatex2(corners, s, t, *dest);
550 // ***************************************************************************
551 void CPatch::computeTileLightmapAutomatic(uint ts, uint tt, CRGBA *dest, uint stride)
553 uint x, y;
554 for(y=0; y<NL_LUMEL_BY_TILE; y++)
556 for(x=0; x<NL_LUMEL_BY_TILE; x++)
558 // compute this pixel.
559 computeTileLightmapPixelAutomatic(ts, tt, x, y, dest+ y*stride + x);
564 // ***************************************************************************
565 void CPatch::computeTileLightmapEdgeAutomatic(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
567 // get coordinate according to edge.
568 uint x=0,y=0;
569 switch(edge)
571 case 0: x= 0; break;
572 case 1: y= NL_LUMEL_BY_TILE-1; break;
573 case 2: x= NL_LUMEL_BY_TILE-1; break;
574 case 3: y= 0; break;
577 uint i;
578 for(i=0; i<NL_LUMEL_BY_TILE; i++)
580 // if vertical edge
581 if( (edge&1)==0 ) y= i;
582 // else horizontal edge
583 else x= i;
585 // manage inverse.
586 uint where;
587 if(inverse) where= (NL_LUMEL_BY_TILE-1)-i;
588 else where= i;
589 // compute this pixel.
590 computeTileLightmapPixelAutomatic(ts, tt, x, y, dest+ where*stride);
594 // ***************************************************************************
595 void CPatch::computeTileLightmapPixelAutomatic(uint ts, uint tt, uint s, uint t, CRGBA *dest)
597 float u,v;
598 static const float lumelSize= 1.f/NL_LUMEL_BY_TILE;
600 // use 3 computeVertex to compute a normal. This is slow....
601 CVector p0, p1 ,p2;
602 // 1st vert. Top-left of the lumel.
603 u= (ts + s*lumelSize )/OrderS;
604 v= (tt + t*lumelSize )/OrderT;
605 p0= computeVertex(u, v);
606 // 2nd vert. Bottom-left of the lumel.
607 u= (ts + s*lumelSize )/OrderS;
608 v= (tt + (t+1)*lumelSize )/OrderT;
609 p1= computeVertex(u, v);
610 // 3rd vert. Center-Right of the lumel.
611 u= (ts + (s+1)*lumelSize )/OrderS;
612 v= (tt + (t+0.5f)*lumelSize )/OrderT;
613 p2= computeVertex(u, v);
615 // the normal.
616 CVector normal;
617 normal= (p1-p0)^(p2-p0);
618 normal.normalize();
620 // lighting.
621 float c= -normal*getLandscape()->getAutomaticLightDir();
622 c= max(c, 0.f);
623 sint ic;
625 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR)
626 // FastFloor using fistp. Don't care convention.
627 float fc= c*256;
628 _asm
630 fld fc
631 fistp ic
633 #else
634 ic= (sint)floor(c*256);
635 #endif
636 clamp(ic, 0, 255);
638 // ambiant/diffuse lighting.
639 *dest= getLandscape()->getStaticLight()[ic];
643 // ***************************************************************************
644 void CPatch::getTileLumelmapPrecomputed(uint ts, uint tt, uint8 *dest, uint stride)
646 // Unpack the lumels
647 uint8 buffer[NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE];
648 unpackLumelBlock (buffer, &(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]));
650 // Retrun it
651 uint x, y;
652 for(y=0; y<NL_LUMEL_BY_TILE; y++)
654 for(x=0; x<NL_LUMEL_BY_TILE; x++)
656 // lumel
657 dest[y*stride + x]= buffer[x+(y<<NL_LUMEL_BY_TILE_SHIFT)];
663 // ***************************************************************************
664 void CPatch::getTileLumelmapPixelPrecomputed(uint ts, uint tt, uint s, uint t, uint8 &dest) const
666 // Return the lumel
667 dest= getUnpackLumelBlock (&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]), s+(t<<2));
671 // ***************************************************************************
672 void CPatch::computeTileLightmapPrecomputed(uint ts, uint tt, CRGBA *dest, uint stride)
674 // Lumel table
675 const CRGBA* colorTable=getLandscape ()->getStaticLight ();
676 // Unpack the lumels
677 uint8 buffer[NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE];
678 unpackLumelBlock (buffer, &(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]));
680 // Retrun it
681 uint x, y;
682 for(y=0; y<NL_LUMEL_BY_TILE; y++)
684 for(x=0; x<NL_LUMEL_BY_TILE; x++)
686 // lumel
687 dest[y*stride + x]=colorTable[buffer[x+(y<<NL_LUMEL_BY_TILE_SHIFT)]];
692 // ***************************************************************************
694 static uint NL3DPixelStartLumel[4]={0, 4*3, 3, 0};
695 static uint NL3DDeltaLumel[4]={4, 1, 4, 1};
697 // ***************************************************************************
698 void CPatch::computeTileLightmapEdgePrecomputed(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
700 // Lumel table
701 const CRGBA* colorTable=getLandscape ()->getStaticLight ();
703 // Witch corner to start ?
704 uint pixel=NL3DPixelStartLumel[edge];
705 uint delta=NL3DDeltaLumel[edge];
707 // For each lumels
708 const uint8 *src=&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]);
709 uint x;
710 if (inverse)
712 uint inverseStride=stride*(4-1);
713 for(x=0; x<4; x++)
715 // lumel
716 dest[inverseStride-x*stride]=colorTable[getUnpackLumelBlock (src, pixel)];
717 pixel+=delta;
720 else
722 for(x=0; x<4; x++)
724 // lumel
725 dest[x*stride]=colorTable[getUnpackLumelBlock (src, pixel)];
726 pixel+=delta;
731 // ***************************************************************************
732 void CPatch::computeTileLightmapPixelPrecomputed(uint ts, uint tt, uint s, uint t, CRGBA *dest)
734 // Lumel table
735 const CRGBA* colorTable=getLandscape ()->getStaticLight ();
737 // Return the lumel
738 *dest=colorTable[getUnpackLumelBlock (&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]), s+(t<<2))];
743 // ***************************************************************************
744 void CPatch::computeTileLightmap(uint ts, uint tt, CRGBA *dest, uint stride)
746 if(getLandscape()->getAutomaticLighting())
747 computeTileLightmapAutomatic(ts, tt, dest, stride);
748 else
750 computeTileLightmapPrecomputed(ts, tt, dest, stride);
751 // Add the inlufence of TLI.
752 addTileLightmapWithTLI(ts, tt, dest, stride);
755 // modulate dest with tileColors (at center of lumels).
756 modulateTileLightmapWithTileColors(ts, tt, dest, stride);
758 // ***************************************************************************
759 void CPatch::computeTileLightmapEdge(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
761 if(getLandscape()->getAutomaticLighting())
762 computeTileLightmapEdgeAutomatic(ts, tt, edge, dest, stride, inverse);
763 else
765 computeTileLightmapEdgePrecomputed(ts, tt, edge, dest, stride, inverse);
766 // Add the inlufence of TLI.
767 addTileLightmapEdgeWithTLI(ts, tt, edge, dest, stride, inverse);
770 // modulate dest with tileColors (at center of lumels).
771 modulateTileLightmapEdgeWithTileColors(ts, tt, edge, dest, stride, inverse);
775 // ***************************************************************************
776 void CPatch::computeTileLightmapPixel(uint ts, uint tt, uint s, uint t, CRGBA *dest)
778 if(getLandscape()->getAutomaticLighting())
779 computeTileLightmapPixelAutomatic(ts, tt, s, t, dest);
780 else
782 computeTileLightmapPixelPrecomputed(ts, tt, s, t, dest);
783 // Add the inlufence of TLI.
784 addTileLightmapPixelWithTLI(ts, tt, s, t, dest);
787 // modulate dest with tileColors (at center of lumels).
788 modulateTileLightmapPixelWithTileColors(ts, tt, s, t, dest);
792 // ***************************************************************************
793 void CPatch::computeTileLightmapPixelAroundCorner(const CVector2f &stIn, CRGBA *dest, bool lookAround)
795 bool mustLookOnNeighbor= false;
797 // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis).
798 sint u, v;
799 u= (sint)floor(stIn.x*NL_LUMEL_BY_TILE);
800 v= (sint)floor(stIn.y*NL_LUMEL_BY_TILE);
802 // if allowed, try to go on neighbor patch.
803 if(lookAround)
805 // try to know if we must go on a neighbor patch (maybe false with bind X/1).
806 if( u<0 || u>=OrderS*NL_LUMEL_BY_TILE || v<0 || v>=OrderT*NL_LUMEL_BY_TILE)
807 mustLookOnNeighbor= true;
811 // If we must get (if possible) the pixel in the current patch, do it.
812 if(!mustLookOnNeighbor)
814 // if out this patch, abort.
815 if( u<0 || u>=OrderS*NL_LUMEL_BY_TILE || v<0 || v>=OrderT*NL_LUMEL_BY_TILE)
816 return;
817 else
819 // get this pixel.
820 computeTileLightmapPixel(u>>NL_LUMEL_BY_TILE_SHIFT, v>>NL_LUMEL_BY_TILE_SHIFT, u&(NL_LUMEL_BY_TILE-1), v&(NL_LUMEL_BY_TILE-1), dest);
823 // else get from the best neighbor patch.
824 else
826 // choose against which edge we must find the pixel.
827 uint edge=0;
828 if(u<0) edge=0;
829 else if(v>=OrderT*NL_LUMEL_BY_TILE) edge=1;
830 else if(u>=OrderS*NL_LUMEL_BY_TILE) edge=2;
831 else if(v<0) edge=3;
833 // retrieve info on neighbor.
834 CBindInfo bindInfo;
835 getBindNeighbor(edge, bindInfo);
837 // if neighbor present.
838 if(bindInfo.Zone)
840 CVector2f stOut;
841 CPatch *patchOut;
842 uint patchId;
844 // Ok, search uv on this patch.
845 CPatchUVLocator uvLocator;
846 uvLocator.build(this, edge, bindInfo);
847 patchId= uvLocator.selectPatch(stIn);
848 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
850 // retry only one time, so at next call, must find the data IN htis patch (else abort).
851 patchOut->computeTileLightmapPixelAroundCorner(stOut, dest, false);
857 // ***************************************************************************
858 void CPatch::computeNearBlockLightmap(uint uts, uint utt, CRGBA *lightText)
860 sint ts= uts;
861 sint tt= utt;
863 // hardcoded for 10x10.
864 nlassert(NL_TILE_LIGHTMAP_SIZE==10);
865 CRGBA *dest;
866 uint edge;
867 uint corner;
869 // Compute center of the TessBlock: the 2x2 tiles.
870 //=================
871 // compute tile 0,0 of the tessBlock. must decal of 1 pixel.
872 dest= lightText+NL_TILE_LIGHTMAP_SIZE+1;
873 computeTileLightmap(ts, tt, dest, NL_TILE_LIGHTMAP_SIZE);
874 // compute tile 1,0 of the tessBlock. must decal of 1 pixel.
875 dest= lightText + NL_LUMEL_BY_TILE + NL_TILE_LIGHTMAP_SIZE+1 ;
876 computeTileLightmap(ts+1, tt, dest, NL_TILE_LIGHTMAP_SIZE);
877 // compute tile 0,1 of the tessBlock. must decal of 1 pixel.
878 dest= lightText + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE + NL_TILE_LIGHTMAP_SIZE+1 ;
879 computeTileLightmap(ts, tt+1, dest, NL_TILE_LIGHTMAP_SIZE);
880 // compute tile 1,1 of the tessBlock. must decal of 1 pixel.
881 dest= lightText + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE + NL_LUMEL_BY_TILE + NL_TILE_LIGHTMAP_SIZE+1 ;
882 computeTileLightmap(ts+1, tt+1, dest, NL_TILE_LIGHTMAP_SIZE);
885 // Compute edges of the TessBlock.
886 //=================
887 bool edgeBorder[4];
888 // where are we on a border of a patch??
889 edgeBorder[0]= ( ts==0 );
890 edgeBorder[1]= ( tt == OrderT-2 );
891 edgeBorder[2]= ( ts == OrderS-2 );
892 edgeBorder[3]= ( tt==0 );
894 // For all edges.
895 for(edge=0; edge<4; edge++)
897 // compute dest info.
898 //==============
899 // Are we on a vertical edge or horizontal edge??
900 uint stride= (edge&1)==0? NL_TILE_LIGHTMAP_SIZE : 1;
902 // must compute on which tile we must find info.
903 sint decalS=0;
904 sint decalT=0;
905 // and must compute ptr, where we store the result of the edge.
906 switch(edge)
908 case 0: decalS=-1; dest= lightText + 0 + NL_TILE_LIGHTMAP_SIZE; break;
909 case 1: decalT= 2; dest= lightText + 1 + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
910 case 2: decalS= 2; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + NL_TILE_LIGHTMAP_SIZE; break;
911 case 3: decalT=-1; dest= lightText + 1; break;
914 // compute the second tile dest info.
915 CRGBA *dest2;
916 sint decalS2;
917 sint decalT2;
918 // if vertical edge.
919 if((edge&1)==0)
921 // Next Y tile.
922 dest2= dest + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE;
923 decalS2= decalS;
924 decalT2= decalT+1;
926 else
928 // Next X tile.
929 dest2= dest + NL_LUMEL_BY_TILE;
930 decalS2= decalS+1;
931 decalT2= decalT;
935 // If we are not on a border of a patch, just compute on the interior of the patch.
936 //==============
937 if(!edgeBorder[edge])
939 // find the result on the mirrored border of us. First tile.
940 computeTileLightmapEdge(ts+decalS, tt+decalT, (edge+2)&3, dest, stride, false);
942 // find the result on the mirrored border of us. Second Tile.
943 computeTileLightmapEdge(ts+decalS2, tt+decalT2, (edge+2)&3, dest2, stride, false);
946 // else, slightly complicated, must find the result on neighbor patch(s).
947 //==============
948 else
950 CPatchUVLocator uvLocator;
951 CBindInfo bindInfo;
952 bindInfo.Zone= NULL;
954 // if smoothed edge, search the neighbor.
955 if(getSmoothFlag(edge))
957 // Build the bindInfo against this edge.
958 getBindNeighbor(edge, bindInfo);
960 // if ok, build the uv info against this edge.
961 if(bindInfo.Zone)
963 uvLocator.build(this, edge, bindInfo);
964 // if there is not same tile order across the edge, invalidate the smooth.
965 // This is rare, so don't bother.
966 if(!uvLocator.sameEdgeOrder())
967 bindInfo.Zone= NULL;
972 // Fast reject: if no neighbor, or if not smoothed, or if edge order pb, just copy from my interior.
973 if(!bindInfo.Zone)
975 CRGBA *src=0;
976 switch(edge)
978 case 0: src= dest + 1; break;
979 case 1: src= dest - NL_TILE_LIGHTMAP_SIZE; break;
980 case 2: src= dest - 1; break;
981 case 3: src= dest + NL_TILE_LIGHTMAP_SIZE; break;
984 // fill the NL_LUMEL_BY_TILE*2 (8) pixels.
985 for(uint n=NL_LUMEL_BY_TILE*2; n>0; n--, src+=stride, dest+=stride)
986 *dest= *src;
988 // else, ok, get from neighbor.
989 else
991 CVector2f stIn, stOut;
992 CPatch *patchOut;
993 uint patchId;
994 uint edgeOut;
995 bool inverse;
997 // First Tile.
998 //=========
999 // to remove floor pbs, take the center of the wanted tile.
1000 stIn.set(ts+decalS + 0.5f, tt+decalT + 0.5f);
1001 patchId= uvLocator.selectPatch(stIn);
1002 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
1003 // must find what edge on neighbor to compute, and if we must inverse (swap) result.
1004 // easy: the edge of the tile is the edge of the patch where we are binded.
1005 edgeOut= bindInfo.Edge[patchId];
1006 // edge0 is oriented in T increasing order. edge1 is oriented in S increasing order.
1007 // edge2 is oriented in T decreasing order. edge3 is oriented in S decreasing order.
1008 // inverse is true if same sens on both edges (because of mirroring, sens should be different).
1009 inverse= (edge>>1)==(edgeOut>>1);
1010 // compute the lightmap on the edge of the neighbor.
1011 patchOut->computeTileLightmapEdge((sint)floor(stOut.x), (sint)floor(stOut.y), edgeOut, dest, stride, inverse);
1013 // Second Tile.
1014 //=========
1015 // same reasoning.
1016 stIn.set(ts+decalS2 + 0.5f, tt+decalT2 + 0.5f);
1017 patchId= uvLocator.selectPatch(stIn);
1018 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
1019 edgeOut= bindInfo.Edge[patchId];
1020 inverse= (edge>>1)==(edgeOut>>1);
1021 patchOut->computeTileLightmapEdge((sint)floor(stOut.x), (sint)floor(stOut.y), edgeOut, dest2, stride, inverse);
1028 // Compute corners of the TessBlock.
1029 //=================
1030 bool cornerOnPatchEdge[4];
1031 bool cornerOnPatchCorner[4];
1032 // where are we on a edge border of a patch??
1033 cornerOnPatchEdge[0]= edgeBorder[3] != edgeBorder[0];
1034 cornerOnPatchEdge[1]= edgeBorder[0] != edgeBorder[1];
1035 cornerOnPatchEdge[2]= edgeBorder[1] != edgeBorder[2];
1036 cornerOnPatchEdge[3]= edgeBorder[2] != edgeBorder[3];
1037 // where are we on a corner border of a patch??
1038 cornerOnPatchCorner[0]= edgeBorder[3] && edgeBorder[0];
1039 cornerOnPatchCorner[1]= edgeBorder[0] && edgeBorder[1];
1040 cornerOnPatchCorner[2]= edgeBorder[1] && edgeBorder[2];
1041 cornerOnPatchCorner[3]= edgeBorder[2] && edgeBorder[3];
1043 // For all corners.
1044 for(corner=0; corner<4; corner++)
1046 // compute dest info.
1047 //==============
1048 // must compute on which tile we must find info.
1049 sint decalS=0;
1050 sint decalT=0;
1051 // and must compute ptr, where we store the result of the corner.
1052 switch(corner)
1054 case 0: decalS=-1; decalT=-1; dest= lightText + 0 + 0; break;
1055 case 1: decalS=-1; decalT= 2; dest= lightText + 0 + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
1056 case 2: decalS= 2; decalT= 2; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
1057 case 3: decalS= 2; decalT=-1; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + 0; break;
1061 // If we are not on a border of a patch, just compute on the interior of the patch.
1062 //==============
1063 // if the corner is IN the patch.
1064 if(!cornerOnPatchCorner[corner] && !cornerOnPatchEdge[corner])
1066 // what pixel to read.
1067 uint subS, subT;
1068 if(decalS==-1) subS= NL_LUMEL_BY_TILE-1;
1069 else subS= 0;
1070 if(decalT==-1) subT= NL_LUMEL_BY_TILE-1;
1071 else subT= 0;
1073 // find the result on the corner of the neighbor tile.
1074 computeTileLightmapPixel(ts+decalS, tt+decalT, subS, subT, dest);
1076 else
1078 // By default, fill the corner with our interior corner. Because other methods may fail.
1079 CRGBA *src=0;
1080 switch(corner)
1082 case 0: src= dest + 1 + NL_TILE_LIGHTMAP_SIZE; break;
1083 case 1: src= dest + 1 - NL_TILE_LIGHTMAP_SIZE; break;
1084 case 2: src= dest - 1 - NL_TILE_LIGHTMAP_SIZE; break;
1085 case 3: src= dest - 1 + NL_TILE_LIGHTMAP_SIZE; break;
1088 // fill the pixel.
1089 *dest= *src;
1091 // get the coordinate of the corner, in our [0,Order] basis. get it at the center of the pixel.
1092 CBindInfo bindInfo;
1093 CPatchUVLocator uvLocator;
1094 CVector2f stIn, stOut;
1095 CPatch *patchOut;
1096 uint patchId;
1097 float decX, decY;
1098 static const float lumelSize= 1.f/NL_LUMEL_BY_TILE;
1099 static const float semiLumelSize= 0.5f*lumelSize;
1101 if(decalS==-1) decX= - semiLumelSize;
1102 else decX= 2+ semiLumelSize;
1103 if(decalT==-1) decY= - semiLumelSize;
1104 else decY= 2+ semiLumelSize;
1105 stIn.set( ts+decX, tt+decY);
1108 // if the corner is on One edge only of the patch.
1109 if(cornerOnPatchEdge[corner])
1111 // find the edge where to read this corner: hard edge after or before this corner.
1112 if(edgeBorder[corner]) edge= corner;
1113 else edge= (corner+4-1) & 3;
1115 // if this edge is smoothed, find on neighbor.
1116 if(getSmoothFlag(edge))
1118 // retrieve neigbhor info.
1119 getBindNeighbor(edge, bindInfo);
1121 // if neighbor present.
1122 if(bindInfo.Zone)
1124 // Ok, search uv on this patch.
1125 uvLocator.build(this, edge, bindInfo);
1126 patchId= uvLocator.selectPatch(stIn);
1127 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
1129 // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis), and get from neighbor patch
1130 sint u, v;
1131 u= (sint)floor(stOut.x*NL_LUMEL_BY_TILE);
1132 v= (sint)floor(stOut.y*NL_LUMEL_BY_TILE);
1133 patchOut->computeTileLightmapPixel(u>>NL_LUMEL_BY_TILE_SHIFT, v>>NL_LUMEL_BY_TILE_SHIFT, u&(NL_LUMEL_BY_TILE-1), v&(NL_LUMEL_BY_TILE-1), dest);
1136 // else we must still smooth with our lumel on this patch, so get it from neighbor on edge.
1137 else
1139 // first, clamp to our patch (recenter on the previous pixel)
1140 if(stIn.x<0) stIn.x+= lumelSize;
1141 else if(stIn.x>OrderS) stIn.x-= lumelSize;
1142 else if(stIn.y<0) stIn.y+= lumelSize;
1143 else if(stIn.y>OrderT) stIn.y-= lumelSize;
1145 // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis), and get from this patch
1146 sint u, v;
1147 u= (sint)floor(stIn.x*NL_LUMEL_BY_TILE);
1148 v= (sint)floor(stIn.y*NL_LUMEL_BY_TILE);
1149 computeTileLightmapPixel(u>>NL_LUMEL_BY_TILE_SHIFT, v>>NL_LUMEL_BY_TILE_SHIFT, u&(NL_LUMEL_BY_TILE-1), v&(NL_LUMEL_BY_TILE-1), dest);
1152 // else it is on a corner of the patch.
1153 else
1155 // if the corner of the patch (same as tile corner) is smoothed, find on neighbor
1156 if(getCornerSmoothFlag(corner))
1158 // retrieve neigbhor info. NB: use edgeId=corner, (corner X is the start of the edge X)it works.
1159 getBindNeighbor(corner, bindInfo);
1161 // if neighbor present.
1162 if(bindInfo.Zone)
1164 // Ok, search uv on this patch.
1165 uvLocator.build(this, corner, bindInfo);
1166 patchId= uvLocator.selectPatch(stIn);
1167 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
1169 // same reasoning as in computeDisplaceCornerSmooth(), must find the pixel on the neighbor
1170 // of our neighbor. But the current corner may be a corner on a bind X/1. All is managed by doing
1171 // this way.
1172 patchOut->computeTileLightmapPixelAroundCorner(stOut, dest, true);
1184 // ***************************************************************************
1185 void CPatch::getTileLightMap(uint ts, uint tt, CPatchRdrPass *&rdrpass)
1187 // TessBlocks must have been allocated.
1188 nlassert(TessBlocks.size()!=0);
1190 // get what tessBlock to use.
1191 uint numtb, numtm;
1192 computeTbTm(numtb, numtm, ts, tt);
1193 CTessBlock &tessBlock= TessBlocks[numtb];
1195 // If the lightmap Id has not been computed, compute it.
1196 if(tessBlock.LightMapRefCount==0)
1198 // Compute the lightmap texture, with help of TileColors, with neighboring info etc...
1199 CRGBA lightText[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE];
1200 computeNearBlockLightmap(ts&(~1), tt&(~1), lightText);
1202 // Create a rdrPass with this texture, donlod to Driver etc...
1203 tessBlock.LightMapId= Zone->Landscape->getTileLightMap(lightText, rdrpass);
1205 // store this rdrpass ptr.
1206 tessBlock.LightMapRdrPass= rdrpass;
1209 // We are using this 2x2 tiles lightmap.
1210 tessBlock.LightMapRefCount++;
1213 // get the rdrpass ptr of the tessBlock lightmap
1214 rdrpass= tessBlock.LightMapRdrPass;
1218 // ***************************************************************************
1219 void CPatch::getTileLightMapUvInfo(uint ts, uint tt, CVector &uvScaleBias)
1221 // TessBlocks must have been allocated.
1222 nlassert(TessBlocks.size()!=0);
1224 // get what tessBlock to use.
1225 uint numtb, numtm;
1226 computeTbTm(numtb, numtm, ts, tt);
1227 CTessBlock &tessBlock= TessBlocks[numtb];
1229 // Get the uvScaleBias for the tile 0,0 of the block.
1230 Zone->Landscape->getTileLightMapUvInfo(tessBlock.LightMapId, uvScaleBias);
1232 // Must increment the bias, for the good tile in the 2x2 block Lightmap.
1233 uint tsDec= ts & 1;
1234 uint ttDec= tt & 1;
1235 uvScaleBias.x+= tsDec * uvScaleBias.z;
1236 uvScaleBias.y+= ttDec * uvScaleBias.z;
1240 // ***************************************************************************
1241 void CPatch::releaseTileLightMap(uint ts, uint tt)
1243 // TessBlocks must have been allocated.
1244 nlassert(TessBlocks.size()!=0);
1246 // get what tessBlock to use.
1247 uint numtb, numtm;
1248 computeTbTm(numtb, numtm, ts, tt);
1249 CTessBlock &tessBlock= TessBlocks[numtb];
1251 // If no more tileMaterial use this lightmap, release it.
1252 nlassert(tessBlock.LightMapRefCount>0);
1253 tessBlock.LightMapRefCount--;
1254 if(tessBlock.LightMapRefCount==0)
1256 Zone->Landscape->releaseTileLightMap(tessBlock.LightMapId);
1260 // ***************************************************************************
1261 void CPatch::packShadowMap (const uint8 *pLumelSrc)
1263 // Number of lumel by lines
1264 uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
1266 // Number of block in a line
1267 nlassert ((lumelCount&0x3)==0);
1268 uint numLumelBlock=lumelCount>>2;
1270 // Number of line
1271 uint lineCount=OrderT*NL_LUMEL_BY_TILE;
1273 // Number of block line
1274 nlassert ((lineCount&0x3)==0);
1275 uint numLineBlock=lineCount>>2;
1277 // Resize the compressed buffer
1278 CompressedLumels.resize (numLumelBlock*numLineBlock*NL_BLOCK_LUMEL_COMPRESSED_SIZE);
1280 // Input of compresed data
1281 uint8 *compressedData=&CompressedLumels[0];
1283 // Each line block
1284 for (uint lineBlock=0; lineBlock<numLineBlock; lineBlock++)
1286 // Block pointer
1287 const uint8 *blockLine=pLumelSrc;
1289 // Each lumel block
1290 for (uint lumelBlock=0; lumelBlock<numLumelBlock; lumelBlock++)
1292 // *** Unpack the block
1293 uint countU;
1295 // Last block ?
1296 if (lumelBlock==numLumelBlock-1)
1297 countU=lumelCount&3;
1298 else
1299 countU=4;
1301 // Destination lumel
1302 const uint8 *blockSrc=blockLine;
1304 // Temp block
1305 uint8 originalBlock[4*4];
1307 // Copy the lumels in the bloc
1308 for (uint v=0; v<NL_LUMEL_BY_TILE; v++)
1310 for (uint u=0; u<NL_LUMEL_BY_TILE; u++)
1312 // Copy the lumel
1313 originalBlock[(v<<2)+u]=blockSrc[u];
1316 // Next line
1317 blockSrc+=lumelCount;
1320 // Get min and max alpha
1321 uint8 alphaMin=255;
1322 uint8 alphaMax=0;
1324 // Scan
1325 for (uint i=0; i<16; i++)
1327 // Min ?
1328 if (originalBlock[i]<alphaMin)
1329 alphaMin=originalBlock[i];
1330 if (originalBlock[i]>alphaMax)
1331 alphaMax=originalBlock[i];
1334 // *** Try to compress by 2 methods
1336 // Blcok uncompressed
1337 uint8 uncompressedBlock[4*4];
1339 // Pack the block
1340 packLumelBlock (compressedData, originalBlock, alphaMin, alphaMax);
1342 // Unpack the block
1343 unpackLumelBlock (uncompressedBlock, compressedData);
1345 // Eval error
1346 uint firstMethod=evalLumelBlock (originalBlock, uncompressedBlock, NL_LUMEL_BY_TILE, NL_LUMEL_BY_TILE);
1348 // second compression
1349 uint8 secondCompressedBlock[NL_BLOCK_LUMEL_COMPRESSED_SIZE];
1350 packLumelBlock (secondCompressedBlock, originalBlock, alphaMax, alphaMin);
1352 // Unpack the block
1353 unpackLumelBlock (uncompressedBlock, secondCompressedBlock);
1355 // Eval error
1356 uint secondMethod=evalLumelBlock (originalBlock, uncompressedBlock, NL_LUMEL_BY_TILE, NL_LUMEL_BY_TILE);
1358 // Second best ?
1359 if (secondMethod<firstMethod)
1361 // Copy compressed data
1362 memcpy (compressedData, secondCompressedBlock, NL_BLOCK_LUMEL_COMPRESSED_SIZE);
1365 // Next source block
1366 compressedData+=NL_BLOCK_LUMEL_COMPRESSED_SIZE;
1368 // Next block on the line
1369 blockLine+=4;
1372 // Next line of block
1373 pLumelSrc+=lumelCount*4;
1377 // ***************************************************************************
1378 void CPatch::resetCompressedLumels ()
1380 // Number of lumel by lines
1381 uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
1383 // Number of block in a line
1384 nlassert ((lumelCount&0x3)==0);
1385 uint numLumelBlock=lumelCount>>2;
1387 // Number of line
1388 uint lineCount=OrderT*NL_LUMEL_BY_TILE;
1390 // Number of block line
1391 nlassert ((lineCount&0x3)==0);
1392 uint numLineBlock=lineCount>>2;
1394 // Size of the lumel array
1395 uint size=numLineBlock*numLumelBlock*8;
1397 // 4 bits per lumel
1398 CompressedLumels.resize (size);
1400 // No line have shadows.
1401 memset (&CompressedLumels[0], 0, size);
1405 // ***************************************************************************
1406 // ***************************************************************************
1407 // Functions (C/ASM).
1408 // ***************************************************************************
1409 // ***************************************************************************
1412 // ***************************************************************************
1413 #define a00 tex[0]
1414 #define a10 tex[1]
1415 #define a20 tex[2]
1416 #define a30 tex[3]
1417 #define a40 tex[4]
1419 #define a01 tex[5]
1420 #define a11 tex[6]
1421 #define a21 tex[7]
1422 #define a31 tex[8]
1423 #define a41 tex[9]
1425 #define a02 tex[10]
1426 #define a12 tex[11]
1427 #define a22 tex[12]
1428 #define a32 tex[13]
1429 #define a42 tex[14]
1431 #define a03 tex[15]
1432 #define a13 tex[16]
1433 #define a23 tex[17]
1434 #define a33 tex[18]
1435 #define a43 tex[19]
1437 #define a04 tex[20]
1438 #define a14 tex[21]
1439 #define a24 tex[22]
1440 #define a34 tex[23]
1441 #define a44 tex[24]
1443 void NL3D_bilinearTileLightMap(CRGBA *tex)
1445 // Fast bilinear of a 5x5 tile.
1446 // Corners must be set.
1447 // Later: pass it to ASM.
1449 // Fill first column 0 and column 4.
1450 a02.avg2(a00, a04);
1451 a01.avg2(a00, a02);
1452 a03.avg2(a02, a04);
1453 a42.avg2(a40, a44);
1454 a41.avg2(a40, a42);
1455 a43.avg2(a42, a44);
1457 // Fill Line 0.
1458 a20.avg2(a00, a40);
1459 a10.avg2(a00, a20);
1460 a30.avg2(a20, a40);
1462 // Fill Line 1.
1463 a21.avg2(a01, a41);
1464 a11.avg2(a01, a21);
1465 a31.avg2(a21, a41);
1467 // Fill Line 2.
1468 a22.avg2(a02, a42);
1469 a12.avg2(a02, a22);
1470 a32.avg2(a22, a42);
1472 // Fill Line 3.
1473 a23.avg2(a03, a43);
1474 a13.avg2(a03, a23);
1475 a33.avg2(a23, a43);
1477 // Fill Line 4.
1478 a24.avg2(a04, a44);
1479 a14.avg2(a04, a24);
1480 a34.avg2(a24, a44);
1485 // ***************************************************************************
1486 // ***************************************************************************
1487 // Lightmap get interface.
1488 // ***************************************************************************
1489 // ***************************************************************************
1492 // ***************************************************************************
1493 uint8 CPatch::getLumel(const CUV &uv) const
1495 // compute tile coord and lumel coord.
1496 sint ts, tt;
1497 // get in lumel coord.
1498 sint w= (OrderS<<NL_LUMEL_BY_TILE_SHIFT);
1499 sint h= (OrderT<<NL_LUMEL_BY_TILE_SHIFT);
1500 // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
1501 // add 128, to round and get cneter of lumel.
1502 ts= NLMISC::OptFastFloor(uv.U* (w<<8) + 128); ts>>=8;
1503 tt= NLMISC::OptFastFloor(uv.V* (h<<8) + 128); tt>>=8;
1504 clamp(ts, 0, w-1);
1505 clamp(tt, 0, h-1);
1506 // get the lumel
1507 uint8 ret;
1508 getTileLumelmapPixelPrecomputed(ts>>NL_LUMEL_BY_TILE_SHIFT, tt>>NL_LUMEL_BY_TILE_SHIFT,
1509 ts&(NL_LUMEL_BY_TILE-1), tt&(NL_LUMEL_BY_TILE-1), ret);
1511 return ret;
1515 // ***************************************************************************
1516 // ***************************************************************************
1517 // TileLightInfluences
1518 // ***************************************************************************
1519 // ***************************************************************************
1522 // ***************************************************************************
1523 void CPatch::resetTileLightInfluences()
1525 // Fill default.
1526 TileLightInfluences.resize((OrderS/2 +1) * (OrderT/2 +1));
1527 // Disable All light influence on all points
1528 for(uint i=0;i <TileLightInfluences.size(); i++)
1530 // Disable all light influence on this point.
1531 TileLightInfluences[i].Light[0]= 0xFF;
1532 TileLightInfluences[i].Light[1]= 0xFF;
1537 // ***************************************************************************
1538 void CPatch::appendTileLightInfluences(const CUV &uv,
1539 std::vector<CPointLightInfluence> &pointLightList) const
1542 WARNING !! only CPointLightNamed must be added here (used for convenience by CPatch::generateTileVegetable() )
1545 // Compute TLI coord for BiLinear.
1546 sint x,y;
1547 // There is (OrderS/2+1) * (OrderT/2+1) tileLightInfluences (TLI).
1548 sint w= (OrderS>>1);
1549 sint h= (OrderT>>1);
1550 sint wTLI= w+1;
1551 // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
1552 x= NLMISC::OptFastFloor(uv.U * (w<<8));
1553 y= NLMISC::OptFastFloor(uv.V * (h<<8));
1554 clamp(x, 0, w<<8);
1555 clamp(y, 0, h<<8);
1556 // compute the TLI coord, and the subCoord for bilinear.
1557 sint xTLI,yTLI, xSub, ySub;
1558 xTLI= x>>8; clamp(xTLI, 0, w-1);
1559 yTLI= y>>8; clamp(yTLI, 0, h-1);
1560 // Hence, xSub and ySub range is [0, 256].
1561 xSub= x - (xTLI<<8);
1562 ySub= y - (yTLI<<8);
1565 // Use a CLightInfluenceInterpolator to biLinear light influence
1566 CLightInfluenceInterpolator interp;
1567 // Must support only 2 light per TLI.
1568 nlassert(CTileLightInfluence::NumLightPerCorner==2);
1569 nlassert(CLightInfluenceInterpolator::NumLightPerCorner==2);
1570 // Get ref on array of PointLightNamed.
1571 CPointLightNamed *zonePointLights= NULL;
1572 if( getZone()->_PointLightArray.getPointLights().size() >0 )
1574 // const_cast, because will only change _IdInfluence, and
1575 // also because CLightingManager will call appendLightedModel()
1576 zonePointLights= const_cast<CPointLightNamed*>(&(getZone()->_PointLightArray.getPointLights()[0]));
1578 // For 4 corners.
1579 for(y=0;y<2;y++)
1581 for(x=0;x<2;x++)
1583 // get ref on TLI, and on corner.
1584 const CTileLightInfluence &tli= TileLightInfluences[ (yTLI+y)*wTLI + xTLI+x ];
1585 CLightInfluenceInterpolator::CCorner &corner= interp.Corners[y*2 + x];
1586 // For all lights
1587 uint lid;
1588 for(lid= 0; lid<CTileLightInfluence::NumLightPerCorner; lid++)
1590 // get the id of the light in the zone
1591 uint tliLightId= tli.Light[lid];
1592 // If empty id, stop
1593 if(tliLightId==0xFF)
1594 break;
1595 else
1597 // Set pointer of the light in the corner
1598 corner.Lights[lid]= zonePointLights + tliLightId;
1601 // Reset Empty slots.
1602 for(; lid<CTileLightInfluence::NumLightPerCorner; lid++)
1604 // set to NULL
1605 corner.Lights[lid]= NULL;
1609 // interpolate.
1610 interp.interpolate(pointLightList, xSub/256.f, ySub/256.f);
1614 // ***************************************************************************
1615 CRGBA CPatch::getCurrentTLIColor(uint x, uint y) const
1617 CRGBA ret;
1618 ret= CRGBA::Black;
1620 // if at least the zone has pointLights, add them.
1621 if( getZone()->_PointLightArray.getPointLights().size() >0 )
1623 const CPointLightNamed *zonePointLights;
1624 zonePointLights= (&(getZone()->_PointLightArray.getPointLights()[0]));
1626 uint wTLI= (OrderS>>1)+1;
1628 const CTileLightInfluence &tli= TileLightInfluences[ y*wTLI + x];
1629 for(uint lid=0;lid<CTileLightInfluence::NumLightPerCorner;lid++)
1631 // Not influenced by a pointLight?, stop
1632 if(tli.Light[lid]==0xFF)
1633 break;
1634 // Append the influence of this pointLight. NB: use unanimated version.
1635 CRGBA lightCol= zonePointLights[tli.Light[lid]].getUnAnimatedDiffuse();
1636 // modulate with landscape Material.
1637 lightCol.modulateFromColorRGBOnly(lightCol, getLandscape()->getPointLightDiffuseMaterial() );
1638 // modulate with precomputed diffuse factor
1639 lightCol.modulateFromuiRGBOnly(lightCol, tli.getDiffuseLightFactor(lid) );
1640 // add to the corner
1641 ret.addRGBOnly(ret, lightCol);
1645 return ret;
1649 // ***************************************************************************
1650 void CPatch::getCurrentTileTLIColors(uint ts, uint tt, NLMISC::CRGBA corners[4])
1652 // Get ref on array of PointLightNamed.
1653 if( getZone()->_PointLightArray.getPointLights().size() >0 )
1655 // get coord of the tessBlock
1656 uint tbs= ts>>1;
1657 uint tbt= tt>>1;
1658 // get tile id local to tessBlock.
1659 uint tls= ts-(tbs<<1);
1660 uint tlt= tt-(tbt<<1);
1662 // For each corner of the tessBlock, compute lighting with pointLights.
1663 CRGBA tbCorners[4];
1664 for(uint y=0;y<2;y++)
1666 for(uint x=0;x<2;x++)
1668 CRGBA &cornerCol= tbCorners[y*2+x];
1669 cornerCol= getCurrentTLIColor(tbs+x, tbt+y);
1673 // Then biLinear to tile Level (tessBlock==2x2 tiles).
1674 CRGBA tbEdges[4];
1675 CRGBA tbMiddle;
1676 // left.
1677 tbEdges[0].avg2RGBOnly(tbCorners[0], tbCorners[2]);
1678 tbEdges[0].A = 255;
1679 // bottom
1680 tbEdges[1].avg2RGBOnly(tbCorners[2], tbCorners[3]);
1681 tbEdges[1].A = 255;
1682 // right
1683 tbEdges[2].avg2RGBOnly(tbCorners[1], tbCorners[3]);
1684 tbEdges[2].A = 255;
1685 // up
1686 tbEdges[3].avg2RGBOnly(tbCorners[0], tbCorners[1]);
1687 tbEdges[3].A = 255;
1688 // middle.
1689 tbMiddle.avg2RGBOnly(tbEdges[0], tbEdges[2]);
1690 tbMiddle.A = 255;
1692 // just copy result according to tile pos in tessBlock.
1693 if(tlt==0)
1695 if(tls==0)
1697 corners[0]= tbCorners[0];
1698 corners[1]= tbEdges[3];
1699 corners[2]= tbEdges[0];
1700 corners[3]= tbMiddle;
1702 else
1704 corners[0]= tbEdges[3];
1705 corners[1]= tbCorners[1];
1706 corners[2]= tbMiddle;
1707 corners[3]= tbEdges[2];
1710 else
1712 if(tls==0)
1714 corners[0]= tbEdges[0];
1715 corners[1]= tbMiddle;
1716 corners[2]= tbCorners[2];
1717 corners[3]= tbEdges[1];
1719 else
1721 corners[0]= tbMiddle;
1722 corners[1]= tbEdges[2];
1723 corners[2]= tbEdges[1];
1724 corners[3]= tbCorners[3];
1728 else
1730 // Just fill with 0s.
1731 corners[0]= CRGBA::Black;
1732 corners[1]= CRGBA::Black;
1733 corners[2]= CRGBA::Black;
1734 corners[3]= CRGBA::Black;
1738 // ***************************************************************************
1739 void CPatch::addTileLightmapWithTLI(uint ts, uint tt, NLMISC::CRGBA *dest, uint stride)
1741 // compute colors ar corners of the tile.
1742 CRGBA corners[4];
1743 getCurrentTileTLIColors(ts, tt, corners);
1745 // Bilinear accross the tile, and add to dest.
1746 uint x, y;
1747 for(y=0; y<NL_LUMEL_BY_TILE; y++)
1749 for(x=0; x<NL_LUMEL_BY_TILE; x++)
1751 // compute this pixel, and add
1752 bilinearColorDiv2AndAdd(corners, x, y, dest[y*stride + x]);
1757 // ***************************************************************************
1758 void CPatch::addTileLightmapEdgeWithTLI(uint ts, uint tt, uint edge, NLMISC::CRGBA *dest, uint stride, bool inverse)
1760 // compute colors ar corners of the tile.
1761 CRGBA corners[4];
1762 getCurrentTileTLIColors(ts, tt, corners);
1764 // get coordinate according to edge.
1765 uint x=0,y=0;
1766 switch(edge)
1768 case 0: x= 0; break;
1769 case 1: y= NL_LUMEL_BY_TILE-1; break;
1770 case 2: x= NL_LUMEL_BY_TILE-1; break;
1771 case 3: y= 0; break;
1774 // For all lumel of the edge, bilinear.
1775 uint i;
1776 for(i=0; i<NL_LUMEL_BY_TILE; i++)
1778 // if vertical edge
1779 if( (edge&1)==0 ) y= i;
1780 // else horizontal edge
1781 else x= i;
1783 // manage inverse.
1784 uint where;
1785 if(inverse) where= (NL_LUMEL_BY_TILE-1)-i;
1786 else where= i;
1787 // compute this pixel, and modulate
1788 bilinearColorDiv2AndAdd(corners, x, y, dest[where*stride]);
1792 // ***************************************************************************
1793 void CPatch::addTileLightmapPixelWithTLI(uint ts, uint tt, uint s, uint t, NLMISC::CRGBA *dest)
1795 // compute colors ar corners of the tile.
1796 CRGBA corners[4];
1797 getCurrentTileTLIColors(ts, tt, corners);
1799 // compute this pixel, and modulate
1800 bilinearColorDiv2AndAdd(corners, s, t, *dest);
1804 // ***************************************************************************
1805 void CPatch::computeCurrentTLILightmapDiv2(NLMISC::CRGBA *array) const
1807 // Size of TileLightInfluences
1808 uint wTLI= (OrderS>>1)+1;
1809 uint hTLI= (OrderT>>1)+1;
1810 // colros at corners of tiles size.
1811 uint wTC= OrderS+1;
1812 uint wTCx2= wTC*2;
1813 uint hTC= OrderT+1;
1814 uint x, y;
1816 // Compute TLI colors at each corner of each TessBlocks.
1817 //=============
1818 for(y=0;y<hTLI;y++)
1820 // store every 2 tiles corners.
1821 CRGBA *dst= array + y*2*wTC;
1822 for(x=0;x<wTLI;x++)
1824 *dst= getCurrentTLIColor(x, y);
1825 dst->R >>= 1;
1826 dst->G >>= 1;
1827 dst->B >>= 1;
1828 // skip 2 tiles corners.
1829 dst++;
1830 dst++;
1834 // Compute TLI colors at each corner of each Tiles.
1835 //=============
1837 // Compute corner at middle of vertical TessBlock edges.
1838 for(y=0;y<hTC-1;y+=2)
1840 CRGBA *dst= array + y*wTC;
1841 for(x=0;x<wTC;x+=2)
1843 // Average midlle with cur and next.
1844 (dst+wTC)->avg2RGBOnly(*dst, *(dst + wTCx2) );
1846 // skip 2 tiles corners.
1847 dst++;
1848 dst++;
1852 // Compute corner at middle of horizontal TessBlock edges, and at middle of TessBlock.
1853 for(y=0;y<hTC;y++)
1855 CRGBA *dst= array + y*wTC;
1856 for(x=0;x<wTC-1;x+=2)
1858 // Average midlle with cur and next.
1859 (dst+1)->avg2RGBOnly(*dst, *(dst+2));
1861 // skip 2 tiles corners.
1862 dst++;
1863 dst++;
1872 // ***************************************************************************
1873 // ***************************************************************************
1874 // UpdateLighting.
1875 // ***************************************************************************
1876 // ***************************************************************************
1879 // ***************************************************************************
1880 void CPatch::linkBeforeNearUL(CPatch *patchNext)
1882 nlassert(patchNext);
1884 // first, unlink others from me. NB: works even if _ULNearPrec==_ULNearNext==this.
1885 _ULNearNext->_ULNearPrec= _ULNearPrec;
1886 _ULNearPrec->_ULNearNext= _ULNearNext;
1887 // link to igNext.
1888 _ULNearNext= patchNext;
1889 _ULNearPrec= patchNext->_ULNearPrec;
1890 // link others to me.
1891 _ULNearNext->_ULNearPrec= this;
1892 _ULNearPrec->_ULNearNext= this;
1896 // ***************************************************************************
1897 void CPatch::unlinkNearUL()
1899 // first, unlink others from me. NB: works even if _ULNearPrec==_ULNearNext==this.
1900 _ULNearNext->_ULNearPrec= _ULNearPrec;
1901 _ULNearPrec->_ULNearNext= _ULNearNext;
1902 // reset
1903 _ULNearPrec= this;
1904 _ULNearNext= this;
1908 // ***************************************************************************
1909 uint CPatch::updateTessBlockLighting(uint numTb)
1911 // TessBlocks must have been allocated and tessBlockId must be ok.
1912 nlassert(numTb<TessBlocks.size());
1914 // compute tessBlock coordinate
1915 uint tbWidth= OrderS>>1;
1916 uint ts= numTb&(tbWidth-1);
1917 uint tt= numTb/tbWidth;
1918 // expand to tile coordinate.
1919 ts*= 2;
1920 tt*= 2;
1922 // get what tessBlock to use.
1923 CTessBlock &tessBlock= TessBlocks[numTb];
1925 // If the lightmap Id has not been computed, quit
1926 if(tessBlock.LightMapRefCount==0)
1927 return 0;
1928 else
1930 // Recompute the lightmap texture, with help of TileColors, with neighboring info etc...
1931 CRGBA lightText[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE];
1932 computeNearBlockLightmap(ts&(~1), tt&(~1), lightText);
1934 // donlod this texture to Driver etc...
1935 Zone->Landscape->refillTileLightMap(tessBlock.LightMapId, lightText);
1937 // return number of pixels computed.
1938 return NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
1943 // ***************************************************************************
1944 // ***************************************************************************
1945 // ***************************************************************************
1946 // ***************************************************************************
1949 // ***************************************************************************
1950 void CPatch::addRefDLMContext()
1952 // the patch must be compiled.
1953 nlassert(Zone);
1955 // if 0, create the context.
1956 if(_DLMContextRefCount==0)
1958 nlassert(_DLMContext==NULL);
1959 _DLMContext= new CPatchDLMContext;
1960 // init now the context.
1961 _DLMContext->generate(this, getLandscape()->getTextureDLM(), getLandscape()->getPatchDLMContextList());
1963 // If the patch is visible, it may have Far Vertices created,
1964 // hence, we must refill them with good DLM Uvs.
1965 if(!isRenderClipped())
1967 // setup DLM Uv with new _DLMContext
1968 fillVBFarsDLMUvOnly();
1972 // incRef.
1973 _DLMContextRefCount++;
1976 // ***************************************************************************
1977 void CPatch::decRefDLMContext(uint count)
1979 // the patch must be compiled.
1980 nlassert(Zone);
1981 nlassert(_DLMContextRefCount>0);
1983 // dec Ref.
1984 _DLMContextRefCount-= count;
1985 nlassert(_DLMContextRefCount>=0);
1987 // If 0, delete the context.
1988 if(_DLMContextRefCount==0)
1990 delete _DLMContext;
1991 _DLMContext= NULL;
1993 // If the patch is visible, it may have Far Vertices created,
1994 // hence, we must reset their DLM Uvs (to point to black pixel)
1995 if(!isRenderClipped())
1997 // setup DLM Uv with new _DLMContext
1998 fillVBFarsDLMUvOnly();
2004 // ***************************************************************************
2005 void CPatch::beginDLMLighting()
2007 nlassert(_DLMContext);
2009 // Must bkup prec pointLightCount in OldPointLightCount, and reset CurPointLightCount
2010 _DLMContext->OldPointLightCount= _DLMContext->CurPointLightCount;
2011 _DLMContext->CurPointLightCount= 0;
2013 // clear lighting, only if patch is visible
2014 if(!isRenderClipped())
2015 // NB: no-op if src is already full black.
2016 _DLMContext->clearLighting();
2020 // ***************************************************************************
2021 void CPatch::processDLMLight(CPatchDLMPointLight &pl)
2023 // add reference to currentLight, creating DLMContext if needed
2024 addRefDLMContext();
2026 // add curLight counter
2027 _DLMContext->CurPointLightCount++;
2029 // compute lighting, only if patch is visible
2030 if(!isRenderClipped())
2031 _DLMContext->addPointLightInfluence(pl);
2034 // ***************************************************************************
2035 void CPatch::endDLMLighting()
2037 nlassert(_DLMContext);
2039 // delete reference from old pointLight influences, at prec render() pass. _DLMContext may be deleted here,
2040 // if no more lights use it, and if the patch is not in Near.
2041 decRefDLMContext(_DLMContext->OldPointLightCount);
2045 } // NL3D