1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
35 using namespace NLMISC
;
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]=
60 static const uint NL3DDecompressLumelFactor1Case1
[6]=
64 // ***************************************************************************
65 void CPatch::unpackLumelBlock (uint8
*dest
, const uint8
*src
)
67 // Take the two alpha values
71 // precompute the 8 possible values, for each possible code.
77 // unrolled, and hardcoded for faster compute
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
90 // unrolled, and hardcoded for faster compute
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
102 // For each pixel, set the value according to the code
103 // ------------------
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]) ;
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
128 // ***************************************************************************
129 inline uint8
getUnpackLumelBlock (const uint8
*src
, uint pixel
)
133 uint offset
=(pixel
>>3)+2;
136 // Uncompress 16 codes
141 code
=(src
[offset
]>>(5-bits
))&0x7;
143 code
= ( (src
[offset
]<<(bits
-5)) | (src
[offset
+1]>>(13-bits
)) )&0x7;
148 // Decompress the data
149 return (uint8
)((NL3DDecompressLumelFactor0Case0
[code
]*src
[0]+NL3DDecompressLumelFactor1Case0
[code
]*src
[1])/7);
154 // Decompress the data
156 return (uint8
)((NL3DDecompressLumelFactor0Case1
[code
]*src
[0]+NL3DDecompressLumelFactor1Case1
[code
]*src
[1])/5);
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;
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
;
191 for (uint lineBlock
=0; lineBlock
<numLineBlock
; lineBlock
++)
196 uint8
*blockLine
=pLumelDest
;
199 for (uint lumelBlock
=0; lumelBlock
<numLumelBlock
; lumelBlock
++)
201 // *** Unpack the block
205 uint8
*blockDest
=blockLine
;
210 // Block unpacking...
211 unpackLumelBlock (block
, compressedData
);
214 for (uint v
=0; v
<countVx4
; v
+=4)
216 for (uint u
=0; u
<countU
; u
++)
219 blockDest
[u
]=block
[v
+u
];
223 blockDest
+=lumelCount
;
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
)
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
]);
255 // ***************************************************************************
256 void CPatch::packLumelBlock (uint8
*dest
, const uint8
*source
, uint8 alpha0
, uint8 alpha1
)
258 // Precalc the height values..
268 value
[i
]=(NL3DDecompressLumelFactor0Case0
[i
]*alpha0
+NL3DDecompressLumelFactor1Case0
[i
]*alpha1
)/7;
272 value
[i
]=(NL3DDecompressLumelFactor0Case1
[i
]*alpha0
+NL3DDecompressLumelFactor1Case1
[i
]*alpha1
)/5;
291 // For each original select the best
296 // Best dist and code
301 for (uint code
=0; code
<8; code
++)
303 // Distance from original value
304 uint dist
=abs ((sint
)(source
[i
])-(sint
)(value
[code
]));
314 // Perfect, stop searching
321 dest
[codeOffset
]|=bestCode
<<codeShift
;
324 dest
[codeOffset
]|=bestCode
>>(-codeShift
);
325 dest
[codeOffset
+1]|=bestCode
<<(8+codeShift
);
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.
365 // compute weight factors.
373 R
= corners
[0].R
* x1y1
;
374 G
= corners
[0].G
* x1y1
;
375 B
= corners
[0].B
* x1y1
;
377 R
+= corners
[1].R
* xy1
;
378 G
+= corners
[1].G
* xy1
;
379 B
+= corners
[1].B
* xy1
;
381 R
+= corners
[2].R
* x1y
;
382 G
+= corners
[2].G
* x1y
;
383 B
+= corners
[2].B
* x1y
;
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
)
397 bilinearColor(corners
, x
, y
, R
, G
, B
);
399 // modulate with input.
404 // R,G,B are on 14 bits
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
)
416 bilinearColor(corners
, x
, y
, R
, G
, B
);
418 // modulate with input.
423 // result not >> 14 but >> 13 and clamp from 0 to 255
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
)
439 bilinearColor(corners
, x
, y
, R
, G
, B
);
441 // add with input. Resulting TLI must be on 7 bits.
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
)
462 bilinearColor(corners
, x
, y
, R
, G
, B
);
464 // add with input. Resulting TLI must be on 7 bits.
481 // ***************************************************************************
482 void CPatch::modulateTileLightmapWithTileColors(uint ts
, uint tt
, CRGBA
*dest
, uint stride
)
484 // Get the tileColors around this tile
486 getTileTileColors(ts
, tt
, corners
);
488 // For all lumel, bilinear.
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
506 getTileTileColors(ts
, tt
, corners
);
508 // get coordinate according to edge.
513 case 1: y
= NL_LUMEL_BY_TILE
-1; break;
514 case 2: x
= NL_LUMEL_BY_TILE
-1; break;
518 // For all lumel of the edge, bilinear.
520 for(i
=0; i
<NL_LUMEL_BY_TILE
; i
++)
523 if( (edge
&1)==0 ) y
= i
;
524 // else horizontal edge
529 if(inverse
) where
= (NL_LUMEL_BY_TILE
-1)-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
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
)
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.
572 case 1: y
= NL_LUMEL_BY_TILE
-1; break;
573 case 2: x
= NL_LUMEL_BY_TILE
-1; break;
578 for(i
=0; i
<NL_LUMEL_BY_TILE
; i
++)
581 if( (edge
&1)==0 ) y
= i
;
582 // else horizontal edge
587 if(inverse
) where
= (NL_LUMEL_BY_TILE
-1)-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
)
598 static const float lumelSize
= 1.f
/NL_LUMEL_BY_TILE
;
600 // use 3 computeVertex to compute a normal. This is slow....
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
);
617 normal
= (p1
-p0
)^(p2
-p0
);
621 float c
= -normal
*getLandscape()->getAutomaticLightDir();
625 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR)
626 // FastFloor using fistp. Don't care convention.
634 ic
= (sint
)floor(c
*256);
638 // ambiant/diffuse lighting.
639 *dest
= getLandscape()->getStaticLight()[ic
];
643 // ***************************************************************************
644 void CPatch::getTileLumelmapPrecomputed(uint ts
, uint tt
, uint8
*dest
, uint stride
)
647 uint8 buffer
[NL_LUMEL_BY_TILE
*NL_LUMEL_BY_TILE
];
648 unpackLumelBlock (buffer
, &(CompressedLumels
[(ts
+ (tt
*OrderS
))*NL_BLOCK_LUMEL_COMPRESSED_SIZE
]));
652 for(y
=0; y
<NL_LUMEL_BY_TILE
; y
++)
654 for(x
=0; x
<NL_LUMEL_BY_TILE
; x
++)
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
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
)
675 const CRGBA
* colorTable
=getLandscape ()->getStaticLight ();
677 uint8 buffer
[NL_LUMEL_BY_TILE
*NL_LUMEL_BY_TILE
];
678 unpackLumelBlock (buffer
, &(CompressedLumels
[(ts
+ (tt
*OrderS
))*NL_BLOCK_LUMEL_COMPRESSED_SIZE
]));
682 for(y
=0; y
<NL_LUMEL_BY_TILE
; y
++)
684 for(x
=0; x
<NL_LUMEL_BY_TILE
; x
++)
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
)
701 const CRGBA
* colorTable
=getLandscape ()->getStaticLight ();
703 // Witch corner to start ?
704 uint pixel
=NL3DPixelStartLumel
[edge
];
705 uint delta
=NL3DDeltaLumel
[edge
];
708 const uint8
*src
=&(CompressedLumels
[(ts
+ (tt
*OrderS
))*NL_BLOCK_LUMEL_COMPRESSED_SIZE
]);
712 uint inverseStride
=stride
*(4-1);
716 dest
[inverseStride
-x
*stride
]=colorTable
[getUnpackLumelBlock (src
, pixel
)];
725 dest
[x
*stride
]=colorTable
[getUnpackLumelBlock (src
, pixel
)];
731 // ***************************************************************************
732 void CPatch::computeTileLightmapPixelPrecomputed(uint ts
, uint tt
, uint s
, uint t
, CRGBA
*dest
)
735 const CRGBA
* colorTable
=getLandscape ()->getStaticLight ();
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
);
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
);
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
);
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).
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.
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
)
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.
826 // choose against which edge we must find the pixel.
829 else if(v
>=OrderT
*NL_LUMEL_BY_TILE
) edge
=1;
830 else if(u
>=OrderS
*NL_LUMEL_BY_TILE
) edge
=2;
833 // retrieve info on neighbor.
835 getBindNeighbor(edge
, bindInfo
);
837 // if neighbor present.
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
)
863 // hardcoded for 10x10.
864 nlassert(NL_TILE_LIGHTMAP_SIZE
==10);
869 // Compute center of the TessBlock: the 2x2 tiles.
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.
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 );
895 for(edge
=0; edge
<4; edge
++)
897 // compute dest info.
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.
905 // and must compute ptr, where we store the result of the 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.
922 dest2
= dest
+ NL_LUMEL_BY_TILE
*NL_TILE_LIGHTMAP_SIZE
;
929 dest2
= dest
+ NL_LUMEL_BY_TILE
;
935 // If we are not on a border of a patch, just compute on the interior of the patch.
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).
950 CPatchUVLocator uvLocator
;
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.
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())
972 // Fast reject: if no neighbor, or if not smoothed, or if edge order pb, just copy from my interior.
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
)
988 // else, ok, get from neighbor.
991 CVector2f stIn
, stOut
;
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
);
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.
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];
1044 for(corner
=0; corner
<4; corner
++)
1046 // compute dest info.
1048 // must compute on which tile we must find info.
1051 // and must compute ptr, where we store the result of the 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.
1063 // if the corner is IN the patch.
1064 if(!cornerOnPatchCorner
[corner
] && !cornerOnPatchEdge
[corner
])
1066 // what pixel to read.
1068 if(decalS
==-1) subS
= NL_LUMEL_BY_TILE
-1;
1070 if(decalT
==-1) subT
= NL_LUMEL_BY_TILE
-1;
1073 // find the result on the corner of the neighbor tile.
1074 computeTileLightmapPixel(ts
+decalS
, tt
+decalT
, subS
, subT
, dest
);
1078 // By default, fill the corner with our interior corner. Because other methods may fail.
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;
1091 // get the coordinate of the corner, in our [0,Order] basis. get it at the center of the pixel.
1093 CPatchUVLocator uvLocator
;
1094 CVector2f stIn
, stOut
;
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.
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
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.
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
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.
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.
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
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.
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.
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.
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.
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;
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];
1284 for (uint lineBlock
=0; lineBlock
<numLineBlock
; lineBlock
++)
1287 const uint8
*blockLine
=pLumelSrc
;
1290 for (uint lumelBlock
=0; lumelBlock
<numLumelBlock
; lumelBlock
++)
1292 // *** Unpack the block
1296 if (lumelBlock
==numLumelBlock
-1)
1297 countU
=lumelCount
&3;
1301 // Destination lumel
1302 const uint8
*blockSrc
=blockLine
;
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
++)
1313 originalBlock
[(v
<<2)+u
]=blockSrc
[u
];
1317 blockSrc
+=lumelCount
;
1320 // Get min and max alpha
1325 for (uint i
=0; i
<16; i
++)
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];
1340 packLumelBlock (compressedData
, originalBlock
, alphaMin
, alphaMax
);
1343 unpackLumelBlock (uncompressedBlock
, compressedData
);
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
);
1353 unpackLumelBlock (uncompressedBlock
, secondCompressedBlock
);
1356 uint secondMethod
=evalLumelBlock (originalBlock
, uncompressedBlock
, NL_LUMEL_BY_TILE
, NL_LUMEL_BY_TILE
);
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
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;
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;
1398 CompressedLumels
.resize (size
);
1400 // No line have shadows.
1401 memset (&CompressedLumels
[0], 0, size
);
1405 // ***************************************************************************
1406 // ***************************************************************************
1407 // Functions (C/ASM).
1408 // ***************************************************************************
1409 // ***************************************************************************
1412 // ***************************************************************************
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.
1485 // ***************************************************************************
1486 // ***************************************************************************
1487 // Lightmap get interface.
1488 // ***************************************************************************
1489 // ***************************************************************************
1492 // ***************************************************************************
1493 uint8
CPatch::getLumel(const CUV
&uv
) const
1495 // compute tile coord and lumel coord.
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;
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
);
1515 // ***************************************************************************
1516 // ***************************************************************************
1517 // TileLightInfluences
1518 // ***************************************************************************
1519 // ***************************************************************************
1522 // ***************************************************************************
1523 void CPatch::resetTileLightInfluences()
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.
1547 // There is (OrderS/2+1) * (OrderT/2+1) tileLightInfluences (TLI).
1548 sint w
= (OrderS
>>1);
1549 sint h
= (OrderT
>>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));
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]));
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
];
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)
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
++)
1605 corner
.Lights
[lid
]= NULL
;
1610 interp
.interpolate(pointLightList
, xSub
/256.f
, ySub
/256.f
);
1614 // ***************************************************************************
1615 CRGBA
CPatch::getCurrentTLIColor(uint x
, uint y
) const
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)
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
);
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
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.
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).
1677 tbEdges
[0].avg2RGBOnly(tbCorners
[0], tbCorners
[2]);
1680 tbEdges
[1].avg2RGBOnly(tbCorners
[2], tbCorners
[3]);
1683 tbEdges
[2].avg2RGBOnly(tbCorners
[1], tbCorners
[3]);
1686 tbEdges
[3].avg2RGBOnly(tbCorners
[0], tbCorners
[1]);
1689 tbMiddle
.avg2RGBOnly(tbEdges
[0], tbEdges
[2]);
1692 // just copy result according to tile pos in tessBlock.
1697 corners
[0]= tbCorners
[0];
1698 corners
[1]= tbEdges
[3];
1699 corners
[2]= tbEdges
[0];
1700 corners
[3]= tbMiddle
;
1704 corners
[0]= tbEdges
[3];
1705 corners
[1]= tbCorners
[1];
1706 corners
[2]= tbMiddle
;
1707 corners
[3]= tbEdges
[2];
1714 corners
[0]= tbEdges
[0];
1715 corners
[1]= tbMiddle
;
1716 corners
[2]= tbCorners
[2];
1717 corners
[3]= tbEdges
[1];
1721 corners
[0]= tbMiddle
;
1722 corners
[1]= tbEdges
[2];
1723 corners
[2]= tbEdges
[1];
1724 corners
[3]= tbCorners
[3];
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.
1743 getCurrentTileTLIColors(ts
, tt
, corners
);
1745 // Bilinear accross the tile, and add to dest.
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.
1762 getCurrentTileTLIColors(ts
, tt
, corners
);
1764 // get coordinate according to 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.
1776 for(i
=0; i
<NL_LUMEL_BY_TILE
; i
++)
1779 if( (edge
&1)==0 ) y
= i
;
1780 // else horizontal edge
1785 if(inverse
) where
= (NL_LUMEL_BY_TILE
-1)-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.
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.
1816 // Compute TLI colors at each corner of each TessBlocks.
1820 // store every 2 tiles corners.
1821 CRGBA
*dst
= array
+ y
*2*wTC
;
1824 *dst
= getCurrentTLIColor(x
, y
);
1828 // skip 2 tiles corners.
1834 // Compute TLI colors at each corner of each Tiles.
1837 // Compute corner at middle of vertical TessBlock edges.
1838 for(y
=0;y
<hTC
-1;y
+=2)
1840 CRGBA
*dst
= array
+ y
*wTC
;
1843 // Average midlle with cur and next.
1844 (dst
+wTC
)->avg2RGBOnly(*dst
, *(dst
+ wTCx2
) );
1846 // skip 2 tiles corners.
1852 // Compute corner at middle of horizontal TessBlock edges, and at middle of TessBlock.
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.
1872 // ***************************************************************************
1873 // ***************************************************************************
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
;
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
;
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.
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)
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.
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();
1973 _DLMContextRefCount
++;
1976 // ***************************************************************************
1977 void CPatch::decRefDLMContext(uint count
)
1979 // the patch must be compiled.
1981 nlassert(_DLMContextRefCount
>0);
1984 _DLMContextRefCount
-= count
;
1985 nlassert(_DLMContextRefCount
>=0);
1987 // If 0, delete the context.
1988 if(_DLMContextRefCount
==0)
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
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
);