# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

patch_lightmap.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 #include "std3d.h"
00028 
00029 
00030 #include "3d/patch.h"
00031 #include "3d/tessellation.h"
00032 #include "3d/bezier_patch.h"
00033 #include "3d/zone.h"
00034 #include "3d/landscape.h"
00035 #include "nel/misc/vector.h"
00036 #include "nel/misc/common.h"
00037 #include "3d/patchuv_locator.h"
00038 #include "3d/vegetable_manager.h"
00039 #include "3d/fast_floor.h"
00040 #include "3d/light_influence_interpolator.h"
00041 #include "3d/patchdlm_context.h"
00042 using   namespace       std;
00043 using   namespace       NLMISC;
00044 
00045 
00046 namespace NL3D 
00047 {
00048 
00049 
00050 // ***************************************************************************
00051 // Precalc table used to decompress shadow map
00052 // NB: if you want to change thoses values, see unpackLumelBlock, cause hardcoded.
00053 static const uint NL3DDecompressLumelFactor0Case0[8]=
00054 {
00055         7, 0, 6, 5, 4, 3, 2, 1
00056 };
00057 static const uint NL3DDecompressLumelFactor1Case0[8]=
00058 {
00059         0, 7, 1, 2, 3, 4, 5, 6
00060 };
00061 static const uint NL3DDecompressLumelFactor0Case1[6]=
00062 {
00063         5, 0, 4, 3, 2, 1,
00064 };
00065 static const uint NL3DDecompressLumelFactor1Case1[6]=
00066 {
00067         0, 5, 1, 2, 3, 4,
00068 };
00069 // ***************************************************************************
00070 void            CPatch::unpackLumelBlock (uint8 *dest, const uint8 *src)
00071 {
00072         // Take the two alpha values
00073         uint alpha0=src[0];
00074         uint alpha1=src[1];
00075 
00076         // precompute the 8 possible values, for each possible code.
00077         // ------------------
00078         uint8   values[8];
00079         // Case 0
00080         if (alpha0>alpha1)
00081         {
00082                 // unrolled, and hardcoded for faster compute
00083                 values[0]= alpha0;
00084                 values[1]= alpha1;
00085                 values[2]= (uint8) ( (alpha0*219 + alpha1*37 ) >>8 ) ;  // 6*256/7
00086                 values[3]= (uint8) ( (alpha0*183 + alpha1*73 ) >>8 ) ;  // 5*256/7
00087                 values[4]= (uint8) ( (alpha0*146 + alpha1*110) >>8 ) ;  // 4*256/7
00088                 values[5]= (uint8) ( (alpha0*110 + alpha1*146) >>8 ) ;  // 3*256/7
00089                 values[6]= (uint8) ( (alpha0*73  + alpha1*183) >>8 ) ;  // 2*256/7
00090                 values[7]= (uint8) ( (alpha0*37  + alpha1*219) >>8 ) ;  // 1*256/7
00091         }
00092         // Case 1
00093         else
00094         {
00095                 // unrolled, and hardcoded for faster compute
00096                 values[0]= alpha0;
00097                 values[1]= alpha1;
00098                 values[2]= (uint8) ( (alpha0*205 + alpha1*51 ) >>8 ) ;  // 4*256/5
00099                 values[3]= (uint8) ( (alpha0*154 + alpha1*102) >>8 ) ;  // 3*256/5
00100                 values[4]= (uint8) ( (alpha0*102 + alpha1*154) >>8 ) ;  // 2*256/5
00101                 values[5]= (uint8) ( (alpha0*51  + alpha1*205) >>8 ) ;  // 1*256/5
00102                 values[6]= 0;
00103                 values[7]= 255;
00104         }
00105 
00106 
00107         // For each pixel, set the value according to the code
00108         // ------------------
00109         uint    block8Pixs[2];
00110         // Split the 48 bits data in 2 24 bits pass.
00111         block8Pixs[0]= ((uint)src[2]<<16) + ((uint)src[3]<<8) + ((uint)src[4]) ;
00112         block8Pixs[1]= ((uint)src[5]<<16) + ((uint)src[6]<<8) + ((uint)src[7]) ;
00113 
00114         // write all lumels
00115         for(uint i=0; i<2; i++)
00116         {
00117                 uint    blockPix= block8Pixs[i];
00118                 // parse the 8 pixs, and write seq to dest
00119                 for(uint n=8; n>0; n--, dest++)
00120                 {
00121                         uint code= (blockPix>>21)&0x7;
00122 
00123                         // read LUT, and store
00124                         *dest= values[code];
00125 
00126                         // shift the block
00127                         blockPix<<= 3;
00128                 }
00129         }
00130 
00131 }
00132 
00133 // ***************************************************************************
00134 inline uint8 getUnpackLumelBlock (const uint8 *src, uint pixel)
00135 {
00136         // Offset of the bit
00137         pixel*=3;
00138         uint offset=(pixel>>3)+2;
00139         uint bits=pixel&7;
00140 
00141         // Uncompress 16 codes
00142         uint code;
00143 
00144         // Get the code
00145         if (bits<=5)
00146                 code=(src[offset]>>(5-bits))&0x7;
00147         else
00148                 code= ( (src[offset]<<(bits-5)) | (src[offset+1]>>(13-bits)) )&0x7;
00149 
00150         // Case 0
00151         if (src[0]>src[1])
00152         {
00153                 // Decompress the data
00154                 return (uint8)((NL3DDecompressLumelFactor0Case0[code]*src[0]+NL3DDecompressLumelFactor1Case0[code]*src[1])/7);
00155         }
00156         // Case 1
00157         else
00158         {
00159                 // Decompress the data
00160                 if (code<6)
00161                         return (uint8)((NL3DDecompressLumelFactor0Case1[code]*src[0]+NL3DDecompressLumelFactor1Case1[code]*src[1])/5);
00162                 else if (code==6)
00163                         return 0;
00164                 else
00165                         return 255;
00166         }
00167 }
00168 
00169 // ***************************************************************************
00170 void            CPatch::unpackShadowMap (uint8 *pLumelDest)
00171 {
00172         // Input of compresed data
00173         uint8 *compressedData=&CompressedLumels[0];
00174 
00175         // Number of lumel by lines
00176         uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
00177 
00178         // Number of block in a line
00179         nlassert ((lumelCount&0x3)==0);
00180         uint numLumelBlock=lumelCount>>2;
00181 
00182         // Number of line
00183         uint lineCount=OrderT*NL_LUMEL_BY_TILE;
00184 
00185         // Number of block line
00186         nlassert ((lineCount&0x3)==0);
00187         uint numLineBlock=lineCount>>2;
00188 
00189         // Destination lumel block size
00190         uint lumelDestBlockSize=4;
00191 
00192         // Destination lumel line block size
00193         uint lumelDestLineBlockSize=lumelCount*lumelDestBlockSize;
00194 
00195         // Each line block
00196         for (uint lineBlock=0; lineBlock<numLineBlock; lineBlock++)
00197         {
00198                 uint countVx4=16;
00199 
00200                 // Block pointer
00201                 uint8 *blockLine=pLumelDest;
00202 
00203                 // Each lumel block
00204                 for (uint lumelBlock=0; lumelBlock<numLumelBlock; lumelBlock++)
00205                 {
00206                         // *** Unpack the block
00207                         uint countU=4;
00208 
00209                         // Destination lumel
00210                         uint8 *blockDest=blockLine;
00211 
00212                         // Temp block
00213                         uint8 block[4*4];
00214 
00215                         // Block unpacking...
00216                         unpackLumelBlock (block, compressedData);
00217 
00218                         // Copy the lumels
00219                         for (uint v=0; v<countVx4; v+=4)
00220                         {
00221                                 for (uint u=0; u<countU; u++)
00222                                 {
00223                                         // Copy the lumel
00224                                         blockDest[u]=block[v+u];
00225                                 }
00226 
00227                                 // Next line
00228                                 blockDest+=lumelCount;
00229                         }
00230 
00231                         // Next source block
00232                         compressedData+=NL_BLOCK_LUMEL_COMPRESSED_SIZE;
00233 
00234                         // Next block on the line
00235                         blockLine+=lumelDestBlockSize;
00236                 }
00237 
00238                 // Next line of block
00239                 pLumelDest+=lumelDestLineBlockSize;
00240         }
00241 }
00242 
00243 // ***************************************************************************
00244 uint            CPatch::evalLumelBlock (const uint8 *original, const uint8 *unCompressed, uint width, uint height)
00245 {
00246         // Sum
00247         uint sum=0;
00248 
00249         // Eval error for each..
00250         for (uint v=0; v<height; v++)
00251         for (uint u=0; u<width; u++)
00252         {
00253                 sum += abs((sint)original[v*4+u]-(sint)unCompressed[v*4+u]);
00254         }
00255 
00256         // return the sum
00257         return sum;
00258 }
00259 
00260 // ***************************************************************************
00261 void            CPatch::packLumelBlock (uint8 *dest, const uint8 *source, uint8 alpha0, uint8 alpha1)
00262 {
00263         // Precalc the height values..
00264         uint8 value[8];
00265 
00266         // For each value
00267         uint i;
00268         for (i=0; i<8; i++)
00269         {
00270                 // Case 0 or 1 ?
00271                 if (alpha0>alpha1)
00272                         // Case 0
00273                         value[i]=(NL3DDecompressLumelFactor0Case0[i]*alpha0+NL3DDecompressLumelFactor1Case0[i]*alpha1)/7;
00274                 else
00275                 {
00276                         if (i<6)
00277                                 value[i]=(NL3DDecompressLumelFactor0Case1[i]*alpha0+NL3DDecompressLumelFactor1Case1[i]*alpha1)/5;
00278                         else if (i==6)
00279                                 value[i]=0;
00280                         else
00281                                 value[i]=255;
00282                 }
00283         }
00284 
00285         // Store alpha value
00286         dest[0]=alpha0;
00287         dest[1]=alpha1;
00288 
00289         // Clear dest codes
00290         for (i=0; i<6; i++)
00291         {
00292                 // Clear the code
00293                 dest[2+i]=0;
00294         }
00295 
00296         // For each original select the best
00297         uint codeOffset=2;
00298         sint codeShift=5;
00299         for (i=0; i<16; i++)
00300         {
00301                 // Best dist and code
00302                 uint bestDist=10000;
00303                 uint8 bestCode=0;
00304 
00305                 // Calc distance
00306                 for (uint code=0; code<8; code++)
00307                 {
00308                         // Distance from original value
00309                         uint dist=abs ((sint)(source[i])-(sint)(value[code]));
00310 
00311                         // The best ?
00312                         if (dist<bestDist)
00313                         {
00314                                 // New best
00315                                 bestDist=dist;
00316                                 bestCode=code;
00317                         }
00318 
00319                         // Perfect, stop searching
00320                         if (dist==0)
00321                                 break;
00322                 }
00323 
00324                 // Store the best
00325                 if (codeShift>=0)
00326                         dest[codeOffset]|=bestCode<<codeShift;
00327                 else
00328                 {
00329                         dest[codeOffset]|=bestCode>>(-codeShift);
00330                         dest[codeOffset+1]|=bestCode<<(8+codeShift);
00331                 }
00332 
00333 
00334                 // Next shift
00335                 codeShift-=3;
00336                 if (codeShift<=-3)
00337                 {
00338                         codeOffset++;
00339                         codeShift+=8;
00340                 }
00341         }
00342 }
00343 
00344 // ***************************************************************************
00345 void            CPatch::getTileTileColors(uint ts, uint tt, CRGBA corners[4])
00346 {
00347         for(sint i=0;i<4;i++)
00348         {
00349                 CTileColor      &tcol= TileColors[ (tt+(i>>1))*(OrderS+1) + (ts+(i&1)) ];
00350                 CRGBA           &col= corners[i];
00351                 col.set565 (tcol.Color565);
00352         }
00353 }
00354 
00355 
00356 // ***************************************************************************
00357 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
00358 inline void             bilinearColor(CRGBA     corners[4], uint x, uint y, uint &R, uint &G, uint &B)
00359 {
00360         // Fast bilinear and modulate. 
00361         // \todo yoyo: TODO_OPTIMIZE: should be ASMed later. (MMX...)
00362         // hardcoded for 4 pixels.
00363         nlassert(NL_LUMEL_BY_TILE==4);
00364 
00365         // expand to be on center of pixel=> 1,3,5 or 7.
00366         x= (x<<1)+1;
00367         y= (y<<1)+1;
00368         uint    x1= 8-x;
00369         uint    y1= 8-y;
00370 
00371         // compute weight factors.
00372         uint    xy=             x*y;
00373         uint    x1y=    x1*y;
00374         uint    xy1=    x*y1;
00375         uint    x1y1=   x1*y1;
00376 
00377         // bilinear
00378         // pix left top.
00379         R = corners[0].R * x1y1;
00380         G = corners[0].G * x1y1;
00381         B = corners[0].B * x1y1;
00382         // pix right top.
00383         R+= corners[1].R * xy1;
00384         G+= corners[1].G * xy1;
00385         B+= corners[1].B * xy1;
00386         // pix left bottom.
00387         R+= corners[2].R * x1y;
00388         G+= corners[2].G * x1y;
00389         B+= corners[2].B * x1y;
00390         // pix right bottom.
00391         R+= corners[3].R * xy;
00392         G+= corners[3].G * xy;
00393         B+= corners[3].B * xy;
00394 
00395 }
00396 
00397 
00398 // ***************************************************************************
00399 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
00400 inline void             bilinearColorAndModulate(CRGBA  corners[4], uint x, uint y, CRGBA &res)
00401 {
00402         uint    R,G,B;
00403         bilinearColor(corners, x, y, R, G, B);
00404 
00405         // modulate with input.
00406         R*= res.R;
00407         G*= res.G;
00408         B*= res.B;
00409 
00410         // result.
00411         res.R= R >> 14;
00412         res.G= G >> 14;
00413         res.B= B >> 14;
00414 }
00415 
00416 
00417 // ***************************************************************************
00418 // bilinear at center of the pixels. x E [0, 3], y E [0, 3].
00419 inline void             bilinearColorAndAdd(CRGBA       corners[4], uint x, uint y, CRGBA &res)
00420 {
00421         uint    R,G,B;
00422         bilinearColor(corners, x, y, R, G, B);
00423 
00424         // add with input.
00425         R= (R>>6) + res.R;
00426         G= (G>>6) + res.G;
00427         B= (B>>6) + res.B;
00428         R= min(R, 255U);
00429         G= min(G, 255U);
00430         B= min(B, 255U);
00431 
00432         // result.
00433         res.R= R;
00434         res.G= G;
00435         res.B= B;
00436 }
00437 
00438 
00439 
00440 // ***************************************************************************
00441 void            CPatch::modulateTileLightmapWithTileColors(uint ts, uint tt, CRGBA *dest, uint stride)
00442 {
00443         // Get the tileColors around this tile
00444         CRGBA   corners[4];
00445         getTileTileColors(ts, tt, corners);
00446 
00447         // For all lumel, bilinear.
00448         uint    x, y;
00449         for(y=0; y<NL_LUMEL_BY_TILE; y++)
00450         {
00451                 for(x=0; x<NL_LUMEL_BY_TILE; x++)
00452                 {
00453                         // compute this pixel, and modulate
00454                         bilinearColorAndModulate(corners, x, y, dest[y*stride + x]);
00455                 }
00456         }
00457 }
00458 
00459 
00460 // ***************************************************************************
00461 void            CPatch::modulateTileLightmapEdgeWithTileColors(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
00462 {
00463         // Get the tileColors around this tile
00464         CRGBA   corners[4];
00465         getTileTileColors(ts, tt, corners);
00466 
00467         // get coordinate according to edge.
00468         uint    x=0,y=0;
00469         switch(edge)
00470         {
00471         case 0: x= 0; break;
00472         case 1: y= NL_LUMEL_BY_TILE-1; break;
00473         case 2: x= NL_LUMEL_BY_TILE-1; break;
00474         case 3: y= 0; break;
00475         };
00476 
00477         // For all lumel of the edge, bilinear.
00478         uint    i;
00479         for(i=0; i<NL_LUMEL_BY_TILE; i++)
00480         {
00481                 // if vertical edge
00482                 if( (edge&1)==0 )       y= i;
00483                 // else horizontal edge
00484                 else                            x= i;
00485 
00486                 // manage inverse.
00487                 uint    where;
00488                 if(inverse)             where= (NL_LUMEL_BY_TILE-1)-i;
00489                 else                    where= i;
00490                 // compute this pixel, and modulate
00491                 bilinearColorAndModulate(corners, x, y, dest[where*stride]);
00492         }
00493 }
00494 
00495 
00496 // ***************************************************************************
00497 void            CPatch::modulateTileLightmapPixelWithTileColors(uint ts, uint tt, uint s, uint t, CRGBA *dest)
00498 {
00499         // Get the tileColors around this tile
00500         CRGBA   corners[4];
00501         getTileTileColors(ts, tt, corners);
00502 
00503         // compute this pixel, and modulate
00504         bilinearColorAndModulate(corners, s, t, *dest);
00505 }
00506 
00507 
00508 
00509 // ***************************************************************************
00510 void            CPatch::computeTileLightmapAutomatic(uint ts, uint tt, CRGBA *dest, uint stride)
00511 {
00512         uint    x, y;
00513         for(y=0; y<NL_LUMEL_BY_TILE; y++)
00514         {
00515                 for(x=0; x<NL_LUMEL_BY_TILE; x++)
00516                 {
00517                         // compute this pixel.
00518                         computeTileLightmapPixelAutomatic(ts, tt, x, y, dest+ y*stride + x);
00519                 }
00520         }
00521 }
00522 
00523 // ***************************************************************************
00524 void            CPatch::computeTileLightmapEdgeAutomatic(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
00525 {
00526         // get coordinate according to edge.
00527         uint    x=0,y=0;
00528         switch(edge)
00529         {
00530         case 0: x= 0; break;
00531         case 1: y= NL_LUMEL_BY_TILE-1; break;
00532         case 2: x= NL_LUMEL_BY_TILE-1; break;
00533         case 3: y= 0; break;
00534         };
00535 
00536         uint    i;
00537         for(i=0; i<NL_LUMEL_BY_TILE; i++)
00538         {
00539                 // if vertical edge
00540                 if( (edge&1)==0 )       y= i;
00541                 // else horizontal edge
00542                 else                            x= i;
00543 
00544                 // manage inverse.
00545                 uint    where;
00546                 if(inverse)             where= (NL_LUMEL_BY_TILE-1)-i;
00547                 else                    where= i;
00548                 // compute this pixel.
00549                 computeTileLightmapPixelAutomatic(ts, tt, x, y, dest+ where*stride);
00550         }
00551 }
00552 
00553 // ***************************************************************************
00554 void            CPatch::computeTileLightmapPixelAutomatic(uint ts, uint tt, uint s, uint t, CRGBA *dest)
00555 {
00556         float           u,v;
00557         static const float      lumelSize= 1.f/NL_LUMEL_BY_TILE;
00558 
00559         // use 3 computeVertex to compute a normal. This is slow....
00560         CVector         p0, p1 ,p2;
00561         // 1st vert. Top-left of the lumel.
00562         u= (ts + s*lumelSize )/OrderS;
00563         v= (tt + t*lumelSize )/OrderT;
00564         p0= computeVertex(u, v);
00565         // 2nd vert. Bottom-left of the lumel.
00566         u= (ts + s*lumelSize )/OrderS;
00567         v= (tt + (t+1)*lumelSize )/OrderT;
00568         p1= computeVertex(u, v);
00569         // 3rd vert. Center-Right of the lumel.
00570         u= (ts + (s+1)*lumelSize )/OrderS;
00571         v= (tt + (t+0.5f)*lumelSize )/OrderT;
00572         p2= computeVertex(u, v);
00573 
00574         // the normal.
00575         CVector         normal;
00576         normal= (p1-p0)^(p2-p0);
00577         normal.normalize();
00578 
00579         // lighting.
00580         float   c= -normal*getLandscape()->getAutomaticLightDir();
00581         c= max(c, 0.f);
00582         sint    ic;
00583 
00584 #ifdef NL_OS_WINDOWS
00585         // FastFloor using fistp. Don't care convention.
00586         float   fc= c*256;
00587         _asm
00588         {
00589                 fld fc
00590                 fistp ic
00591         }
00592 #else
00593         ic= (sint)floor(c*256);
00594 #endif
00595         clamp(ic, 0, 255);
00596 
00597         // ambiant/diffuse lighting.
00598         *dest= getLandscape()->getStaticLight()[ic];
00599 }
00600 
00601 
00602 // ***************************************************************************
00603 void            CPatch::getTileLumelmapPrecomputed(uint ts, uint tt, uint8 *dest, uint stride)
00604 {
00605         // Unpack the lumels
00606         uint8 buffer[NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE];
00607         unpackLumelBlock (buffer, &(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]));
00608 
00609         // Retrun it
00610         uint    x, y;
00611         for(y=0; y<NL_LUMEL_BY_TILE; y++)
00612         {
00613                 for(x=0; x<NL_LUMEL_BY_TILE; x++)
00614                 {
00615                         // lumel
00616                         dest[y*stride + x]= buffer[x+(y<<NL_LUMEL_BY_TILE_SHIFT)];
00617                 }
00618         }
00619 }
00620 
00621 
00622 // ***************************************************************************
00623 void            CPatch::getTileLumelmapPixelPrecomputed(uint ts, uint tt, uint s, uint t, uint8 &dest) const
00624 {
00625         // Return the lumel
00626         dest= getUnpackLumelBlock (&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]), s+(t<<2));
00627 }
00628 
00629 
00630 // ***************************************************************************
00631 void            CPatch::computeTileLightmapPrecomputed(uint ts, uint tt, CRGBA *dest, uint stride)
00632 {
00633         // Lumel table
00634         const CRGBA* colorTable=getLandscape ()->getStaticLight ();
00635         // Unpack the lumels
00636         uint8 buffer[NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE];
00637         unpackLumelBlock (buffer, &(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]));
00638 
00639         // Retrun it
00640         uint    x, y;
00641         for(y=0; y<NL_LUMEL_BY_TILE; y++)
00642         {
00643                 for(x=0; x<NL_LUMEL_BY_TILE; x++)
00644                 {
00645                         // lumel
00646                         dest[y*stride + x]=colorTable[buffer[x+(y<<NL_LUMEL_BY_TILE_SHIFT)]];
00647                 }
00648         }
00649 }
00650 
00651 // ***************************************************************************
00652 
00653 static uint NL3DPixelStartLumel[4]={0, 4*3, 3, 0};
00654 static uint NL3DDeltaLumel[4]={4, 1, 4, 1};
00655 
00656 // ***************************************************************************
00657 void            CPatch::computeTileLightmapEdgePrecomputed(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
00658 {
00659         // Lumel table
00660         const CRGBA* colorTable=getLandscape ()->getStaticLight ();
00661 
00662         // Witch corner to start ?
00663         uint pixel=NL3DPixelStartLumel[edge];
00664         uint delta=NL3DDeltaLumel[edge];
00665 
00666         // For each lumels
00667         const uint8 *src=&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]);
00668         uint x;
00669         if (inverse)
00670         {
00671                 uint inverseStride=stride*(4-1);
00672                 for(x=0; x<4; x++)
00673                 {
00674                         // lumel
00675                         dest[inverseStride-x*stride]=colorTable[getUnpackLumelBlock (src, pixel)];
00676                         pixel+=delta;
00677                 }
00678         }
00679         else
00680         {
00681                 for(x=0; x<4; x++)
00682                 {
00683                         // lumel
00684                         dest[x*stride]=colorTable[getUnpackLumelBlock (src, pixel)];
00685                         pixel+=delta;
00686                 }
00687         }
00688 }
00689 
00690 // ***************************************************************************
00691 void            CPatch::computeTileLightmapPixelPrecomputed(uint ts, uint tt, uint s, uint t, CRGBA *dest)
00692 {
00693         // Lumel table
00694         const CRGBA* colorTable=getLandscape ()->getStaticLight ();
00695 
00696         // Return the lumel
00697         *dest=colorTable[getUnpackLumelBlock (&(CompressedLumels[(ts + (tt*OrderS))*NL_BLOCK_LUMEL_COMPRESSED_SIZE]), s+(t<<2))];
00698 }
00699 
00700 
00701 
00702 // ***************************************************************************
00703 void            CPatch::computeTileLightmap(uint ts, uint tt, CRGBA *dest, uint stride)
00704 {
00705         if(getLandscape()->getAutomaticLighting())
00706                 computeTileLightmapAutomatic(ts, tt, dest, stride);
00707         else
00708         {
00709                 computeTileLightmapPrecomputed(ts, tt, dest, stride);
00710                 // Add the inlufence of TLI.
00711                 addTileLightmapWithTLI(ts, tt, dest, stride);
00712         }
00713 
00714         // modulate dest with tileColors (at center of lumels).
00715         modulateTileLightmapWithTileColors(ts, tt, dest, stride);
00716 }
00717 // ***************************************************************************
00718 void            CPatch::computeTileLightmapEdge(uint ts, uint tt, uint edge, CRGBA *dest, uint stride, bool inverse)
00719 {
00720         if(getLandscape()->getAutomaticLighting())
00721                 computeTileLightmapEdgeAutomatic(ts, tt, edge, dest, stride, inverse);
00722         else
00723         {
00724                 computeTileLightmapEdgePrecomputed(ts, tt, edge, dest, stride, inverse);
00725                 // Add the inlufence of TLI.
00726                 addTileLightmapEdgeWithTLI(ts, tt, edge, dest, stride, inverse);
00727         }
00728 
00729         // modulate dest with tileColors (at center of lumels).
00730         modulateTileLightmapEdgeWithTileColors(ts, tt, edge, dest, stride, inverse);
00731 }
00732 
00733 
00734 // ***************************************************************************
00735 void            CPatch::computeTileLightmapPixel(uint ts, uint tt, uint s, uint t, CRGBA *dest)
00736 {
00737         if(getLandscape()->getAutomaticLighting())
00738                 computeTileLightmapPixelAutomatic(ts, tt, s, t, dest);
00739         else
00740         {
00741                 computeTileLightmapPixelPrecomputed(ts, tt, s, t, dest);
00742                 // Add the inlufence of TLI.
00743                 addTileLightmapPixelWithTLI(ts, tt, s, t, dest);
00744         }
00745 
00746         // modulate dest with tileColors (at center of lumels).
00747         modulateTileLightmapPixelWithTileColors(ts, tt, s, t, dest);
00748 }
00749 
00750 
00751 // ***************************************************************************
00752 void            CPatch::computeTileLightmapPixelAroundCorner(const CVector2f &stIn, CRGBA *dest, bool lookAround)
00753 {
00754         bool    mustLookOnNeighbor= false;
00755 
00756         // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis).
00757         sint    u, v;
00758         u= (sint)floor(stIn.x*NL_LUMEL_BY_TILE);
00759         v= (sint)floor(stIn.y*NL_LUMEL_BY_TILE);
00760 
00761         // if allowed, try to go on neighbor patch.
00762         if(lookAround)
00763         {
00764                 // try to know if we must go on a neighbor patch (maybe false with bind X/1).
00765                 if( u<0 || u>=OrderS*NL_LUMEL_BY_TILE || v<0 || v>=OrderT*NL_LUMEL_BY_TILE)
00766                         mustLookOnNeighbor= true;
00767         }
00768 
00769 
00770         // If we must get (if possible) the pixel in the current patch, do it.
00771         if(!mustLookOnNeighbor)
00772         {
00773                 // if out this patch, abort.
00774                 if( u<0 || u>=OrderS*NL_LUMEL_BY_TILE || v<0 || v>=OrderT*NL_LUMEL_BY_TILE)
00775                         return;
00776                 else
00777                 {
00778                         // get this pixel.
00779                         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);
00780                 }
00781         }
00782         // else get from the best neighbor patch.
00783         else
00784         {
00785                 // choose against which edge we must find the pixel.
00786                 uint    edge=0;
00787                 if(u<0)                                 edge=0;
00788                 else if(v>=OrderT*NL_LUMEL_BY_TILE)     edge=1;
00789                 else if(u>=OrderS*NL_LUMEL_BY_TILE)     edge=2;
00790                 else if(v<0)                    edge=3;
00791 
00792                 // retrieve info on neighbor.
00793                 CBindInfo                       bindInfo;
00794                 getBindNeighbor(edge, bindInfo);
00795 
00796                 // if neighbor present.
00797                 if(bindInfo.Zone)
00798                 {
00799                         CVector2f       stOut;
00800                         CPatch          *patchOut;
00801                         uint            patchId;
00802 
00803                         // Ok, search uv on this patch.
00804                         CPatchUVLocator         uvLocator;
00805                         uvLocator.build(this, edge, bindInfo);
00806                         patchId= uvLocator.selectPatch(stIn);
00807                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00808 
00809                         // retry only one time, so at next call, must find the data IN htis patch (else abort).
00810                         patchOut->computeTileLightmapPixelAroundCorner(stOut, dest, false);
00811                 }
00812         }
00813 }
00814 
00815 
00816 // ***************************************************************************
00817 void            CPatch::computeNearBlockLightmap(uint uts, uint utt, CRGBA      *lightText)
00818 {
00819         sint    ts= uts;
00820         sint    tt= utt;
00821 
00822         // hardcoded for 10x10.
00823         nlassert(NL_TILE_LIGHTMAP_SIZE==10);
00824         CRGBA   *dest;
00825         uint    edge;
00826         uint    corner;
00827 
00828         // Compute center of the TessBlock: the 2x2 tiles.
00829         //=================
00830         // compute tile 0,0 of the tessBlock. must decal of 1 pixel.
00831         dest= lightText+NL_TILE_LIGHTMAP_SIZE+1;
00832         computeTileLightmap(ts, tt, dest, NL_TILE_LIGHTMAP_SIZE);
00833         // compute tile 1,0 of the tessBlock. must decal of 1 pixel.
00834         dest= lightText + NL_LUMEL_BY_TILE + NL_TILE_LIGHTMAP_SIZE+1 ;
00835         computeTileLightmap(ts+1, tt, dest, NL_TILE_LIGHTMAP_SIZE);
00836         // compute tile 0,1 of the tessBlock. must decal of 1 pixel.
00837         dest= lightText + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE + NL_TILE_LIGHTMAP_SIZE+1 ;
00838         computeTileLightmap(ts, tt+1, dest, NL_TILE_LIGHTMAP_SIZE);
00839         // compute tile 1,1 of the tessBlock. must decal of 1 pixel.
00840         dest= lightText + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE + NL_LUMEL_BY_TILE + NL_TILE_LIGHTMAP_SIZE+1 ;
00841         computeTileLightmap(ts+1, tt+1, dest, NL_TILE_LIGHTMAP_SIZE);
00842 
00843 
00844         // Compute edges of the TessBlock.
00845         //=================
00846         bool    edgeBorder[4];
00847         // where are we on a border of a patch??
00848         edgeBorder[0]= ( ts==0 );
00849         edgeBorder[1]= ( tt == OrderT-2 );
00850         edgeBorder[2]= ( ts == OrderS-2 );
00851         edgeBorder[3]= ( tt==0 );
00852 
00853         // For all edges.
00854         for(edge=0; edge<4; edge++)
00855         {
00856                 // compute dest info.
00857                 //==============
00858                 // Are we on a vertical edge or horizontal edge??
00859                 uint    stride= (edge&1)==0? NL_TILE_LIGHTMAP_SIZE : 1;
00860 
00861                 // must compute on which tile we must find info.
00862                 sint    decalS=0;
00863                 sint    decalT=0;
00864                 // and must compute ptr, where we store the result of the edge.
00865                 switch(edge)
00866                 {
00867                 case 0: decalS=-1; dest= lightText + 0 + NL_TILE_LIGHTMAP_SIZE; break;
00868                 case 1: decalT= 2; dest= lightText + 1 + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
00869                 case 2: decalS= 2; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + NL_TILE_LIGHTMAP_SIZE; break;
00870                 case 3: decalT=-1; dest= lightText + 1; break;
00871                 };
00872 
00873                 // compute the second tile dest info.
00874                 CRGBA   *dest2;
00875                 sint    decalS2;
00876                 sint    decalT2;
00877                 // if vertical edge.
00878                 if((edge&1)==0)
00879                 {
00880                         // Next Y tile.
00881                         dest2= dest + NL_LUMEL_BY_TILE*NL_TILE_LIGHTMAP_SIZE;
00882                         decalS2= decalS;
00883                         decalT2= decalT+1;
00884                 }
00885                 else
00886                 {
00887                         // Next X tile.
00888                         dest2= dest + NL_LUMEL_BY_TILE;
00889                         decalS2= decalS+1;
00890                         decalT2= decalT;
00891                 }
00892 
00893 
00894                 // If we are not on a border of a patch, just compute on the interior of the patch.
00895                 //==============
00896                 if(!edgeBorder[edge])
00897                 {
00898                         // find the result on the mirrored border of us. First tile.
00899                         computeTileLightmapEdge(ts+decalS, tt+decalT, (edge+2)&3, dest, stride, false);
00900 
00901                         // find the result on the mirrored border of us. Second Tile.
00902                         computeTileLightmapEdge(ts+decalS2, tt+decalT2, (edge+2)&3, dest2, stride, false);
00903 
00904                 }
00905                 // else, slightly complicated, must find the result on neighbor patch(s).
00906                 //==============
00907                 else
00908                 {
00909                         CPatchUVLocator         uvLocator;
00910                         CBindInfo                       bindInfo;
00911                         bindInfo.Zone= NULL;
00912 
00913                         // if smmothed edge, search the neighbor.
00914                         if(getSmoothFlag(edge))
00915                         {
00916                                 // Build the bindInfo against this edge.
00917                                 getBindNeighbor(edge, bindInfo);
00918 
00919                                 // if ok, build the uv info against this edge.
00920                                 if(bindInfo.Zone)
00921                                 {
00922                                         uvLocator.build(this, edge, bindInfo);
00923                                         // if there is not same tile order across the edge, invalidate the smooth.
00924                                         // This is rare, so don't bother.
00925                                         if(!uvLocator.sameEdgeOrder())
00926                                                 bindInfo.Zone= NULL;
00927                                 }
00928                         }
00929 
00930 
00931                         // Fast reject: if no neighbor, or if not smoothed, or if edge order pb, just copy from my interior.
00932                         if(!bindInfo.Zone)
00933                         {
00934                                 CRGBA   *src=0;
00935                                 switch(edge)
00936                                 {
00937                                 case 0: src= dest + 1; break;
00938                                 case 1: src= dest - NL_TILE_LIGHTMAP_SIZE; break;
00939                                 case 2: src= dest - 1; break;
00940                                 case 3: src= dest + NL_TILE_LIGHTMAP_SIZE; break;
00941                                 };
00942                                 
00943                                 // fill the NL_LUMEL_BY_TILE*2 (8) pixels.
00944                                 for(uint n=NL_LUMEL_BY_TILE*2; n>0; n--, src+=stride, dest+=stride)
00945                                         *dest= *src;
00946                         }
00947                         // else, ok, get from neighbor.
00948                         else
00949                         {
00950                                 CVector2f       stIn, stOut;
00951                                 CPatch          *patchOut;
00952                                 uint            patchId;
00953                                 uint            edgeOut;
00954                                 bool            inverse;
00955 
00956                                 // First Tile.
00957                                 //=========
00958                                 // to remove floor pbs, take the center of the wanted tile.
00959                                 stIn.set(ts+decalS + 0.5f, tt+decalT + 0.5f);
00960                                 patchId= uvLocator.selectPatch(stIn);
00961                                 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00962                                 // must find what edge on neighbor to compute, and if we must inverse (swap) result.
00963                                 // easy: the edge of the tile is the edge of the patch where we are binded.
00964                                 edgeOut= bindInfo.Edge[patchId];
00965                                 // edge0 is oriented in T increasing order. edge1 is oriented in S increasing order.
00966                                 // edge2 is oriented in T decreasing order. edge3 is oriented in S decreasing order.
00967                                 // inverse is true if same sens on both edges (because of mirroring, sens should be different).
00968                                 inverse= (edge>>1)==(edgeOut>>1);
00969                                 // compute the lightmap on the edge of the neighbor.
00970                                 patchOut->computeTileLightmapEdge((sint)floor(stOut.x), (sint)floor(stOut.y), edgeOut, dest, stride, inverse);
00971 
00972                                 // Second Tile.
00973                                 //=========
00974                                 // same reasoning.
00975                                 stIn.set(ts+decalS2 + 0.5f, tt+decalT2 + 0.5f);
00976                                 patchId= uvLocator.selectPatch(stIn);
00977                                 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00978                                 edgeOut= bindInfo.Edge[patchId];
00979                                 inverse= (edge>>1)==(edgeOut>>1);
00980                                 patchOut->computeTileLightmapEdge((sint)floor(stOut.x), (sint)floor(stOut.y), edgeOut, dest2, stride, inverse);
00981                         }
00982 
00983                 }
00984         }
00985 
00986 
00987         // Compute corners of the TessBlock.
00988         //=================
00989         bool    cornerOnPatchEdge[4];
00990         bool    cornerOnPatchCorner[4];
00991         // where are we on a edge border of a patch??
00992         cornerOnPatchEdge[0]= edgeBorder[3] != edgeBorder[0];
00993         cornerOnPatchEdge[1]= edgeBorder[0] != edgeBorder[1];
00994         cornerOnPatchEdge[2]= edgeBorder[1] != edgeBorder[2];
00995         cornerOnPatchEdge[3]= edgeBorder[2] != edgeBorder[3];
00996         // where are we on a corner border of a patch??
00997         cornerOnPatchCorner[0]= edgeBorder[3] && edgeBorder[0];
00998         cornerOnPatchCorner[1]= edgeBorder[0] && edgeBorder[1];
00999         cornerOnPatchCorner[2]= edgeBorder[1] && edgeBorder[2];
01000         cornerOnPatchCorner[3]= edgeBorder[2] && edgeBorder[3];
01001 
01002         // For all corners.
01003         for(corner=0; corner<4; corner++)
01004         {
01005                 // compute dest info.
01006                 //==============
01007                 // must compute on which tile we must find info.
01008                 sint    decalS=0;
01009                 sint    decalT=0;
01010                 // and must compute ptr, where we store the result of the corner.
01011                 switch(corner)
01012                 {
01013                 case 0: decalS=-1; decalT=-1; dest= lightText + 0 + 0; break;
01014                 case 1: decalS=-1; decalT= 2; dest= lightText + 0 + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
01015                 case 2: decalS= 2; decalT= 2; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + (NL_TILE_LIGHTMAP_SIZE-1)*NL_TILE_LIGHTMAP_SIZE; break;
01016                 case 3: decalS= 2; decalT=-1; dest= lightText + (NL_TILE_LIGHTMAP_SIZE-1) + 0; break;
01017                 };
01018 
01019 
01020                 // If we are not on a border of a patch, just compute on the interior of the patch.
01021                 //==============
01022                 // if the corner is IN the patch.
01023                 if(!cornerOnPatchCorner[corner] && !cornerOnPatchEdge[corner])
01024                 {
01025                         // what pixel to read.
01026                         uint    subS, subT;
01027                         if(decalS==-1)  subS= NL_LUMEL_BY_TILE-1;
01028                         else                    subS= 0;
01029                         if(decalT==-1)  subT= NL_LUMEL_BY_TILE-1;
01030                         else                    subT= 0;
01031 
01032                         // find the result on the corner of the neighbor tile.
01033                         computeTileLightmapPixel(ts+decalS, tt+decalT, subS, subT, dest);
01034                 }
01035                 else
01036                 {
01037                         // By default, fill the corner with our interior corner. Because other methods may fail.
01038                         CRGBA   *src=0;
01039                         switch(corner)
01040                         {
01041                         case 0: src= dest + 1 + NL_TILE_LIGHTMAP_SIZE; break;
01042                         case 1: src= dest + 1 - NL_TILE_LIGHTMAP_SIZE; break;
01043                         case 2: src= dest - 1 - NL_TILE_LIGHTMAP_SIZE; break;
01044                         case 3: src= dest - 1 + NL_TILE_LIGHTMAP_SIZE; break;
01045                         };
01046                         
01047                         // fill the pixel.
01048                         *dest= *src;
01049 
01050                         // get the coordinate of the corner, in our [0,Order] basis. get it at the center of the pixel.
01051                         CBindInfo                       bindInfo;
01052                         CPatchUVLocator         uvLocator;
01053                         CVector2f                       stIn, stOut;
01054                         CPatch                          *patchOut;
01055                         uint                            patchId;
01056                         float                           decX, decY;
01057                         static const float      lumelSize= 1.f/NL_LUMEL_BY_TILE;
01058                         static const float      semiLumelSize= 0.5f*lumelSize;
01059 
01060                         if(decalS==-1)  decX= -  semiLumelSize;
01061                         else                    decX= 2+ semiLumelSize;
01062                         if(decalT==-1)  decY= -  semiLumelSize;
01063                         else                    decY= 2+ semiLumelSize;
01064                         stIn.set( ts+decX, tt+decY);
01065 
01066 
01067                         // if the corner is on One edge only of the patch.
01068                         if(cornerOnPatchEdge[corner])
01069                         {
01070                                 // find the edge where to read this corner: hard edge after or before this corner.
01071                                 if(edgeBorder[corner])  edge= corner;
01072                                 else                                    edge= (corner+4-1) & 3;
01073 
01074                                 // if this edge is smoothed, find on neighbor.
01075                                 if(getSmoothFlag(edge))
01076                                 {
01077                                         // retrieve neigbhor info.
01078                                         getBindNeighbor(edge, bindInfo);
01079 
01080                                         // if neighbor present.
01081                                         if(bindInfo.Zone)
01082                                         {
01083                                                 // Ok, search uv on this patch.
01084                                                 uvLocator.build(this, edge, bindInfo);
01085                                                 patchId= uvLocator.selectPatch(stIn);
01086                                                 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
01087 
01088                                                 // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis), and get from neighbor patch
01089                                                 sint    u, v;
01090                                                 u= (sint)floor(stOut.x*NL_LUMEL_BY_TILE);
01091                                                 v= (sint)floor(stOut.y*NL_LUMEL_BY_TILE);
01092                                                 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);
01093                                         }
01094                                 }
01095                                 // else we must still smooth with our lumel on this patch, so get it from neighbor on edge.
01096                                 else
01097                                 {
01098                                         // first, clamp to our patch (recenter on the previous pixel)
01099                                         if(stIn.x<0)                    stIn.x+= lumelSize;
01100                                         else if(stIn.x>OrderS)  stIn.x-= lumelSize;
01101                                         else if(stIn.y<0)               stIn.y+= lumelSize;
01102                                         else if(stIn.y>OrderT)  stIn.y-= lumelSize;
01103 
01104                                         // Get the Uv, in [0,Order?*NL_LUMEL_BY_TILE] basis (ie lumel basis), and get from this patch
01105                                         sint    u, v;
01106                                         u= (sint)floor(stIn.x*NL_LUMEL_BY_TILE);
01107                                         v= (sint)floor(stIn.y*NL_LUMEL_BY_TILE);
01108                                         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);
01109                                 }
01110                         }
01111                         // else it is on a corner of the patch.
01112                         else
01113                         {
01114                                 // if the corner of the patch (same as tile corner) is smoothed, find on neighbor
01115                                 if(getCornerSmoothFlag(corner))
01116                                 {
01117                                         // retrieve neigbhor info. NB: use edgeId=corner, (corner X is the start of the edge X)it works.
01118                                         getBindNeighbor(corner, bindInfo);
01119 
01120                                         // if neighbor present.
01121                                         if(bindInfo.Zone)
01122                                         {
01123                                                 // Ok, search uv on this patch.
01124                                                 uvLocator.build(this, corner, bindInfo);
01125                                                 patchId= uvLocator.selectPatch(stIn);
01126                                                 uvLocator.locateUV(stIn, patchId, patchOut, stOut);
01127 
01128                                                 // same reasoning as in computeDisplaceCornerSmooth(), must find the pixel on the neighbor 
01129                                                 // of our neighbor. But the current corner may be a corner on a bind X/1. All is managed by doing
01130                                                 // this way.
01131                                                 patchOut->computeTileLightmapPixelAroundCorner(stOut, dest, true);
01132                                         }
01133                                 }
01134                         }
01135                 }
01136 
01137         }
01138 
01139 
01140 }
01141 
01142 
01143 // ***************************************************************************
01144 void            CPatch::getTileLightMap(uint ts, uint tt, CPatchRdrPass *&rdrpass)
01145 {
01146         // TessBlocks must have been allocated.
01147         nlassert(TessBlocks.size()!=0);
01148 
01149         // get what tessBlock to use.
01150         uint    numtb, numtm;
01151         computeTbTm(numtb, numtm, ts, tt);
01152         CTessBlock      &tessBlock= TessBlocks[numtb];
01153 
01154         // If the lightmap Id has not been computed, compute it.
01155         if(tessBlock.LightMapRefCount==0)
01156         {
01157                 // Compute the lightmap texture, with help of TileColors, with neighboring info etc...
01158                 CRGBA   lightText[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE];
01159                 computeNearBlockLightmap(ts&(~1), tt&(~1), lightText);
01160 
01161                 // Create a rdrPass with this texture, donlod to Driver etc...
01162                 tessBlock.LightMapId= Zone->Landscape->getTileLightMap(lightText, rdrpass);
01163 
01164                 // store this rdrpass ptr.
01165                 tessBlock.LightMapRdrPass= rdrpass;
01166         }
01167 
01168         // We are using this 2x2 tiles lightmap.
01169         tessBlock.LightMapRefCount++;
01170 
01171 
01172         // get the rdrpass ptr of the tessBlock lightmap
01173         rdrpass= tessBlock.LightMapRdrPass;
01174 }
01175 
01176 
01177 // ***************************************************************************
01178 void            CPatch::getTileLightMapUvInfo(uint ts, uint tt, CVector &uvScaleBias)
01179 {
01180         // TessBlocks must have been allocated.
01181         nlassert(TessBlocks.size()!=0);
01182 
01183         // get what tessBlock to use.
01184         uint    numtb, numtm;
01185         computeTbTm(numtb, numtm, ts, tt);
01186         CTessBlock      &tessBlock= TessBlocks[numtb];
01187 
01188         // Get the uvScaleBias for the tile 0,0  of the block.
01189         Zone->Landscape->getTileLightMapUvInfo(tessBlock.LightMapId, uvScaleBias);
01190 
01191         // Must increment the bias, for the good tile in the 2x2 block Lightmap.
01192         uint    tsDec= ts & 1;
01193         uint    ttDec= tt & 1;
01194         uvScaleBias.x+= tsDec * uvScaleBias.z;
01195         uvScaleBias.y+= ttDec * uvScaleBias.z;
01196 }
01197 
01198 
01199 // ***************************************************************************
01200 void            CPatch::releaseTileLightMap(uint ts, uint tt)
01201 {
01202         // TessBlocks must have been allocated.
01203         nlassert(TessBlocks.size()!=0);
01204 
01205         // get what tessBlock to use.
01206         uint    numtb, numtm;
01207         computeTbTm(numtb, numtm, ts, tt);
01208         CTessBlock      &tessBlock= TessBlocks[numtb];
01209 
01210         // If no more tileMaterial use this lightmap, release it.
01211         nlassert(tessBlock.LightMapRefCount>0);
01212         tessBlock.LightMapRefCount--;
01213         if(tessBlock.LightMapRefCount==0)
01214         {
01215                 Zone->Landscape->releaseTileLightMap(tessBlock.LightMapId);
01216         }
01217 }
01218 
01219 // ***************************************************************************
01220 void            CPatch::packShadowMap (const uint8 *pLumelSrc)
01221 {
01222         // Number of lumel by lines
01223         uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
01224 
01225         // Number of block in a line
01226         nlassert ((lumelCount&0x3)==0);
01227         uint numLumelBlock=lumelCount>>2;
01228 
01229         // Number of line
01230         uint lineCount=OrderT*NL_LUMEL_BY_TILE;
01231 
01232         // Number of block line
01233         nlassert ((lineCount&0x3)==0);
01234         uint numLineBlock=lineCount>>2;
01235 
01236         // Resize the compressed buffer
01237         CompressedLumels.resize (numLumelBlock*numLineBlock*NL_BLOCK_LUMEL_COMPRESSED_SIZE);
01238 
01239         // Input of compresed data
01240         uint8 *compressedData=&CompressedLumels[0];
01241 
01242         // Each line block
01243         for (uint lineBlock=0; lineBlock<numLineBlock; lineBlock++)
01244         {
01245                 // Block pointer
01246                 const uint8 *blockLine=pLumelSrc;
01247 
01248                 // Each lumel block
01249                 for (uint lumelBlock=0; lumelBlock<numLumelBlock; lumelBlock++)
01250                 {
01251                         // *** Unpack the block
01252                         uint countU;
01253 
01254                         // Last block ?
01255                         if (lumelBlock==numLumelBlock-1)
01256                                 countU=lumelCount&3;
01257                         else
01258                                 countU=4;
01259 
01260                         // Destination lumel
01261                         const uint8 *blockSrc=blockLine;
01262 
01263                         // Temp block
01264                         uint8 originalBlock[4*4];
01265 
01266                         // Copy the lumels in the bloc
01267                         for (uint v=0; v<NL_LUMEL_BY_TILE; v++)
01268                         {
01269                                 for (uint u=0; u<NL_LUMEL_BY_TILE; u++)
01270                                 {
01271                                         // Copy the lumel
01272                                         originalBlock[(v<<2)+u]=blockSrc[u];
01273                                 }
01274 
01275                                 // Next line
01276                                 blockSrc+=lumelCount;
01277                         }
01278 
01279                         // Get min and max alpha
01280                         uint8 alphaMin=255;
01281                         uint8 alphaMax=0;
01282 
01283                         // Scan
01284                         for (uint i=0; i<16; i++)
01285                         {
01286                                 // Min ?
01287                                 if (originalBlock[i]<alphaMin)
01288                                         alphaMin=originalBlock[i];
01289                                 if (originalBlock[i]>alphaMax)
01290                                         alphaMax=originalBlock[i];
01291                         }
01292 
01293                         // *** Try to compress by 2 methods
01294 
01295                         // Blcok uncompressed
01296                         uint8 uncompressedBlock[4*4];
01297         
01298                         // Pack the block
01299                         packLumelBlock (compressedData, originalBlock, alphaMin, alphaMax);
01300 
01301                         // Unpack the block
01302                         unpackLumelBlock (uncompressedBlock, compressedData);
01303 
01304                         // Eval error
01305                         uint firstMethod=evalLumelBlock (originalBlock, uncompressedBlock, NL_LUMEL_BY_TILE, NL_LUMEL_BY_TILE);
01306 
01307                         // second compression
01308                         uint8 secondCompressedBlock[NL_BLOCK_LUMEL_COMPRESSED_SIZE];
01309                         packLumelBlock (secondCompressedBlock, originalBlock, alphaMax, alphaMin);
01310 
01311                         // Unpack the block
01312                         unpackLumelBlock (uncompressedBlock, secondCompressedBlock);
01313 
01314                         // Eval error
01315                         uint secondMethod=evalLumelBlock (originalBlock, uncompressedBlock, NL_LUMEL_BY_TILE, NL_LUMEL_BY_TILE);
01316 
01317                         // Second best ?
01318                         if (secondMethod<firstMethod)
01319                         {
01320                                 // Copy compressed data
01321                                 memcpy (compressedData, secondCompressedBlock, NL_BLOCK_LUMEL_COMPRESSED_SIZE);
01322                         }
01323 
01324                         // Next source block
01325                         compressedData+=NL_BLOCK_LUMEL_COMPRESSED_SIZE;
01326 
01327                         // Next block on the line
01328                         blockLine+=4;
01329                 }
01330 
01331                 // Next line of block
01332                 pLumelSrc+=lumelCount*4;
01333         }
01334 }
01335 
01336 // ***************************************************************************
01337 void            CPatch::resetCompressedLumels ()
01338 {
01339         // Number of lumel by lines
01340         uint lumelCount=OrderS*NL_LUMEL_BY_TILE;
01341 
01342         // Number of block in a line
01343         nlassert ((lumelCount&0x3)==0);
01344         uint numLumelBlock=lumelCount>>2;
01345 
01346         // Number of line
01347         uint lineCount=OrderT*NL_LUMEL_BY_TILE;
01348 
01349         // Number of block line
01350         nlassert ((lineCount&0x3)==0);
01351         uint numLineBlock=lineCount>>2;
01352 
01353         // Size of the lumel array
01354         uint size=numLineBlock*numLumelBlock*8;
01355 
01356         // 4 bits per lumel
01357         CompressedLumels.resize (size);
01358 
01359         // No line have shadows.
01360         memset (&CompressedLumels[0], 0, size);
01361 }
01362 
01363 
01364 // ***************************************************************************
01365 // ***************************************************************************
01366 // Functions (C/ASM).
01367 // ***************************************************************************
01368 // ***************************************************************************
01369 
01370 
01371 // ***************************************************************************
01372 #define         a00     tex[0]
01373 #define         a10     tex[1]
01374 #define         a20     tex[2]
01375 #define         a30     tex[3]
01376 #define         a40     tex[4]
01377 
01378 #define         a01     tex[5]
01379 #define         a11     tex[6]
01380 #define         a21     tex[7]
01381 #define         a31     tex[8]
01382 #define         a41     tex[9]
01383 
01384 #define         a02     tex[10]
01385 #define         a12     tex[11]
01386 #define         a22     tex[12]
01387 #define         a32     tex[13]
01388 #define         a42     tex[14]
01389 
01390 #define         a03     tex[15]
01391 #define         a13     tex[16]
01392 #define         a23     tex[17]
01393 #define         a33     tex[18]
01394 #define         a43     tex[19]
01395 
01396 #define         a04     tex[20]
01397 #define         a14     tex[21]
01398 #define         a24     tex[22]
01399 #define         a34     tex[23]
01400 #define         a44     tex[24]
01401 
01402 void    NL3D_bilinearTileLightMap(CRGBA *tex)
01403 {
01404         // Fast bilinear of a 5x5 tile.
01405         // Corners must be set.
01406         // Later: pass it to ASM.
01407 
01408         // Fill first column 0 and column 4.
01409         a02.avg2(a00, a04);
01410         a01.avg2(a00, a02);
01411         a03.avg2(a02, a04);
01412         a42.avg2(a40, a44);
01413         a41.avg2(a40, a42);
01414         a43.avg2(a42, a44);
01415 
01416         // Fill Line 0.
01417         a20.avg2(a00, a40);
01418         a10.avg2(a00, a20);
01419         a30.avg2(a20, a40);
01420 
01421         // Fill Line 1.
01422         a21.avg2(a01, a41);
01423         a11.avg2(a01, a21);
01424         a31.avg2(a21, a41);
01425 
01426         // Fill Line 2. 
01427         a22.avg2(a02, a42);
01428         a12.avg2(a02, a22);
01429         a32.avg2(a22, a42);
01430 
01431         // Fill Line 3. 
01432         a23.avg2(a03, a43);
01433         a13.avg2(a03, a23);
01434         a33.avg2(a23, a43);
01435 
01436         // Fill Line 4. 
01437         a24.avg2(a04, a44);
01438         a14.avg2(a04, a24);
01439         a34.avg2(a24, a44);
01440 
01441 }
01442 
01443 
01444 // ***************************************************************************
01445 // ***************************************************************************
01446 // Lightmap get interface.
01447 // ***************************************************************************
01448 // ***************************************************************************
01449 
01450 
01451 // ***************************************************************************
01452 uint8           CPatch::getLumel(const CUV &uv) const
01453 {
01454         // compute tile coord and lumel coord.
01455         sint    ts, tt;
01456         // get in lumel coord.
01457         sint    w= (OrderS<<NL_LUMEL_BY_TILE_SHIFT);
01458         sint    h= (OrderT<<NL_LUMEL_BY_TILE_SHIFT);
01459         // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
01460         // add 128, to round and get cneter of lumel.
01461         ts= OptFastFloor(uv.U* (w<<8) + 128);   ts>>=8;
01462         tt= OptFastFloor(uv.V* (h<<8) + 128);   tt>>=8;
01463         clamp(ts, 0, w-1);
01464         clamp(tt, 0, h-1);
01465         // get the lumel
01466         uint8   ret;
01467         getTileLumelmapPixelPrecomputed(ts>>NL_LUMEL_BY_TILE_SHIFT, tt>>NL_LUMEL_BY_TILE_SHIFT, 
01468                 ts&(NL_LUMEL_BY_TILE-1), tt&(NL_LUMEL_BY_TILE-1), ret);
01469 
01470         return ret;
01471 }
01472 
01473 
01474 // ***************************************************************************
01475 // ***************************************************************************
01476 // TileLightInfluences
01477 // ***************************************************************************
01478 // ***************************************************************************
01479 
01480 
01481 // ***************************************************************************
01482 void            CPatch::resetTileLightInfluences()
01483 {
01484         // Fill default.
01485         TileLightInfluences.resize((OrderS/2 +1) * (OrderT/2 +1));
01486         // Disable All light influence on all points
01487         for(uint i=0;i <TileLightInfluences.size(); i++)
01488         {
01489                 // Disable all light influence on this point.
01490                 TileLightInfluences[i].Light[0]= 0xFF;
01491         }
01492 }
01493 
01494 
01495 // ***************************************************************************
01496 void            CPatch::appendTileLightInfluences(const CUV &uv, 
01497         std::vector<CPointLightInfluence> &pointLightList) const
01498 {
01499         // Compute TLI coord for BiLinear.
01500         sint    x,y;
01501         // There is (OrderS/2+1) * (OrderT/2+1) tileLightInfluences (TLI).
01502         sint    w= (OrderS>>1);
01503         sint    h= (OrderT>>1);
01504         sint    wTLI= w+1;
01505         // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
01506         x= OptFastFloor(uv.U * (w<<8));
01507         y= OptFastFloor(uv.V * (h<<8));
01508         clamp(x, 0, w<<8);
01509         clamp(y, 0, h<<8);
01510         // compute the TLI coord, and the subCoord for bilinear.
01511         sint    xTLI,yTLI, xSub, ySub;
01512         xTLI= x>>8; clamp(xTLI, 0, w-1);
01513         yTLI= y>>8; clamp(yTLI, 0, h-1);
01514         // Hence, xSub and ySub range is [0, 256].
01515         xSub= x - (xTLI<<8);
01516         ySub= y - (yTLI<<8);
01517 
01518 
01519         // Use a CLightInfluenceInterpolator to biLinear light influence
01520         CLightInfluenceInterpolator             interp;
01521         // Must support only 2 light per TLI.
01522         nlassert(CTileLightInfluence::NumLightPerCorner==2);
01523         nlassert(CLightInfluenceInterpolator::NumLightPerCorner==2);
01524         // Get ref on array of PointLightNamed.
01525         CPointLightNamed        *zonePointLights= NULL;
01526         if( getZone()->_PointLightArray.getPointLights().size() >0 )
01527         {
01528                 // const_cast, because will only change _IdInfluence, and 
01529                 // also because CLightingManager will call appendLightedModel()
01530                 zonePointLights= const_cast<CPointLightNamed*>(&(getZone()->_PointLightArray.getPointLights()[0]));
01531         }
01532         // For 4 corners.
01533         for(y=0;y<2;y++)
01534         {
01535                 for(x=0;x<2;x++)
01536                 {
01537                         // get ref on TLI, and on corner.
01538                         const CTileLightInfluence                               &tli= TileLightInfluences[ (yTLI+y)*wTLI + xTLI+x ];
01539                         CLightInfluenceInterpolator::CCorner    &corner= interp.Corners[y*2 + x];
01540                         // For all lights
01541                         uint lid;
01542                         for(lid= 0; lid<CTileLightInfluence::NumLightPerCorner; lid++)
01543                         {
01544                                 // get the id of the light in the zone
01545                                 uint    tliLightId= tli.Light[lid];
01546                                 // If empty id, stop
01547                                 if(tliLightId==0xFF)
01548                                         break;
01549                                 else
01550                                 {
01551                                         // Set pointer of the light in the corner
01552                                         corner.Lights[lid]= zonePointLights + tliLightId;
01553                                 }
01554                         }
01555                         // Reset Empty slots.
01556                         for(; lid<CTileLightInfluence::NumLightPerCorner; lid++)
01557                         {
01558                                 // set to NULL
01559                                 corner.Lights[lid]= NULL;
01560                         }
01561                 }
01562         }
01563         // interpolate.
01564         interp.interpolate(pointLightList, xSub/256.f, ySub/256.f);
01565 }
01566 
01567 
01568 // ***************************************************************************
01569 CRGBA           CPatch::getCurrentTLIColor(uint x, uint y) const
01570 {
01571         CRGBA   ret;
01572         ret= CRGBA::Black;
01573 
01574         // if at least the zone has pointLights, add them.
01575         if( getZone()->_PointLightArray.getPointLights().size() >0 )
01576         {
01577                 const CPointLightNamed  *zonePointLights;
01578                 zonePointLights= (&(getZone()->_PointLightArray.getPointLights()[0]));
01579 
01580                 uint    wTLI= (OrderS>>1)+1;
01581 
01582                 const CTileLightInfluence       &tli= TileLightInfluences[ y*wTLI + x];
01583                 for(uint lid=0;lid<CTileLightInfluence::NumLightPerCorner;lid++)
01584                 {
01585                         // Not influenced by a pointLight?, stop
01586                         if(tli.Light[lid]==0xFF)
01587                                 break;
01588                         // Append the influence of this pointLight. 
01589                         CRGBA   lightCol= zonePointLights[tli.Light[lid]].getDiffuse();
01590                         // modulate with landscape Material.
01591                         lightCol.modulateFromColorRGBOnly(lightCol, getLandscape()->getPointLightDiffuseMaterial() );
01592                         // modulate with precomputed diffuse factor
01593                         lightCol.modulateFromuiRGBOnly(lightCol, tli.getDiffuseLightFactor(lid) );
01594                         // add to the corner
01595                         ret.addRGBOnly(ret, lightCol);
01596                 }
01597         }
01598 
01599         return ret;
01600 }
01601 
01602 
01603 // ***************************************************************************
01604 void            CPatch::getCurrentTileTLIColors(uint ts, uint tt, NLMISC::CRGBA corners[4])
01605 {
01606         // Get ref on array of PointLightNamed.
01607         if( getZone()->_PointLightArray.getPointLights().size() >0 )
01608         {
01609                 // get coord of the tessBlock
01610                 uint    tbs= ts>>1;
01611                 uint    tbt= tt>>1;
01612                 // get tile id local to tessBlock.
01613                 uint    tls= ts-(tbs<<1);
01614                 uint    tlt= tt-(tbt<<1);
01615 
01616                 // For each corner of the tessBlock, compute lighting with pointLights.
01617                 CRGBA   tbCorners[4];
01618                 for(uint y=0;y<2;y++)
01619                 {
01620                         for(uint x=0;x<2;x++)
01621                         {
01622                                 CRGBA   &cornerCol= tbCorners[y*2+x];
01623                                 cornerCol= getCurrentTLIColor(tbs+x, tbt+y);
01624                         }
01625                 }
01626 
01627                 // Then biLinear to tile Level (tessBlock==2x2 tiles).
01628                 CRGBA   tbEdges[4];
01629                 CRGBA   tbMiddle;
01630                 // left.
01631                 tbEdges[0].avg2RGBOnly(tbCorners[0], tbCorners[2]);
01632                 // bottom
01633                 tbEdges[1].avg2RGBOnly(tbCorners[2], tbCorners[3]);
01634                 // right
01635                 tbEdges[2].avg2RGBOnly(tbCorners[1], tbCorners[3]);
01636                 // up
01637                 tbEdges[3].avg2RGBOnly(tbCorners[0], tbCorners[1]);
01638                 // middle.
01639                 tbMiddle.avg2RGBOnly(tbEdges[0], tbEdges[2]);
01640                 
01641                 // just copy result according to tile pos in tessBlock.
01642                 if(tlt==0)
01643                 {
01644                         if(tls==0)
01645                         {
01646                                 corners[0]= tbCorners[0];
01647                                 corners[1]= tbEdges[3];
01648                                 corners[2]= tbEdges[0];
01649                                 corners[3]= tbMiddle;
01650                         }
01651                         else
01652                         {
01653                                 corners[0]= tbEdges[3];
01654                                 corners[1]= tbCorners[1];
01655                                 corners[2]= tbMiddle;
01656                                 corners[3]= tbEdges[2];
01657                         }
01658                 }
01659                 else
01660                 {
01661                         if(tls==0)
01662                         {
01663                                 corners[0]= tbEdges[0];
01664                                 corners[1]= tbMiddle;
01665                                 corners[2]= tbCorners[2];
01666                                 corners[3]= tbEdges[1];
01667                         }
01668                         else
01669                         {
01670                                 corners[0]= tbMiddle;
01671                                 corners[1]= tbEdges[2];
01672                                 corners[2]= tbEdges[1];
01673                                 corners[3]= tbCorners[3];
01674                         }
01675                 }
01676         }
01677         else
01678         {
01679                 // Just fill with 0s.
01680                 corners[0]= CRGBA::Black;
01681                 corners[1]= CRGBA::Black;
01682                 corners[2]= CRGBA::Black;
01683                 corners[3]= CRGBA::Black;
01684         }
01685 }
01686 
01687 // ***************************************************************************
01688 void            CPatch::addTileLightmapWithTLI(uint ts, uint tt, NLMISC::CRGBA *dest, uint stride)
01689 {
01690         // compute colors ar corners of the tile.
01691         CRGBA   corners[4];
01692         getCurrentTileTLIColors(ts, tt, corners);
01693 
01694         // Bilinear accross the tile, and add to dest.
01695         uint    x, y;
01696         for(y=0; y<NL_LUMEL_BY_TILE; y++)
01697         {
01698                 for(x=0; x<NL_LUMEL_BY_TILE; x++)
01699                 {
01700                         // compute this pixel, and add
01701                         bilinearColorAndAdd(corners, x, y, dest[y*stride + x]);
01702                 }
01703         }
01704 }
01705 
01706 // ***************************************************************************
01707 void            CPatch::addTileLightmapEdgeWithTLI(uint ts, uint tt, uint edge, NLMISC::CRGBA *dest, uint stride, bool inverse)
01708 {
01709         // compute colors ar corners of the tile.
01710         CRGBA   corners[4];
01711         getCurrentTileTLIColors(ts, tt, corners);
01712 
01713         // get coordinate according to edge.
01714         uint    x=0,y=0;
01715         switch(edge)
01716         {
01717         case 0: x= 0; break;
01718         case 1: y= NL_LUMEL_BY_TILE-1; break;
01719         case 2: x= NL_LUMEL_BY_TILE-1; break;
01720         case 3: y= 0; break;
01721         };
01722 
01723         // For all lumel of the edge, bilinear.
01724         uint    i;
01725         for(i=0; i<NL_LUMEL_BY_TILE; i++)
01726         {
01727                 // if vertical edge
01728                 if( (edge&1)==0 )       y= i;
01729                 // else horizontal edge
01730                 else                            x= i;
01731 
01732                 // manage inverse.
01733                 uint    where;
01734                 if(inverse)             where= (NL_LUMEL_BY_TILE-1)-i;
01735                 else                    where= i;
01736                 // compute this pixel, and modulate
01737                 bilinearColorAndAdd(corners, x, y, dest[where*stride]);
01738         }
01739 }
01740 
01741 // ***************************************************************************
01742 void            CPatch::addTileLightmapPixelWithTLI(uint ts, uint tt, uint s, uint t, NLMISC::CRGBA *dest)
01743 {
01744         // compute colors ar corners of the tile.
01745         CRGBA   corners[4];
01746         getCurrentTileTLIColors(ts, tt, corners);
01747 
01748         // compute this pixel, and modulate
01749         bilinearColorAndAdd(corners, s, t, *dest);
01750 }
01751 
01752 
01753 // ***************************************************************************
01754 void            CPatch::computeCurrentTLILightmap(NLMISC::CRGBA *array) const
01755 {
01756         // Size of TileLightInfluences
01757         uint    wTLI= (OrderS>>1)+1;
01758         uint    hTLI= (OrderT>>1)+1;
01759         // colros at corners of tiles size.
01760         uint    wTC= OrderS+1;
01761         uint    wTCx2= wTC*2;
01762         uint    hTC= OrderT+1;
01763         uint    x, y;
01764 
01765         // Compute TLI colors at each corner of each TessBlocks.
01766         //=============
01767         for(y=0;y<hTLI;y++)
01768         {
01769                 // store every 2 tiles corners.
01770                 CRGBA   *dst= array + y*2*wTC;
01771                 for(x=0;x<wTLI;x++)
01772                 {
01773                         *dst= getCurrentTLIColor(x, y);
01774                         // skip 2 tiles corners.
01775                         dst++;
01776                         dst++;
01777                 }
01778         }
01779 
01780         // Compute TLI colors at each corner of each Tiles.
01781         //=============
01782 
01783         // Compute corner at middle of vertical TessBlock edges.
01784         for(y=0;y<hTC-1;y+=2)
01785         {
01786                 CRGBA   *dst= array + y*wTC;
01787                 for(x=0;x<wTC;x+=2)
01788                 {
01789                         // Average midlle with cur and next.
01790                         (dst+wTC)->avg2RGBOnly(*dst, *(dst + wTCx2) );
01791 
01792                         // skip 2 tiles corners.
01793                         dst++;
01794                         dst++;
01795                 }
01796         }
01797 
01798         // Compute corner at middle of horizontal TessBlock edges, and at middle of TessBlock.
01799         for(y=0;y<hTC;y++)
01800         {
01801                 CRGBA   *dst= array + y*wTC;
01802                 for(x=0;x<wTC-1;x+=2)
01803                 {
01804                         // Average midlle with cur and next.
01805                         (dst+1)->avg2RGBOnly(*dst, *(dst+2));
01806 
01807                         // skip 2 tiles corners.
01808                         dst++;
01809                         dst++;
01810                 }
01811         }
01812 
01813 
01814 }
01815 
01816 
01817 
01818 // ***************************************************************************
01819 // ***************************************************************************
01820 // UpdateLighting.
01821 // ***************************************************************************
01822 // ***************************************************************************
01823 
01824 
01825 // ***************************************************************************
01826 void CPatch::linkBeforeNearUL(CPatch *patchNext)
01827 {
01828         nlassert(patchNext);
01829 
01830         // first, unlink others from me. NB: works even if _ULNearPrec==_ULNearNext==this.
01831         _ULNearNext->_ULNearPrec= _ULNearPrec;
01832         _ULNearPrec->_ULNearNext= _ULNearNext;
01833         // link to igNext.
01834         _ULNearNext= patchNext;
01835         _ULNearPrec= patchNext->_ULNearPrec;
01836         // link others to me.
01837         _ULNearNext->_ULNearPrec= this;
01838         _ULNearPrec->_ULNearNext= this;
01839 }
01840 
01841 
01842 // ***************************************************************************
01843 void CPatch::unlinkNearUL()
01844 {
01845         // first, unlink others from me. NB: works even if _ULNearPrec==_ULNearNext==this.
01846         _ULNearNext->_ULNearPrec= _ULNearPrec;
01847         _ULNearPrec->_ULNearNext= _ULNearNext;
01848         // reset
01849         _ULNearPrec= this;
01850         _ULNearNext= this;
01851 }
01852 
01853 
01854 // ***************************************************************************
01855 uint CPatch::updateTessBlockLighting(uint numTb)
01856 {
01857         // TessBlocks must have been allocated and tessBlockId must be ok.
01858         nlassert(numTb<TessBlocks.size());
01859 
01860         // compute tessBlock coordinate
01861         uint tbWidth= OrderS>>1;
01862         uint ts= numTb&(tbWidth-1);
01863         uint tt= numTb/tbWidth;
01864         // expand to tile coordinate.
01865         ts*= 2;
01866         tt*= 2;
01867 
01868         // get what tessBlock to use.
01869         CTessBlock      &tessBlock= TessBlocks[numTb];
01870 
01871         // If the lightmap Id has not been computed, quit
01872         if(tessBlock.LightMapRefCount==0)
01873                 return 0;
01874         else
01875         {
01876                 // Recompute the lightmap texture, with help of TileColors, with neighboring info etc...
01877                 CRGBA   lightText[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE];
01878                 computeNearBlockLightmap(ts&(~1), tt&(~1), lightText);
01879 
01880                 // donlod this texture to Driver etc...
01881                 Zone->Landscape->refillTileLightMap(tessBlock.LightMapId, lightText);
01882 
01883                 // return number of pixels computed.
01884                 return  NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE;
01885         }
01886 }
01887 
01888 
01889 // ***************************************************************************
01890 // ***************************************************************************
01891 // ***************************************************************************
01892 // ***************************************************************************
01893 
01894 
01895 // ***************************************************************************
01896 void                            CPatch::addRefDLMContext()
01897 {
01898         // the patch must be compiled.
01899         nlassert(Zone);
01900 
01901         // if 0, create the context.
01902         if(_DLMContextRefCount==0)
01903         {
01904                 nlassert(_DLMContext==NULL);
01905                 _DLMContext= new CPatchDLMContext;
01906                 // init now the context.
01907                 _DLMContext->generate(this, getLandscape()->getTextureDLM(), getLandscape()->getPatchDLMContextList());
01908 
01909                 // If the patch is visible, it may have Far Vertices created, 
01910                 // hence, we must refill them with good DLM Uvs.
01911                 if(!RenderClipped)
01912                 {
01913                         // setup DLM Uv with new _DLMContext
01914                         fillVBFarsDLMUvOnly();
01915                 }
01916         }
01917 
01918         // incRef.
01919         _DLMContextRefCount++;
01920 }
01921 
01922 // ***************************************************************************
01923 void                            CPatch::decRefDLMContext(uint count)
01924 {
01925         // the patch must be compiled.
01926         nlassert(Zone);
01927         nlassert(_DLMContextRefCount>0);
01928 
01929         // dec Ref.
01930         _DLMContextRefCount-= count;
01931         nlassert(_DLMContextRefCount>=0);
01932 
01933         // If 0, delete the context.
01934         if(_DLMContextRefCount==0)
01935         {
01936                 delete _DLMContext;
01937                 _DLMContext= NULL;
01938 
01939                 // If the patch is visible, it may have Far Vertices created, 
01940                 // hence, we must reset their DLM Uvs (to point to black pixel)
01941                 if(!RenderClipped)
01942                 {
01943                         // setup DLM Uv with new _DLMContext
01944                         fillVBFarsDLMUvOnly();
01945                 }
01946         }
01947 }
01948 
01949 
01950 // ***************************************************************************
01951 void            CPatch::beginDLMLighting()
01952 {
01953         nlassert(_DLMContext);
01954 
01955         // Must bkup prec pointLightCount in OldPointLightCount, and reset CurPointLightCount
01956         _DLMContext->OldPointLightCount= _DLMContext->CurPointLightCount;
01957         _DLMContext->CurPointLightCount= 0;
01958 
01959         // clear lighting, only if patch is visible
01960         if(!RenderClipped)
01961                 // NB: no-op if src is already full black.
01962                 _DLMContext->clearLighting();
01963 
01964 }
01965 
01966 // ***************************************************************************
01967 void            CPatch::processDLMLight(CPatchDLMPointLight &pl)
01968 {
01969         // add reference to currentLight, creating DLMContext if needed
01970         addRefDLMContext();
01971 
01972         // add curLight counter
01973         _DLMContext->CurPointLightCount++;
01974 
01975         // compute lighting, only if patch is visible
01976         if(!RenderClipped)
01977                 _DLMContext->addPointLightInfluence(pl);
01978 }
01979 
01980 // ***************************************************************************
01981 void            CPatch::endDLMLighting()
01982 {
01983         nlassert(_DLMContext);
01984 
01985         // delete reference from old pointLight influences, at prec render() pass. _DLMContext may be deleted here,
01986         // if no more lights use it, and if the patch is not in Near.
01987         decRefDLMContext(_DLMContext->OldPointLightCount);
01988 }
01989 
01990 
01991 } // NL3D
01992