# 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  

patchdlm_context.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 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 #include "std3d.h"
00027 
00028 #include "3d/patchdlm_context.h"
00029 #include "3d/patch.h"
00030 #include "3d/bezier_patch.h"
00031 #include "3d/point_light.h"
00032 #include "3d/texture_dlm.h"
00033 #include "3d/fast_floor.h"
00034 #include "3d/tile_far_bank.h"
00035 #include "3d/landscape.h"
00036 #include "nel/misc/system_info.h"
00037 #include "nel/misc/fast_mem.h"
00038 
00039 
00040 using namespace std;
00041 using namespace NLMISC;
00042 
00043 namespace NL3D 
00044 {
00045 
00046 // ***************************************************************************
00047 // ***************************************************************************
00048 // ***************************************************************************
00049 
00050 
00051 // ***************************************************************************
00052 void            CPatchDLMPointLight::compile(const CPointLight &pl, NLMISC::CRGBA landDiffMat, float maxAttEnd)
00053 {
00054         nlassert(maxAttEnd>0);
00055 
00056         // copy color
00057         R= (float) (( pl.getDiffuse().R*(landDiffMat.R+1) ) >>8);
00058         G= (float) (( pl.getDiffuse().G*(landDiffMat.G+1) ) >>8);
00059         B= (float) (( pl.getDiffuse().B*(landDiffMat.B+1) ) >>8);
00060         // Copy Spot/Pos/Dir.
00061         IsSpot= pl.getType() == CPointLight::SpotLight;
00062         Pos= pl.getPosition();
00063         Dir= pl.getSpotDirection();
00064         
00065         // compute spot params
00066         if(IsSpot)
00067         {
00068                 CosMax= cosf(pl.getSpotAngleBegin());
00069                 CosMin= cosf(pl.getSpotAngleEnd());
00070         }
00071         else
00072         {
00073                 // with tesse Values, we have always (cosSpot-CosMin) * OOCosDelta > 1.0f
00074                 CosMax= -1;
00075                 CosMin= -2;
00076         }
00077         OOCosDelta= 1.f / (CosMax-CosMin);
00078 
00079         // compute att params
00080         AttMax= pl.getAttenuationEnd();
00081         AttMin= pl.getAttenuationBegin();
00082         // infinite pointLight?
00083         if(AttMax==0)
00084         {
00085                 AttMax= maxAttEnd;
00086                 AttMin= maxAttEnd*0.99f;
00087         }
00088         // To big pointLigt?
00089         else if(AttMax>maxAttEnd)
00090         {
00091                 AttMax= maxAttEnd;
00092                 AttMin= min(AttMin, maxAttEnd*0.99f);
00093         }
00094         // compile distance
00095         OOAttDelta= 1.f / (AttMin-AttMax);
00096 
00097 
00098         // Compute bounding sphere.
00099         // If not a spot or if angleMin>Pi/2
00100         if(!IsSpot || CosMin<0)
00101         {
00102                 // Take sphere of pointlight sphere
00103                 BSphere.Center= Pos;
00104                 BSphere.Radius= AttMax;
00105                 // The bbox englobe the sphere.
00106                 BBox.setCenter(Pos);
00107                 BBox.setHalfSize(CVector(AttMax, AttMax, AttMax));
00108         }
00109         else
00110         {
00111                 // Compute BSphere.
00112                 //==============
00113 
00114                 // compute sinus of AngleMin
00115                 float   sinMin= sqrtf(1-sqr(CosMin));
00116 
00117                 // Test 2 centers: Center of radius along Dir: Pos+Dir*AttMax/2, and intersection of end cone with line (Pos,Dir)
00118                 // Don't know why but I think they are sufficiently good :)
00119                 // See below for computing of those centers.
00120 
00121                 /* compute radius of each sphere by taking max of 3 distances: distance to spotLight center, distance
00122                         to spotLight forward extremity, and distance to spotLight circle interstion Cone/Sphere. (named DCCS)
00123                         NB: Do the compute with radius=1 at first, then multiply later.
00124                 */
00125                 float   radius1= 0.5f;          // =max(0.5, 0.5); max distance to spot center and extremity center :)
00126                 // for distance DCCS, this is the hypothenuse of (cosMin-0.5) + sinMin.
00127                 float   dccs= sqrtf( sqr(CosMin-0.5f) + sqr(sinMin));
00128                 // take the bigger.
00129                 radius1= max(radius1, dccs );
00130 
00131                 // Same reasoning for center2.
00132                 float   radius2= max(CosMin, 1-CosMin); // max distance to spot center and extremity center :)
00133                 // for distance DCCS, it is simply sinMin!!
00134                 dccs= sinMin;
00135                 // take the bigger.
00136                 radius2= max(radius2, dccs );
00137 
00138 
00139                 // Then take the center which gives the smaller sphere
00140                 if(radius1<radius2)
00141                 {
00142                         BSphere.Center= Pos + (Dir*0.5f*AttMax);
00143                         // radius1 E [0,1], must take real size.
00144                         BSphere.Radius= radius1 * AttMax;
00145                 }
00146                 else
00147                 {
00148                         BSphere.Center= Pos + (Dir*CosMin*AttMax);
00149                         // radius2 E [0,1], must take real size.
00150                         BSphere.Radius= radius2 * AttMax;
00151                 }
00152 
00153 
00154                 // Compute BBox.
00155                 //==============
00156                 
00157                 // just take bbox of the sphere, even if not optimal.
00158                 BBox.setCenter(BSphere.Center);
00159                 float   rad= BSphere.Radius;
00160                 BBox.setHalfSize( CVector(rad, rad, rad) );
00161         }
00162 }
00163 
00164 
00165 // ***************************************************************************
00166 // ***************************************************************************
00167 // ***************************************************************************
00168 
00169 
00170 // ***************************************************************************
00171 CPatchDLMContext::CPatchDLMContext()
00172 {
00173         _Patch= NULL;
00174         _DLMTexture= NULL;
00175         _DLMContextList= NULL;
00176         OldPointLightCount= 0;
00177         CurPointLightCount= 0;
00178         // By default there is crash in textures
00179         _IsSrcTextureFullBlack= false;
00180         _IsDstTextureFullBlack= false;
00181 }
00182 
00183 
00184 // ***************************************************************************
00185 CPatchDLMContext::~CPatchDLMContext()
00186 {
00187         // release the lightmap in the texture
00188         if(_DLMTexture)
00189         {
00190                 _DLMTexture->releaseLightMap(TextPosX, TextPosY);
00191         }
00192         // exit
00193         _Patch= NULL;
00194         _DLMTexture= NULL;
00195 
00196         // remove it from list.
00197         if(_DLMContextList)
00198                 _DLMContextList->remove(this);
00199 }
00200 
00201 
00202 // ***************************************************************************
00203 #ifdef NL_DLM_TILE_RES
00204 // if tileRes defined, still start to clip at tessBlockLevel.
00205 #define NL_DLM_CLIP_FACTOR              2
00206 #else
00207 // start to clip at tessBlockLevel (same as dlm map precision)
00208 #define NL_DLM_CLIP_FACTOR              1
00209 #endif
00210 
00211 #define NL_DLM_CLIP_NUM_LEVEL   3
00212 
00213 // ***************************************************************************
00214 bool                    CPatchDLMContext::generate(CPatch *patch, CTextureDLM *textureDLM, CPatchDLMContextList *ctxList)
00215 {
00216         nlassert(patch);
00217         nlassert(textureDLM);
00218         nlassert(ctxList);
00219 
00220         // keep info on patch/landscape.
00221         _Patch= patch;
00222         _DLMTexture= textureDLM;
00223         // append to the list.
00224         _DLMContextList= ctxList;
00225         _DLMContextList->append(this);
00226 
00227         // Get Texture Size info; 
00228 #ifdef NL_DLM_TILE_RES
00229         // get coord at cornes of tiles
00230         Width= (_Patch->getOrderS())+1;
00231         Height= (_Patch->getOrderT())+1;
00232 #else
00233         // get coord at cornes of tessBlocks
00234         Width= (_Patch->getOrderS()/2)+1;
00235         Height= (_Patch->getOrderT()/2)+1;
00236 #endif
00237 
00238         // Allocate space in texture
00239         if(!_DLMTexture->createLightMap(Width, Height, TextPosX, TextPosY))
00240         {
00241                 // Mark as not allocated.
00242                 // NB: the context still work with NULL _DLMTexture, but do nothing (excpetionnal case)
00243                 _DLMTexture= NULL;
00244         }
00245 
00246         // If the lightmap is correclty allocated in the global texture, compute UVBias.
00247         if(_DLMTexture)
00248         {
00249                 // Compute patch UV matrix from pixels. Must map to center of pixels.
00250                 DLMUScale= (float)(Width-1) / (float)_DLMTexture->getWidth();
00251                 DLMVScale= (float)(Height-1) / (float)_DLMTexture->getHeight();
00252                 DLMUBias= ((float)TextPosX+0.5f) / (float)_DLMTexture->getWidth();
00253                 DLMVBias= ((float)TextPosY+0.5f) / (float)_DLMTexture->getHeight();
00254         }
00255         else
00256         {
00257                 // Build UVBias such that the UVs point to Black
00258                 // NB: TextureDLM ensure that point (MaxX,MaxY) of texture is black.
00259                 DLMUScale= 0;
00260                 DLMVScale= 0;
00261                 DLMUBias= 1;
00262                 DLMVBias= 1;
00263         }
00264 
00265         // TestYoyo: to see lightmap usage in the big texture
00266         /*DLMUScale= _Patch->getOrderS();
00267         DLMVScale= _Patch->getOrderT();
00268         DLMUBias= 0;
00269         DLMVBias= 0;*/
00270 
00271 
00272         // Bound 8bits UV for Vegetable. This is to ensure vegetable Dlm UVs won't peek in neighbor lightmaps.
00273         sint    tmpU, tmpV;
00274         // Bound U minimum
00275         tmpU= (sint)ceil ( (DLMUBias) * 255 );
00276         clamp(tmpU, 0, 255);
00277         MinU8= tmpU;
00278         // Bound U maximum
00279         tmpU= (sint)floor( (DLMUBias+DLMUScale) * 255 );
00280         clamp(tmpU, (sint)MinU8, 255);
00281         MaxU8= tmpU;
00282         // Bound V minimum
00283         tmpV= (sint)ceil ( (DLMVBias) * 255 );
00284         clamp(tmpV, 0, 255);
00285         MinV8= tmpV;
00286         // Bound V maximum
00287         tmpV= (sint)floor( (DLMVBias+DLMVScale) * 255 );
00288         clamp(tmpV, (sint)MinV8, 255);
00289         MaxV8= tmpV;
00290 
00291 
00292         // Allocate RAM Lightmap
00293         _LightMap.resize(Width*Height);
00294 
00295         // generate Vertices: pos and normals
00296         _Vertices.resize(Width*Height);
00297         float   s, t;
00298         float   ds= 1.0f / (Width-1);
00299         float   dt= 1.0f / (Height-1);
00300         // eval all the patch.
00301         t= 0;
00302         uint    x,y;
00303         for(y=0; y<Height; y++, t+=dt)
00304         {
00305                 s= 0;
00306                 for(x=0; x<Width; x++, s+=ds)
00307                 {
00308                         CVertex &vert= _Vertices[y*Width+x];
00309                         // NB: use the bezier patch, and don't take Noise into account, for speed reason.
00310                         CBezierPatch    *bpatch= _Patch->unpackIntoCache();
00311                         // Eval pos.
00312                         vert.Pos= bpatch->eval(s, t);
00313                         // Eval Normal.
00314                         vert.Normal= bpatch->evalNormal(s, t);
00315                 }
00316         }
00317 
00318         // Build bounding Spheres QuadTree
00319         //============
00320 
00321         // Size of the cluster array (at level 0)
00322         uint    bsx, bsy;
00323 #ifdef NL_DLM_TILE_RES
00324         // level 0 is at tile level.
00325         bsx= max(1, (_Patch->getOrderS())/NL_DLM_CLIP_FACTOR );
00326         bsy= max(1, (_Patch->getOrderT())/NL_DLM_CLIP_FACTOR );
00327 #else
00328         // level 0 is at tessBlock level.
00329         bsx= max(1, (_Patch->getOrderS()/2)/NL_DLM_CLIP_FACTOR );
00330         bsy= max(1, (_Patch->getOrderT()/2)/NL_DLM_CLIP_FACTOR );
00331 #endif
00332 
00333         // resize bboxes for level 0.
00334         static  vector<CAABBox>         tmpBBoxes[NL_DLM_CLIP_NUM_LEVEL];
00335         tmpBBoxes[0].resize(bsx * bsy);
00336 
00337         // Extend all leaves clusters BBoxes with patch coordinates
00338         for(y=0;y<bsy;y++)
00339         {
00340                 // For Y, compute how many patch Positions used to extend bbox.
00341                 uint    beginY= y*NL_DLM_CLIP_FACTOR;
00342                 uint    endY= min( (y+1)*NL_DLM_CLIP_FACTOR+1, Height);
00343                 for(x=0;x<bsx;x++)
00344                 {
00345                         // For X, compute how many patch Positions used to extend bbox.
00346                         uint    beginX= x*NL_DLM_CLIP_FACTOR;
00347                         uint    endX= min((x+1)*NL_DLM_CLIP_FACTOR+1, Width);
00348                         // Build a bbox.
00349                         CAABBox         bbox;
00350                         bbox.setCenter(_Vertices[beginY*Width + beginX].Pos);
00351                         for(uint yi= beginY; yi<endY; yi++)
00352                         {
00353                                 for(uint xi= beginX; xi<endX; xi++)
00354                                 {
00355                                         bbox.extend(_Vertices[yi*Width + xi].Pos);
00356                                 }
00357                         }
00358                         // Set the BBox info.
00359                         tmpBBoxes[0][y*bsx + x]= bbox;
00360                 }
00361         }
00362 
00363         // build parent BSpheres for quadTree hierarchy
00364         uint    curLevel= 0;
00365         uint    nextLevel= 1;
00366         uint    nextBsx= max(1U, bsx/2);
00367         uint    nextBsy= max(1U, bsy/2);
00368         // the number of cluster Sons, and descendants this cluster level owns.
00369         uint    tmpClusterNumToSkip[NL_DLM_CLIP_NUM_LEVEL];
00370         // width for this cluster level.
00371         uint    tmpClusterWidth[NL_DLM_CLIP_NUM_LEVEL];
00372         // Number of sons per line/column
00373         uint    tmpClusterWSon[NL_DLM_CLIP_NUM_LEVEL];
00374         uint    tmpClusterHSon[NL_DLM_CLIP_NUM_LEVEL];
00375         // Fill level 0 info
00376         tmpClusterNumToSkip[0]= 0;
00377         tmpClusterWidth[0]= bsx;
00378         tmpClusterWSon[0]= 0;
00379         tmpClusterHSon[0]= 0;
00380         uint    finalClusterSize= bsx * bsy;
00381 
00382         // If the next level has 1x1 cases, it is not usefull (since same sphere as entire Patch)
00383         while(nextBsx * nextBsy > 1 && nextLevel<NL_DLM_CLIP_NUM_LEVEL )
00384         {
00385                 finalClusterSize+= nextBsx * nextBsy;
00386 
00387                 uint    wSon= (bsx/nextBsx);
00388                 uint    hSon= (bsy/nextBsy);
00389                 // compute cluster level info.
00390                 tmpClusterWidth[nextLevel]= nextBsx;
00391                 tmpClusterWSon[nextLevel]= wSon;
00392                 tmpClusterHSon[nextLevel]= hSon;
00393                 // NB: level 0 has 0 sons to skip, hence level1 must skip (1+0)*4= 4  (wSon==hSon==2)
00394                 // level2 must skip (1+4)*4= 20    (wSon==hSon==2)
00395                 tmpClusterNumToSkip[nextLevel]= (1+tmpClusterNumToSkip[curLevel]) * wSon * hSon;
00396 
00397                 // alloc bboxes.
00398                 tmpBBoxes[nextLevel].resize(nextBsx * nextBsy);
00399 
00400                 // For all cluster of upper level, build bb, as union of finers clusters
00401                 for(y=0;y<nextBsy;y++)
00402                 {
00403                         for(x=0;x<nextBsx;x++)
00404                         {
00405                                 // compute coordinate in curLevel tmpBBoxes to look
00406                                 uint    x2= x*wSon;
00407                                 uint    y2= y*hSon;
00408                                 // Build a bbox for 4 (or 2) children clusters
00409                                 if(wSon>1 && hSon>1)
00410                                 {
00411                                         CAABBox         bbox1;
00412                                         CAABBox         bbox2;
00413                                         bbox1= CAABBox::computeAABBoxUnion(
00414                                                 tmpBBoxes[curLevel][y2*bsx + x2], tmpBBoxes[curLevel][y2*bsx + x2+1]);
00415                                         bbox2= CAABBox::computeAABBoxUnion(
00416                                                 tmpBBoxes[curLevel][(y2+1)*bsx + x2], tmpBBoxes[curLevel][(y2+1)*bsx + x2+1]);
00417                                         // final father bbox.
00418                                         tmpBBoxes[nextLevel][y*nextBsx + x]= CAABBox::computeAABBoxUnion(bbox1, bbox2);
00419                                 }
00420                                 else if(wSon==1)
00421                                 {
00422                                         CAABBox         bbox1;
00423                                         bbox1= CAABBox::computeAABBoxUnion(
00424                                                 tmpBBoxes[curLevel][y2*bsx + x2], tmpBBoxes[curLevel][(y2+1)*bsx + x2]);
00425                                         // final father bbox.
00426                                         tmpBBoxes[nextLevel][y*nextBsx + x]= bbox1;
00427                                 }
00428                                 else if(hSon==1)
00429                                 {
00430                                         CAABBox         bbox1;
00431                                         bbox1= CAABBox::computeAABBoxUnion(
00432                                                 tmpBBoxes[curLevel][y2*bsx + x2], tmpBBoxes[curLevel][y2*bsx + x2+1]);
00433                                         // final father bbox.
00434                                         tmpBBoxes[nextLevel][y*nextBsx + x]= bbox1;
00435                                 }
00436                                 else
00437                                         // impossible...
00438                                         nlstop;
00439                         }
00440                 }
00441 
00442                 // upper level.
00443                 bsx= nextBsx;
00444                 bsy= nextBsy;
00445                 nextBsx= max(1U, nextBsx/2);
00446                 nextBsy= max(1U, nextBsy/2);
00447                 curLevel++;
00448                 nextLevel++;
00449         }
00450 
00451 
00452         // Resize clusters with size according to all levels
00453         _Clusters.resize(finalClusterSize);
00454         uint    iDstCluster= 0;
00455 
00456         // Fill cluster hierarchy, in _Clusters.
00457         uint    numLevels= nextLevel;
00458         // NB: the principle is recursive, but it is "iterated", with a stack-like: tmpClusterX and tmpClusterY;
00459         uint    tmpClusterX[NL_DLM_CLIP_NUM_LEVEL];
00460         uint    tmpClusterY[NL_DLM_CLIP_NUM_LEVEL];
00461         uint    tmpClusterXMin[NL_DLM_CLIP_NUM_LEVEL];
00462         uint    tmpClusterYMin[NL_DLM_CLIP_NUM_LEVEL];
00463         uint    tmpClusterXMax[NL_DLM_CLIP_NUM_LEVEL];
00464         uint    tmpClusterYMax[NL_DLM_CLIP_NUM_LEVEL];
00465         // we start at curLevel (the highest Level), and we must fill all the squares of this level
00466         tmpClusterX[curLevel]= 0;
00467         tmpClusterY[curLevel]= 0;
00468         tmpClusterXMin[curLevel]= 0;
00469         tmpClusterYMin[curLevel]= 0;
00470         tmpClusterXMax[curLevel]= bsx;
00471         tmpClusterYMax[curLevel]= bsy;
00472         // while the "root" level is not pop
00473         while(curLevel < numLevels)
00474         {
00475                 // If we ended with this level (all lines done).
00476                 if(tmpClusterY[curLevel] >= tmpClusterYMax[curLevel])
00477                 {
00478                         // Ok, finished with this level, pop up.
00479                         curLevel++;
00480                         // skip.
00481                         continue;
00482                 }
00483 
00484                 nlassert(iDstCluster<_Clusters.size());
00485 
00486                 // get the bbox from current position.
00487                 CAABBox bbox= tmpBBoxes[curLevel][ tmpClusterY[curLevel] * tmpClusterWidth[curLevel] + tmpClusterX[curLevel] ];
00488                 // Fill _Clusters for this square.
00489                 _Clusters[iDstCluster].BSphere.Center= bbox.getCenter(); 
00490                 _Clusters[iDstCluster].BSphere.Radius= bbox.getRadius(); 
00491                 // If leaf level, fill special info
00492                 if(curLevel == 0)
00493                 {
00494                         _Clusters[iDstCluster].NSkips= 0;
00495                         _Clusters[iDstCluster].X= tmpClusterX[0];
00496                         _Clusters[iDstCluster].Y= tmpClusterY[0];
00497                 }
00498                 // else, set total number of sons to skips if "invisible"
00499                 else
00500                         _Clusters[iDstCluster].NSkips= tmpClusterNumToSkip[curLevel];
00501 
00502                 // next dst cluster
00503                 iDstCluster ++;
00504 
00505 
00506                 // If not Leaf level, recurs. First pass, use curLevel params (tmpClusterX...)
00507                 if(curLevel > 0)
00508                 {
00509                         // compute info for next level.
00510                         tmpClusterXMin[curLevel-1]= tmpClusterX[curLevel] * tmpClusterWSon[curLevel];
00511                         tmpClusterYMin[curLevel-1]= tmpClusterY[curLevel] * tmpClusterHSon[curLevel];
00512                         tmpClusterXMax[curLevel-1]= (tmpClusterX[curLevel]+1) * tmpClusterWSon[curLevel];
00513                         tmpClusterYMax[curLevel-1]= (tmpClusterY[curLevel]+1) * tmpClusterHSon[curLevel];
00514                         // begin iteration of child level
00515                         tmpClusterX[curLevel-1]= tmpClusterXMin[curLevel-1];
00516                         tmpClusterY[curLevel-1]= tmpClusterYMin[curLevel-1];
00517                 }
00518 
00519 
00520                 // next square for this level
00521                 tmpClusterX[curLevel]++;
00522                 // if ended for X.
00523                 if(tmpClusterX[curLevel] >= tmpClusterXMax[curLevel])
00524                 {
00525                         // reset X.
00526                         tmpClusterX[curLevel]= tmpClusterXMin[curLevel];
00527                         // next line.
00528                         tmpClusterY[curLevel]++;
00529                 }
00530 
00531 
00532                 // If not Leaf level, recurs. Second pass, after tmpClusterX and tmpClusterY of curLevel are changed
00533                 if(curLevel > 0)
00534                 {
00535                         // descend in hierarchy. (recurs)
00536                         curLevel--;
00537                 }
00538 
00539         }
00540 
00541         // All dst clusters must have been filled
00542         nlassert(iDstCluster == _Clusters.size());
00543 
00544 
00545         // PreProcess Patch TileColors.
00546         //============
00547         // Verify that a CTileColor is nothing more than a 565 color.
00548         nlassert(sizeof(CTileColor)==sizeof(uint16));
00549 #ifndef NL_DLM_TILE_RES
00550 
00551         // retrieve patch tileColor pointer.
00552         nlassert(_Patch->TileColors.size()>0);
00553         CTileColor      *tileColor= &_Patch->TileColors[0];
00554 
00555         // skip 1 tiles colors per column and per row
00556         uint            wTileColor= _Patch->getOrderS()+1;
00557         CTileColor      *tcOrigin= tileColor;
00558         // alloc _LowResTileColors at same resolution than lightmap
00559         _LowResTileColors.resize(Width*Height);
00560         uint16  *dstLRtc= &_LowResTileColors[0];
00561 
00562         // For all lines of dst.
00563         for(y=0;y<Height;y++)
00564         {
00565                 // tileColor start of line.
00566                 tileColor= tcOrigin + y*2* wTileColor;
00567                 sint    npix= Width;
00568                 // for all pixels at corner of tessBlock.
00569                 for(;npix>0; npix--, tileColor+=2, dstLRtc++)
00570                 {
00571                         *dstLRtc= tileColor->Color565;
00572                 }
00573 
00574         }
00575 #endif
00576 
00577 
00578         // compute the TextureFar used for Far dynamic lightmaping.
00579         //============
00580         // NB: simpler to compute it at generate() time, even if not necessarly needed for near
00581         computeTextureFar();
00582 
00583 
00584         // fill texture with Black
00585         //============
00586         clearLighting();
00587 
00588         return true;
00589 }
00590 
00591 // ***************************************************************************
00592 void                    CPatchDLMContext::clearLighting()
00593 {
00594         // If the srcTexture is not already black.
00595         if(!_IsSrcTextureFullBlack)
00596         {
00597                 // Reset Lightmap with black.
00598                 uint    count= _LightMap.size();
00599                 if(count>0)
00600                 {
00601                         memset(&_LightMap[0], 0, count * sizeof(CRGBA));
00602                 }
00603 
00604                 // Now the src lightmap is fully black
00605                 _IsSrcTextureFullBlack= true;
00606         }
00607 }
00608 
00609 
00610 // ***************************************************************************
00611 
00612 // TestYoyo: I thought this code was better, but actually, this is not the case
00613 /*
00614 static  float   NL3D_Val1= 1.f;
00615 inline void     __stdcall fastClamp01(float &x)
00616 {
00617         __asm
00618         {
00619                 mov esi, x
00620                 mov eax, [esi]
00621 
00622                 // clamp to 0.
00623                 cmp eax, 0x80000001             // set carry if sign bit is set.
00624                 sbb ecx, ecx                    // if attDist is negative, ecx==0 , else 0xFFFFFFFF.
00625                 and eax, ecx                    // if attDist is negative, eax=0, else unchanged
00626 
00627                 // clamp eax to 1 (NB: now we are sure eax>=0).
00628                 cmp     eax, NL3D_Val1          // set carry if < Val1.
00629                 sbb     ecx, ecx                        // if < Val1, ecx==0xFFFFFFFF, else 0.
00630                 and     eax, ecx                        // if < Val1, ecx= eax, else ecx=0
00631                 not     ecx
00632                 and     ecx, NL3D_Val1          // if > Val1, ecx== Val1, else ecx= 0.
00633                 add     eax, ecx                        // finally, eax= val clamped to 1.
00634 
00635                 // store.
00636                 mov [esi], eax
00637         }
00638 }*/
00639 
00640 // faster to do a simple clamp ???
00641 inline void     fastClamp01(float &x)
00642 {
00643         clamp(x, 0.f, 1.f);
00644 }
00645 
00646 
00647 // ***************************************************************************
00648 void                    CPatchDLMContext::addPointLightInfluence(const CPatchDLMPointLight &pl)
00649 {
00650         uint            nverts= _Vertices.size();
00651         nlassert(nverts==_LightMap.size());
00652 
00653         if(nverts==0)
00654                 return;
00655         CVertex         *vert= &_Vertices[0];
00656 
00657 
00658         // precise clip: parse the quadTree of sphere
00659         //================
00660         uint    i, x,y;
00661         uint    startX, startY, endX, endY;
00662         startX= 0xFFFFFFFF;
00663         startY= 0xFFFFFFFF;
00664         endX= 0;
00665         endY= 0;
00666         for(i=0;i<_Clusters.size();)
00667         {
00668                 // If the sphere intersect pl, 
00669                 if(_Clusters[i].BSphere.intersect(pl.BSphere) )
00670                 {
00671                         // if this cluster is a leaf, extend start/end
00672                         if(_Clusters[i].NSkips==0)
00673                         {
00674                                 x= _Clusters[i].X;
00675                                 y= _Clusters[i].Y;
00676                                 startX= min(startX, x);
00677                                 startY= min(startY, y);
00678                                 endX= max(endX, x+1);
00679                                 endY= max(endY, y+1);
00680                         }
00681                         // go to next cluster (a brother, a parent or a son)
00682                         i++;
00683                 }
00684                 else
00685                 {
00686                         // if this cluster is a leaf, just go to next cluster (a parent or a brother)
00687                         if(_Clusters[i].NSkips==0)
00688                                 i++;
00689                         // else, go to next brother or parent (NSkips say how to go)
00690                         else
00691                                 i+= _Clusters[i].NSkips;
00692                 }
00693         }
00694         // if never intersect, just quit.
00695         if(startX==0xFFFFFFFF)
00696                 return;
00697 
00698         // get vertices in array to process.
00699         startX*=NL_DLM_CLIP_FACTOR;
00700         startY*=NL_DLM_CLIP_FACTOR;
00701         endX= min(endX*NL_DLM_CLIP_FACTOR+1, Width);
00702         endY= min(endY*NL_DLM_CLIP_FACTOR+1, Height);
00703 
00704         // TestYoyo only.
00705         /*extern uint YOYO_LandDLCount;
00706         YOYO_LandDLCount+= (endX - startX) * (endY - startY);*/
00707         
00708         // process all vertices
00709         //================
00710         float   r,g,b;
00711         CRGBA   *dst= &_LightMap[0];
00712         CVertex         *originVert= vert;
00713         CRGBA           *originDst= dst;
00714 
00715         // TestYoyo: finally, precache does not seems to impact final result.
00716         // precache loading, for better cache use. NB: precache the entire line, ignoring clip result.
00717         // Precache only if interesting.
00718         /*if( (endX - startX)*4>=Width && (endY-startY)>=2)
00719         {
00720                 vert= originVert + startY*Width;
00721                 dst= originDst + startY*Width;
00722                 uint    nPixelLine= (endY-startY)*Width;
00723                 CFastMem::precacheBest(vert, nPixelLine * sizeof(CVertex));
00724                 CFastMem::precacheBest(dst, nPixelLine * sizeof(CRGBA));
00725         }*/
00726 
00727         // Start 24 precision, for faster compute.
00728         OptFastFloorBegin24();
00729 
00730         // If the pointLight is a spot, compute is more complex/slower
00731         if(pl.IsSpot)
00732         {
00733                 for(y=startY; y<endY; y++)
00734                 {
00735                         nverts= endX - startX;
00736 
00737                         vert= originVert + startX + y*Width;
00738                         dst= originDst + startX + y*Width;
00739                         for(;nverts>0; nverts--, vert++, dst++)
00740                         {
00741                                 CVector dirToP= vert->Pos - pl.Pos;
00742                                 float   dist= dirToP.norm();
00743                                 dirToP/= dist;
00744 
00745                                 // compute cos for pl. attenuation
00746                                 float   cosSpot= dirToP * pl.Dir;
00747                                 float   attSpot= (cosSpot-pl.CosMin) * pl.OOCosDelta;
00748                                 fastClamp01(attSpot);
00749 
00750                                 // distance attenuation
00751                                 float   attDist= (dist-pl.AttMax) * pl.OOAttDelta;
00752                                 fastClamp01(attDist);
00753 
00754                                 // compute diffuse lighting
00755                                 float   diff= -(vert->Normal * dirToP);
00756                                 fastClamp01(diff);
00757                                 
00758                                 // compute colors.
00759                                 diff*= attSpot * attDist;
00760                                 r= pl.R*diff;
00761                                 g= pl.G*diff;
00762                                 b= pl.B*diff;
00763 
00764                                 CRGBA   col;
00765                                 col.R= (uint8)OptFastFloor24(r);
00766                                 col.G= (uint8)OptFastFloor24(g);
00767                                 col.B= (uint8)OptFastFloor24(b);
00768 
00769                                 // add to map.
00770 #ifdef NL_OS_WINDOWS
00771                                 // Fast AddClamp.
00772                                 __asm
00773                                 {
00774                                         mov     esi, dst
00775 
00776                                         mov     al, [esi]dst.R
00777                                         add     al, col.R
00778                                         sbb     cl, cl
00779                                         or      al, cl
00780                                         mov     [esi]dst.R, al
00781 
00782                                         mov     al, [esi]dst.G
00783                                         add     al, col.G
00784                                         sbb     cl, cl
00785                                         or      al, cl
00786                                         mov     [esi]dst.G, al
00787 
00788                                         mov     al, [esi]dst.B
00789                                         add     al, col.B
00790                                         sbb     cl, cl
00791                                         or      al, cl
00792                                         mov     [esi]dst.B, al
00793                                 }
00794 #else
00795                                 // add and clamp to map.
00796                                 dst->addRGBOnly(*dst, col);
00797 #endif
00798                         }
00799                 }
00800         }
00801         // else, pointLight with no Spot cone attenuation
00802         else
00803         {
00804                 // TestYoyo
00805                 /*extern        void    YOYO_startDLMItCount();
00806                 YOYO_startDLMItCount();*/
00807 
00808                 // Compute lightmap pixels of interest 
00809                 for(y=startY; y<endY; y++)
00810                 {
00811                         nverts= endX - startX;
00812 
00813                         vert= originVert + startX + y*Width;
00814                         dst= originDst + startX + y*Width;
00815                         for(;nverts>0; nverts--, vert++, dst++)
00816                         {
00817                                 CVector dirToP= vert->Pos - pl.Pos;
00818                                 float   dist= dirToP.norm();
00819                                 float   OODist= 1.0f / dist;
00820                                 dirToP*= OODist;
00821 
00822                                 // distance attenuation
00823                                 float   attDist= (dist-pl.AttMax) * pl.OOAttDelta;
00824                                 fastClamp01(attDist);
00825 
00826                                 // compute diffuse lighting
00827                                 float   diff= -(vert->Normal * dirToP);
00828                                 fastClamp01(diff);
00829                                 
00830                                 // compute colors.
00831                                 diff*= attDist;
00832                                 r= pl.R*diff;
00833                                 g= pl.G*diff;
00834                                 b= pl.B*diff;
00835 
00836                                 CRGBA   col;
00837                                 col.R= (uint8)OptFastFloor24(r);
00838                                 col.G= (uint8)OptFastFloor24(g);
00839                                 col.B= (uint8)OptFastFloor24(b);
00840 
00841                                 // add to map.
00842 #ifdef NL_OS_WINDOWS
00843                                 // Fast AddClamp.
00844                                 __asm
00845                                 {
00846                                         mov     esi, dst
00847 
00848                                         mov     al, [esi]dst.R
00849                                         add     al, col.R
00850                                         sbb     cl, cl
00851                                         or      al, cl
00852                                         mov     [esi]dst.R, al
00853 
00854                                         mov     al, [esi]dst.G
00855                                         add     al, col.G
00856                                         sbb     cl, cl
00857                                         or      al, cl
00858                                         mov     [esi]dst.G, al
00859 
00860                                         mov     al, [esi]dst.B
00861                                         add     al, col.B
00862                                         sbb     cl, cl
00863                                         or      al, cl
00864                                         mov     [esi]dst.B, al
00865                                 }
00866 #else
00867                                 // add and clamp to map.
00868                                 dst->addRGBOnly(*dst, col);
00869 #endif
00870                         }
00871                 }
00872 
00873                 // TestYoyo
00874                 /*extern        void    YOYO_endDLMItCount();
00875                 YOYO_endDLMItCount();*/
00876         }
00877 
00878         // Stop 24 bit precision
00879         OptFastFloorEnd24();
00880 
00881         // Src texture is modified, hence it can't be black.
00882         //==============
00883         _IsSrcTextureFullBlack= false;
00884 }
00885 
00886 
00887 // ***************************************************************************
00888 void                    CPatchDLMContext::compileLighting(TCompileType compType, CRGBA modulateCte)
00889 {
00890         // If srcTexture is full black, and if dst texture is already full black too, don't need to update dst texture
00891         if(! (_IsSrcTextureFullBlack && _IsDstTextureFullBlack) )
00892         {
00893                 // if lightMap allocated
00894                 if(_LightMap.size()>0 && _DLMTexture)
00895                 {
00896                         // If the srcTexture is full black (ie no pointLight influence touch it), 
00897                         if(_IsSrcTextureFullBlack)
00898                         {
00899                                 // reset the texture to full black.
00900                                 _DLMTexture->fillRect(TextPosX, TextPosY, Width, Height, 0);
00901                         }
00902                         // else the srcTexture is not full black (ie some pointLight influence touch it), 
00903                         else
00904                         {
00905                                 // if must modulate with tileColor
00906                                 if(compType == ModulateTileColor)
00907                                 {
00908                                         nlassert(_Patch->TileColors.size()>=0);
00909                                         #ifdef NL_DLM_TILE_RES
00910                                         // retrieve userColor pointer.
00911                                         uint16  *tileColor= (uint16*)(&_Patch->TileColors[0]);
00912                                         #else
00913                                         uint16  *tileColor= (uint16*)(&_LowResTileColors[0]);
00914                                         #endif
00915 
00916                                         // modulate and fill dest.
00917                                         _DLMTexture->modulateAndfillRect565(TextPosX, TextPosY, Width, Height, &_LightMap[0], tileColor);
00918                                 }
00919                                 // else if must modulate with textureFar
00920                                 else if(compType == ModulateTextureFar)
00921                                 {
00922                                         // modulate and fill dest.
00923                                         _DLMTexture->modulateAndfillRect8888(TextPosX, TextPosY, Width, Height, &_LightMap[0], &_TextureFar[0]);
00924                                 }
00925                                 // else if must modulate with constante
00926                                 else if(compType == ModulateConstant)
00927                                 {
00928                                         // modulate and fill dest.
00929                                         _DLMTexture->modulateConstantAndfillRect(TextPosX, TextPosY, Width, Height, &_LightMap[0], modulateCte);
00930                                 }
00931                                 // else, no Modulate.
00932                                 else
00933                                 {
00934                                         // just copy lightmap to texture
00935                                         _DLMTexture->copyRect(TextPosX, TextPosY, Width, Height, &_LightMap[0]);
00936                                 }
00937                         }
00938                 }
00939 
00940 
00941                 // copy full black state
00942                 _IsDstTextureFullBlack= _IsSrcTextureFullBlack;
00943         }
00944 }
00945 
00946 
00947 // ***************************************************************************
00948 uint                    CPatchDLMContext::getMemorySize() const
00949 {
00950         uint    size= sizeof(CPatchDLMContext);
00951         size+= _Vertices.size() * sizeof(CVertex);
00952         size+= _LightMap.size() * sizeof(CRGBA);
00953         size+= _Clusters.size() * sizeof(CCluster);
00954         size+= _TextureFar.size() * sizeof(CRGBA);
00955 #ifndef NL_DLM_TILE_RES
00956         size+= _LowResTileColors.size() * sizeof(uint16);
00957 #endif
00958 
00959         return size;
00960 }
00961 
00962 
00963 // ***************************************************************************
00964 void                    CPatchDLMContext::computeTextureFar()
00965 {
00966         // First compute Far at order1 Level (ie 2x2 pixels per tiles).
00967         //==================
00968         static  vector<CRGBA>   tileFars;
00969         // Get the FarBank from landscape.
00970         CTileFarBank    &farBank= _Patch->getLandscape()->TileFarBank;
00971         // size of the texture.
00972         uint    os= _Patch->getOrderS();
00973         uint    ot= _Patch->getOrderT();
00974         // resize tmp texture. keep a border of 1 pixel around this texture (for average with border)
00975         uint    tfWidth= os*2+2;
00976         uint    tfHeight= ot*2+2;
00977         uint    tfSize= tfWidth * tfHeight;
00978         tileFars.resize(tfSize);
00979         CRGBA   *dst= &tileFars[0];
00980 
00981         // default: fill dst with black (for possible non-existing tiles).
00982         memset(dst, 0, tfSize*sizeof(CRGBA));
00983 
00984         // For all tiles.
00985         uint    x, y;
00986         for(y=0; y<ot; y++)
00987         {
00988                 for(x=0;x<os;x++)
00989                 {
00990                         // get the tile from patch.
00991                         CTileElement    &tileElm= _Patch->Tiles[y*os + x];
00992 
00993                         // For all layers
00994                         for(uint l=0; l<3;l++)
00995                         {
00996                                 uint16          tileId= tileElm.Tile[0];
00997                                 if (tileId!=NL_TILE_ELM_LAYER_EMPTY)
00998                                 {
00999                                         // Get the read only pointer on the far tile
01000                                         const CTileFarBank::CTileFar*   pTile= farBank.getTile (tileId);
01001                                         // if exist.
01002                                         if(pTile && pTile->isFill (CTileFarBank::diffuse))
01003                                         {
01004                                                 // get tile element information.
01005                                                 sint    nRot= tileElm.getTileOrient(l);
01006                                                 bool    is256x256;
01007                                                 uint8   uvOff;
01008                                                 tileElm.getTile256Info(is256x256, uvOff);
01009 
01010                                                 // compute src pixel
01011                                                 const CRGBA     *srcPixel= pTile->getPixels(CTileFarBank::diffuse, CTileFarBank::order1);
01012                                                 // compute src info, for this tile rot and 256x256 context.
01013                                                 sint srcDeltaX;
01014                                                 sint srcDeltaY;
01015                                                 srcPixel= computeTileFarSrcDeltas(nRot, is256x256, uvOff, srcPixel, srcDeltaX, srcDeltaY);
01016 
01017                                                 // compute dst coordinate. start writing at pixel (1,1)
01018                                                 CRGBA   *dstPixel= dst + (y*2+1)*tfWidth + x*2+1;
01019 
01020                                                 if(l==0)
01021                                                 {
01022                                                         // copy the tile content to the texture.
01023                                                         copyTileToTexture(srcPixel, srcDeltaX, srcDeltaY, dstPixel, tfWidth);
01024                                                 }
01025                                                 else
01026                                                 {
01027                                                         // blend the tile content to the texture.
01028                                                         blendTileToTexture(srcPixel, srcDeltaX, srcDeltaY, dstPixel, tfWidth);
01029                                                 }
01030                                         }
01031                                         else
01032                                                 // go to next tile.
01033                                                 break;
01034                                 }
01035                                 else
01036                                         // go to next tile.
01037                                         break;
01038                         }
01039                 }
01040         }
01041 
01042         /* copy borders pixels from border of current patch
01043                 NB: this is not correct, but visually sufficient.
01044                 To look on neighbor would be more complex.
01045         */
01046 
01047         // copy lines up and down.
01048         y= tfHeight-1;
01049         for(x=1;x<tfWidth-1;x++)
01050         {
01051                 // copy line 0 from line 1.
01052                 dst[0*tfWidth + x]= dst[1*tfWidth + x];
01053                 // copy last line from last line-1.
01054                 dst[y*tfWidth + x]= dst[(y-1)*tfWidth + x];
01055         }
01056 
01057         // copy column left and right
01058         x= tfWidth-1;
01059         for(y=1;y<tfHeight-1;y++)
01060         {
01061                 // copy column 0 from column 1.
01062                 dst[y*tfWidth + 0]= dst[y*tfWidth + 1];
01063                 // copy last column from last column-1.
01064                 dst[y*tfWidth + x]= dst[y*tfWidth + x-1];
01065         }
01066 
01067         // copy 4 corners
01068         x= tfWidth-1;
01069         y= tfHeight-1;
01070         // top-left corner
01071         dst[0]= dst[1];
01072         // top-right corner
01073         dst[x]= dst[x-1];
01074         // bottom-left corner
01075         dst[y*tfWidth + 0]= dst[y*tfWidth + 1];
01076         // bottom-right corner
01077         dst[y*tfWidth + x]= dst[y*tfWidth + x-1];
01078 
01079 
01080         // Average to DLM resolution (ie OrderS+1, OrderT+1)
01081         //==================
01082         // resize _TextureFar.
01083         _TextureFar.resize(Width*Height);
01084         CRGBA   *src= &tileFars[0];
01085         dst= &_TextureFar[0];
01086 
01087         // for all pixels of dst texture.
01088         for(y=0;y<Height;y++)
01089         {
01090                 for(x=0;x<Width;x++, dst++)
01091                 {
01092                         // compute coordinate in tileFars.
01093                         uint    x2, y2;
01094 #ifdef  NL_DLM_TILE_RES
01095                         x2= x * 2;
01096                         y2= y * 2;
01097 #else
01098                         // easiest method: sample every 2 tiles.
01099                         x2= x * 4;
01100                         y2= y * 4;
01101 #endif
01102 
01103                         // Average the 4 pixels around this tile corner
01104                         dst->avg4RGBOnly(src[y2*tfWidth + x2], 
01105                                 src[y2*tfWidth + x2+1], 
01106                                 src[(y2+1)*tfWidth + x2], 
01107                                 src[(y2+1)*tfWidth + x2+1]);
01108                 }
01109         }
01110 
01111 
01112         // Modulate result with TileColors.
01113         //==================
01114         nlassert(_Patch->TileColors.size()>=0);
01115         #ifdef NL_DLM_TILE_RES
01116         // retrieve userColor pointer.
01117         uint16  *tileColor= (uint16*)(&_Patch->TileColors[0]);
01118         #else
01119         uint16  *tileColor= (uint16*)(&_LowResTileColors[0]);
01120         #endif
01121 
01122         // For all pixels
01123         dst= &_TextureFar[0];
01124         for(sint n= Width*Height; n>0; n--, dst++, tileColor++)
01125         {
01126                 uint16  tc= *tileColor;
01127                 // modulate R.
01128                 dst->R= ( (tc>>11) * dst->R)>>5;
01129                 // modulate G.
01130                 dst->G= (((tc>>5)&63) * dst->G)>>6;
01131                 // modulate B.
01132                 dst->B= ( (tc&31) * dst->B)>>5;
01133         }
01134 
01135 }
01136 
01137 
01138 
01139 // ***************************************************************************
01140 const CRGBA     *CPatchDLMContext::computeTileFarSrcDeltas(sint nRot, bool is256x256, uint8 uvOff, const CRGBA *srcPixel, sint &srcDeltaX, sint &srcDeltaY)
01141 {
01142         // NB: code copied from CTextureFar::rebuildRectangle()
01143 
01144         // The tileSize at order1 is 2.
01145         uint    tileSize= 2;
01146 
01147         // Source size
01148         sint sourceSize;
01149 
01150         // Source offset (for 256)
01151         uint sourceOffset=0;
01152 
01153         // 256 ?
01154         if (is256x256)
01155         {
01156                 // On the left ?
01157                 if (uvOff&0x02)
01158                         sourceOffset+=tileSize;
01159 
01160                 // On the bottom ?
01161                 if ((uvOff==1)||(uvOff==2))
01162                         sourceOffset+=2*tileSize*tileSize;
01163 
01164                 // Yes, 256
01165                 sourceSize=tileSize<<1;
01166         }
01167         else
01168         {
01169                 // No, 128
01170                 sourceSize=tileSize;
01171         }
01172 
01173         // Compute offset and deltas
01174         switch (nRot)
01175         {
01176         case 0:
01177                 // Source pointers
01178                 srcPixel= srcPixel+sourceOffset;
01179 
01180                 // Source delta
01181                 srcDeltaX=1;
01182                 srcDeltaY=sourceSize;
01183                 break;
01184         case 1:
01185                 {
01186                         // Source pointers
01187                         uint newOffset=sourceOffset+(tileSize-1);
01188                         srcPixel=srcPixel+newOffset;
01189 
01190                         // Source delta
01191                         srcDeltaX=sourceSize;
01192                         srcDeltaY=-1;
01193                 }
01194                 break;
01195         case 2:
01196                 {
01197                         // Destination pointer
01198                         uint newOffset=sourceOffset+(tileSize-1)*sourceSize+tileSize-1;
01199                         srcPixel=srcPixel+newOffset;
01200 
01201                         // Source delta
01202                         srcDeltaX=-1;
01203                         srcDeltaY=-sourceSize;
01204                 }
01205                 break;
01206         case 3:
01207                 {
01208                         // Destination pointer
01209                         uint newOffset=sourceOffset+(tileSize-1)*sourceSize;
01210                         srcPixel=srcPixel+newOffset;
01211 
01212                         // Source delta
01213                         srcDeltaX=-sourceSize;
01214                         srcDeltaY=1;
01215                 }
01216                 break;
01217         }
01218 
01219         return srcPixel;
01220 }
01221 
01222 
01223 // ***************************************************************************
01224 void            CPatchDLMContext::copyTileToTexture(const CRGBA *srcPixel, sint srcDeltaX, sint srcDeltaY, CRGBA *dstPixel, uint dstStride)
01225 {
01226         // copy the 2x2 tile to the texture.
01227 
01228         // first line.
01229         dstPixel[0]= srcPixel[0];
01230         dstPixel[1]= srcPixel[srcDeltaX];
01231         // second line.
01232         dstPixel[0+dstStride]= srcPixel[srcDeltaY];
01233         dstPixel[1+dstStride]= srcPixel[srcDeltaY+srcDeltaX];
01234 }
01235 
01236 // ***************************************************************************
01237 void            CPatchDLMContext::blendTileToTexture(const CRGBA *srcPixel, sint srcDeltaX, sint srcDeltaY, CRGBA *dstPixel, uint dstStride)
01238 {
01239         // blend the 2x2 tile with the texture.
01240         CRGBA   *dst;
01241         CRGBA   src;
01242 
01243         // first line.
01244         dst= &dstPixel[0]; src= srcPixel[0];
01245         dst->blendFromuiRGBOnly(*dst, src, src.A);
01246 
01247         dst= &dstPixel[1]; src= srcPixel[srcDeltaX];
01248         dst->blendFromuiRGBOnly(*dst, src, src.A);
01249 
01250         // second line.
01251         dst= &dstPixel[0+dstStride]; src= srcPixel[srcDeltaY];
01252         dst->blendFromuiRGBOnly(*dst, src, src.A);
01253 
01254         dst= &dstPixel[1+dstStride]; src= srcPixel[srcDeltaY+srcDeltaX];
01255         dst->blendFromuiRGBOnly(*dst, src, src.A);
01256 }
01257 
01258 
01259 } // NL3D