# 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_noise.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 #include "std3d.h"
00027 
00028 
00029 #include "3d/patch.h"
00030 #include "3d/tessellation.h"
00031 #include "3d/bezier_patch.h"
00032 #include "3d/zone.h"
00033 #include "3d/landscape.h"
00034 #include "nel/misc/vector.h"
00035 #include "nel/misc/common.h"
00036 #include "3d/tile_noise_map.h"
00037 #include "3d/patchuv_locator.h"
00038 using   namespace       std;
00039 using   namespace       NLMISC;
00040 
00041 
00042 namespace NL3D 
00043 {
00044 
00045 
00046 // ***************************************************************************
00047 
00048 
00049 #ifdef NL_OS_WINDOWS
00050 
00051 /* This floor works only for floor with noise, because floor/ceil are only made on decimal coordinates:
00052         sTile =1.25 ....  NB: because of difference of mapping (rare case), we may have sometimes values with
00053         precision < 1/4 (eg 1.125). Just use f*256 to compute the floor.
00054 
00055   NB: using a fastFloor() (fistp changing the controlfp() is not very a good idea here, because 
00056   computeNoise() are not "packed", so change on controlFp() would bee to frequent... 
00057   And also because we need either floor() or ceil() here.
00058 */
00059 inline  sint noiseFloor(float f)
00060 {
00061         // build a fixed 24:8.
00062         sint    a;
00063         f*=256;
00064 
00065         // fast ftol. work if no decimal.
00066         _asm
00067         {
00068                 fld f
00069                 fistp a
00070         }
00071 
00072         // floor.
00073         a>>=8;
00074 
00075         return a;
00076 }
00077 
00078 
00079 inline  sint noiseCeil(float f)
00080 {
00081         // build a fixed 24:8.
00082         sint    a;
00083         f*=256;
00084 
00085         // fast ftol. work if no decimal.
00086         _asm
00087         {
00088                 fld f
00089                 fistp a
00090         }
00091 
00092         // ceil.
00093         a+=255;
00094         a>>=8;
00095 
00096         return a;
00097 }
00098 
00099 
00100 inline  float noiseFloorF(float f)
00101 {
00102         return (float)noiseFloor(f);
00103 }
00104 inline  float noiseCeilF(float f)
00105 {
00106         return (float)noiseCeil(f);
00107 }
00108 
00109 
00110 #else
00111 
00112 
00113 inline  float noiseFloorF(float f)
00114 {
00115         return (float)floor(f);
00116 }
00117 inline  float noiseCeilF(float f)
00118 {
00119         return (float)ceil(f);
00120 }
00121 
00122 inline  sint noiseFloor(float f)
00123 {
00124         return (sint)floor(f);
00125 }
00126 inline  sint noiseCeil(float f)
00127 {
00128         return (sint)ceil(f);
00129 }
00130 
00131 #endif
00132 
00133 
00134 
00135 // ***************************************************************************
00136 float           CPatch::computeDisplaceRawInteger(sint ts, sint tt, sint ms, sint mt) const
00137 {
00138         // Choose the noiseMap.
00139         // ===============================
00140         clamp(ts, 0, OrderS-1);
00141         clamp(tt, 0, OrderT-1);
00142 
00143         uint    tileId= tt*OrderS + ts;
00144         // Get the tile for pass0. This is the principal tile, and this one tells what noise to take.
00145         sint    tileNumber= Tiles[tileId].Tile[0];
00146         // Get the subNoise from tileElement.
00147         uint    tileSubNoise= Tiles[tileId].getTileSubNoise();
00148 
00149         // retrieve the wanted noiseMap.
00150         CTileNoiseMap   *noiseMap;
00151         noiseMap = getZone()->getLandscape()->TileBank.getTileNoiseMap (tileNumber, tileSubNoise);
00152 
00153 
00154         // Sample the noiseMap with (s,t).
00155         // ===============================
00156 
00157         // sample from map.
00158         sint8   pix= noiseMap->Pixels[mt*NL3D_TILE_NOISE_MAP_SIZE + ms];
00159 
00160         // normalize.
00161         return  (float)pix * (NL3D_NOISE_MAX / 127.f);
00162 }
00163 
00164 
00165 // ***************************************************************************
00166 void            CPatch::computeDisplaceRawCoordinates(float sTile, float tTile, float s, float t,
00167         sint &ts, sint &tt, sint &ms, sint &mt) const
00168 {
00169         // Choose the noiseMap.
00170         // ===============================
00171         // Compute coordinate in the patch.
00172         ts= noiseFloor(sTile);
00173         tt= noiseFloor(tTile);
00174 
00175 
00176         // Sample the noiseMap with (s,t).
00177         // ===============================
00178 
00179         // scale the map.
00180         float   u= s * NL3D_TILE_NOISE_MAP_TILE_FACTOR;
00181         float   v= t * NL3D_TILE_NOISE_MAP_TILE_FACTOR;
00182 
00183         // Speed rotation.
00184         CUV             uv;
00185         switch(NoiseRotation & 3)
00186         {
00187                 case 0: 
00188                         uv.U= u;
00189                         uv.V= v;
00190                         break;
00191                 case 1: 
00192                         uv.U= NL3D_TILE_NOISE_MAP_SIZE-v;
00193                         uv.V= u;
00194                         break;
00195                 case 2: 
00196                         uv.U= NL3D_TILE_NOISE_MAP_SIZE-u;
00197                         uv.V= NL3D_TILE_NOISE_MAP_SIZE-v;
00198                         break;
00199                 case 3: 
00200                         uv.U= v;
00201                         uv.V= NL3D_TILE_NOISE_MAP_SIZE-u;
00202                         break;
00203         }
00204 
00205         // direct map (no bilinear, no round, the case where s,t < 1/4 of a tile is very rare).
00206         ms= noiseFloor(uv.U);
00207         mt= noiseFloor(uv.V);
00208 
00209         // Manage Tiling (add NL3D_TILE_NOISE_MAP_SIZE*1 should be sufficient, but take margin).
00210         ms= (ms + (NL3D_TILE_NOISE_MAP_SIZE*256)) & (NL3D_TILE_NOISE_MAP_SIZE-1);
00211         mt= (mt + (NL3D_TILE_NOISE_MAP_SIZE*256)) & (NL3D_TILE_NOISE_MAP_SIZE-1);
00212 }
00213 
00214 
00215 
00216 // ***************************************************************************
00217 float           CPatch::computeDisplaceRaw(float sTile, float tTile, float s, float t) const
00218 {
00219         sint    ts,tt,ms,mt;
00220         computeDisplaceRawCoordinates(sTile, tTile, s, t, ts, tt, ms, mt);
00221         return computeDisplaceRawInteger(ts, tt, ms, mt);
00222 
00223 }
00224 
00225 // ***************************************************************************
00226 static inline   void    computeDisplaceBilinear(float sTile, float tTile, 
00227         float &sInc, float &tInc, float &sa, float &ta, float &sa1, float &ta1)
00228 {
00229         float   sDecimal= sTile-noiseFloor(sTile);
00230         float   tDecimal= tTile-noiseFloor(tTile);
00231         float   sDist, tDist;
00232 
00233         // Do a bilinear centered on 0.5, 0.5.
00234 
00235         // Compute increment, according to position against center.
00236         if(sDecimal>=0.5)
00237                 sInc= 1;
00238         else
00239                 sInc= -1;
00240         if(tDecimal>=0.5)
00241                 tInc= 1;
00242         else
00243                 tInc= -1;
00244 
00245         // Compute weight factor.
00246         sDist= (float)fabs(0.5 - sDecimal);     // s distance from center.
00247         tDist= (float)fabs(0.5 - tDecimal);     // t distance from center.
00248         sa= 1-sDist;
00249         ta= 1-tDist;
00250         sa1= 1-sa;
00251         ta1= 1-ta;
00252 }
00253 
00254 
00255 // ***************************************************************************
00256 float           CPatch::computeDisplaceInteriorSmooth(float s, float t) const
00257 {
00258         float sTile= s;
00259         float tTile= t;
00260         float   ret;
00261 
00262         // compute bi-linear weight factors.
00263         float   sInc, tInc, sa, ta, sa1, ta1;
00264         computeDisplaceBilinear(sTile, tTile, sInc, tInc, sa, ta, sa1, ta1);
00265 
00266 
00267         // NB: to have smooth transition, must keep the same (s,t), so we do a transition with the noise tile of 
00268         // our neigbhor, but under us.
00269 
00270         // speed up, using just one computeDisplaceRawCoordinates(), and multiple computeDisplaceRawInteger().
00271         sint    ts,tt,ms,mt;
00272         computeDisplaceRawCoordinates(sTile, tTile, s, t, ts, tt, ms, mt);
00273 
00274         sint    sIncInt= (sint) sInc;
00275         sint    tIncInt= (sint) tInc;
00276         ret = computeDisplaceRawInteger(ts, tt, ms,mt) * sa * ta;
00277         ret+= computeDisplaceRawInteger(ts+sIncInt, tt, ms,mt) * sa1 * ta;
00278         ret+= computeDisplaceRawInteger(ts, tt+tIncInt, ms,mt) * sa * ta1;
00279         ret+= computeDisplaceRawInteger(ts+sIncInt, tt+tIncInt, ms,mt) * sa1 * ta1;
00280 
00281         return ret;
00282 }
00283 
00284 
00285 // ***************************************************************************
00286 float           CPatch::computeDisplaceEdgeSmooth(float s, float t, sint8 smoothBorderX, sint8 smoothBorderY) const
00287 {
00288         float sTile= s;
00289         float tTile= t;
00290         CBindInfo       bindInfo;
00291         uint            edge=0;
00292 
00293         // only one must be not null
00294         nlassert( (smoothBorderX==0) != (smoothBorderY==0) );
00295 
00296 
00297         // Get the edge against we must share displace.
00298         if(smoothBorderX==-1)   edge=0;
00299         else if(smoothBorderY==1)       edge=1;
00300         else if(smoothBorderX==1)       edge=2;
00301         else if(smoothBorderY==-1)      edge=3;
00302         else nlstop;
00303 
00304         // Build the bindInfo against this edge.
00305         getBindNeighbor(edge, bindInfo);
00306 
00307         // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
00308         if(!bindInfo.Zone)
00309                 return computeDisplaceInteriorSmooth(s, t);
00310         // else, look for result in neighborhood.
00311         else
00312         {
00313                 float   ret;
00314 
00315 
00316                 // compute bi-linear weight factors.
00317                 float   sInc, tInc, sa, ta, sa1, ta1;
00318                 computeDisplaceBilinear(sTile, tTile, sInc, tInc, sa, ta, sa1, ta1);
00319                 // Manage limit case: if bilinear has not chosen the good direction (because of floor and orientation).
00320                 // eg on Right edge: This case arise if sDecimal==0, so if sa==sa1==0.5f. result is that
00321                 // smoothBorderX is != than sInc on right border. same reasoning with downBorder (smoothBorderY=1).
00322 
00323                 // NO NEED TO DO HERE, because sInc or tInc is not used if it is bad (smoothBorder? used instead).
00324                 // and no need to correct sa, sa1, because in this case they are both equal to 0.5.
00325 
00326 
00327                 // compute Neighboring info.
00328                 CPatchUVLocator         uvLocator;
00329                 uvLocator.build(this, edge, bindInfo);
00330 
00331                 /* NB: there is floor problems with neighbors:
00332                         - difference of orientation => uv.v=1. This point to the 1th tile. But this is not the same, if
00333                                 v goes to up, or goes to down.
00334                         - if multiple bind, problem at limit (eg a bind 1/2 on edge 0 with OrdertT=8, when uv.v= 4).
00335                                 because, selection of the patch is dependent of orientation too.
00336                         To avoid them, just take center of (sTile, tTile) to remove ambiguity.
00337                         This works because computeDisplaceRaw() use sTile, tTile to get the noiseMap, so the decimal part is not 
00338                         used.
00339 
00340                         Notice that we do this AFTER computeDisplaceBilinear() of course.
00341                 */
00342                 sTile= noiseFloor(sTile) + 0.5f;
00343                 tTile= noiseFloor(tTile) + 0.5f;
00344                 // If we were exactly on the superior edge, prec compute is false... so correct this here.
00345                 if(sTile>OrderS) sTile--;
00346                 if(tTile>OrderT) tTile--;
00347 
00348 
00349                 // Bilinear across an edge (enjoy!!).
00350                 CVector2f       stTileIn, stIn;
00351                 CVector2f       stTileOut, stOut;
00352                 CPatch          *patchOut;
00353                 uint            patchId;
00354 
00355 
00356                 // if vertical edge.
00357                 if(smoothBorderX!=0)
00358                 {
00359                         // compute contribution of our patch.
00360                         ret = computeDisplaceRaw(sTile,tTile, s,t) * sa * ta;
00361                         ret+= computeDisplaceRaw(sTile,tTile+tInc, s,t) * sa * ta1;
00362 
00363                         // compute contribution of next(s) patchs.
00364 
00365                         // contribution of next at tTile.
00366                         // Keep the same coordinate.
00367                         stIn.set(s, t);
00368                         // But look for the neighbor noise tile.
00369                         stTileIn.set(sTile+smoothBorderX, tTile);
00370                         // change basis: find the s,t on the neighbor patch.
00371                         patchId= uvLocator.selectPatch(stTileIn);
00372                         uvLocator.locateUV(stTileIn, patchId, patchOut, stTileOut);
00373                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00374                         // Compute displace, and bi-linear on the neighbor patch.
00375                         ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa1 * ta;
00376 
00377                         // contribution of next at tTile+tInc (same reasoning).
00378                         stIn.set(s, t);
00379                         stTileIn.set(sTile+smoothBorderX, tTile+tInc);
00380                         patchId= uvLocator.selectPatch(stTileIn);
00381                         uvLocator.locateUV(stTileIn, patchId, patchOut, stTileOut);
00382                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00383                         ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa1 * ta1;
00384 
00385                 }
00386                 // else if horizontal edge.
00387                 else
00388                 {
00389                         // same reasoning as above.
00390 
00391                         // compute contribution of our patch.
00392                         ret = computeDisplaceRaw(sTile, tTile, s,t) * sa * ta;
00393                         ret+= computeDisplaceRaw(sTile+sInc,tTile, s,t) * sa1 * ta;
00394 
00395                         // compute contribution of next(s) patchs.
00396                         // contribution of next at tTile.
00397                         stIn.set(s, t);
00398                         stTileIn.set(sTile, tTile+smoothBorderY);
00399                         patchId= uvLocator.selectPatch(stTileIn);
00400                         uvLocator.locateUV(stTileIn, patchId, patchOut, stTileOut);
00401                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00402                         ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa * ta1;
00403 
00404                         // contribution of next at tTile+tInc (same reasoning).
00405                         stIn.set(s, t);
00406                         stTileIn.set(sTile+sInc, tTile+smoothBorderY);
00407                         patchId= uvLocator.selectPatch(stTileIn);
00408                         uvLocator.locateUV(stTileIn, patchId, patchOut, stTileOut);
00409                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00410                         ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa1 * ta1;
00411                 }
00412 
00413                 return ret;
00414         }
00415 
00416 }
00417 
00418 
00419 // ***************************************************************************
00420 float           CPatch::computeDisplaceRawOnNeighbor(float sTile, float tTile, float s, float t) const
00421 {
00422         sint    edge= -1;
00423 
00424         // look on what neighbor patch we must find the value (if any).
00425         if(sTile<0)     edge=0;
00426         else if(tTile>OrderT)   edge=1;
00427         else if(sTile>OrderS)   edge=2;
00428         else if(tTile<0)                edge=3;
00429 
00430         // If the location is In the patch, just return normal value.
00431         if(edge==-1)
00432                 return computeDisplaceRaw(sTile, tTile, s, t);
00433         // else must find on neighbor.
00434         else
00435         {
00436                 CBindInfo       bindInfo;
00437                 getBindNeighbor(edge, bindInfo);
00438 
00439                 // Fast reject: if no neighbor on the edge, just do a simple computeDisplaceRaw()
00440                 if(!bindInfo.Zone)
00441                 {
00442                         return computeDisplaceRaw(sTile, tTile, s, t);
00443                 }
00444                 // else must find on neighbor.
00445                 else
00446                 {
00447                         CPatchUVLocator         uvLocator;
00448                         uvLocator.build(this, edge, bindInfo);
00449 
00450                         CVector2f       stTileIn, stIn;
00451                         CVector2f       stTileOut, stOut;
00452                         CPatch          *patchOut;
00453                         uint            patchId;
00454 
00455                         // look on neighbor. same reasoning as in computeDisplaceEdgeSmooth();
00456                         stIn.set(s, t);
00457                         stTileIn.set(sTile, tTile);
00458                         patchId= uvLocator.selectPatch(stTileIn);
00459                         uvLocator.locateUV(stTileIn, patchId, patchOut, stTileOut);
00460                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00461                         return patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y);
00462                 }
00463 
00464         }
00465 }
00466 
00467 
00468 // ***************************************************************************
00469 float           CPatch::computeDisplaceCornerSmooth(float s, float t, sint8 smoothBorderX, sint8 smoothBorderY) const
00470 {
00471         // compute the value across the corner (enjoy!!)
00472         // NB: Only corners with Edges==4 and corners on a bind are correclty supported.
00473         // ignore problems with corner which nbEdges!=4, because Blend of normals blend to 0 on corner (see computenoise()).
00474 
00475         float sTile= s;
00476         float tTile= t;
00477         CBindInfo       bindInfoX;
00478         CBindInfo       bindInfoY;
00479         uint            edgeX=0;
00480         uint            edgeY=0;
00481 
00482         // both must be not null
00483         nlassert( (smoothBorderX!=0) && (smoothBorderY!=0) );
00484 
00485 
00486         // Get the edge against we must share displace.
00487         if(smoothBorderX==-1)   edgeX=0;
00488         else if(smoothBorderX==1)       edgeX=2;
00489         else nlstop;
00490         if(smoothBorderY==1)    edgeY=1;
00491         else if(smoothBorderY==-1)      edgeY=3;
00492         else nlstop;
00493 
00494         // Build the bindInfo against those 2 edge.
00495         getBindNeighbor(edgeX, bindInfoX);
00496         getBindNeighbor(edgeY, bindInfoY);
00497 
00498         // Fast reject: if no neighbor on one of the edge, just do a simple computeDisplaceInteriorSmooth.
00499         if(!bindInfoX.Zone || !bindInfoY.Zone)
00500                 return computeDisplaceInteriorSmooth(s, t);
00501         else
00502         {
00503                 float   ret;
00504 
00505 
00506                 // compute bi-linear weight factors.
00507                 float   sInc, tInc, sa, ta, sa1, ta1;
00508                 computeDisplaceBilinear(sTile, tTile, sInc, tInc, sa, ta, sa1, ta1);
00509                 // Manage limit case: if bilinear has not chosen the good direction (because of floor and orientation).
00510                 // eg on Right edge: This case arise if sDecimal==0, so if sa==sa1==0.5f. result is that
00511                 // smoothBorderX is != than sInc on right border. same reasoning with downBorder (smoothBorderY=1).
00512 
00513                 // NO NEED TO DO HERE, because sInc or tInc are not used at all.
00514 
00515 
00516 
00517                 // compute Neighboring info.
00518                 CPatchUVLocator         uvLocatorX;
00519                 CPatchUVLocator         uvLocatorY;
00520                 uvLocatorX.build(this, edgeX, bindInfoX);
00521                 uvLocatorY.build(this, edgeY, bindInfoY);
00522 
00523 
00524                 /* NB: see floor problems note in computeDisplaceEdgeSmooth();
00525                 */
00526                 sTile= noiseFloor(sTile) + 0.5f;
00527                 tTile= noiseFloor(tTile) + 0.5f;
00528                 // If we were exactly on the superior edge, prec compute is false... so correct this here.
00529                 if(sTile>OrderS) sTile--;
00530                 if(tTile>OrderT) tTile--;
00531 
00532 
00533                 // Bilinear across a corner.
00534                 CVector2f       stTileIn, stIn;
00535                 CVector2f       stTileOut, stOut;
00536                 CPatch          *patchOut;
00537                 uint            patchId;
00538 
00539 
00540                 // compute contribution of our patch.
00541                 ret = computeDisplaceRaw(sTile,tTile, s,t) * sa * ta;
00542 
00543                 // compute contribution of the patch on the left/right side. same reasoning as in computeDisplaceEdgeSmooth();
00544                 stIn.set(s, t);
00545                 stTileIn.set(sTile+smoothBorderX, tTile);
00546                 patchId= uvLocatorX.selectPatch(stTileIn);
00547                 uvLocatorX.locateUV(stTileIn, patchId, patchOut, stTileOut);
00548                 uvLocatorX.locateUV(stIn, patchId, patchOut, stOut);
00549                 ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa1 * ta;
00550 
00551 
00552                 // compute contribution of the patch on the up/down side. same reasoning as in computeDisplaceEdgeSmooth();
00553                 stIn.set(s, t);
00554                 stTileIn.set(sTile, tTile+smoothBorderY);
00555                 patchId= uvLocatorY.selectPatch(stTileIn);
00556                 uvLocatorY.locateUV(stTileIn, patchId, patchOut, stTileOut);
00557                 uvLocatorY.locateUV(stIn, patchId, patchOut, stOut);
00558                 ret+= patchOut->computeDisplaceRaw(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa * ta1;
00559 
00560 
00561                 /* compute contribution of the patch adjacent to me.
00562                         There is multiple case to consider here. Take example with corner=0 (ie smBdX=smBdY=-1):
00563                                 - if we are a normal corner with 4 edges, take the result from the left patch of our top patch.
00564                                 - if the corner is on a bind Edge, the top patch may be the bigger patch, so don't take the result
00565                                         from his neighbor (of course).
00566                                 - if we are a normal corner with N!=4 edges, just do same thing than if N==4. this is false but don't bother.
00567 
00568                         To solve smoothly cases 1 and 2, use computeDisplaceRawOnNeighbor().
00569                         This method, if nessecary, look on his neighbor to compute the value.
00570                 */
00571                 stIn.set(s, t);
00572                 stTileIn.set(sTile+smoothBorderX, tTile+smoothBorderY);
00573                 // look on our "top" patch (this is arbitrary).
00574                 patchId= uvLocatorY.selectPatch(stTileIn);
00575                 uvLocatorY.locateUV(stTileIn, patchId, patchOut, stTileOut);
00576                 uvLocatorY.locateUV(stIn, patchId, patchOut, stOut);
00577                 ret+= patchOut->computeDisplaceRawOnNeighbor(stTileOut.x, stTileOut.y, stOut.x, stOut.y) * sa1 * ta1;
00578 
00579 
00580                 return ret;
00581         }
00582 
00583 }
00584 
00585 // ***************************************************************************
00586 CVector         CPatch::computeNormalEdgeSmooth(float s, float t, sint8 smoothBorderX, sint8 smoothBorderY) const
00587 {
00588         CBindInfo       bindInfo;
00589         uint            edge=0;
00590         CBezierPatch    *bpatch;
00591         bpatch= unpackIntoCache();
00592 
00593         // only one must be not null
00594         nlassert( (smoothBorderX==0) != (smoothBorderY==0) );
00595 
00596 
00597         // Get the edge against we must share displace.
00598         if(smoothBorderX==-1)   edge=0;
00599         else if(smoothBorderY==1)       edge=1;
00600         else if(smoothBorderX==1)       edge=2;
00601         else if(smoothBorderY==-1)      edge=3;
00602         else nlstop;
00603 
00604         // If the edge is smoothed, blend with neighbor.
00605         if(getSmoothFlag(edge))
00606         {
00607                 // Build the bindInfo against this edge.
00608                 getBindNeighbor(edge, bindInfo);
00609 
00610                 // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
00611                 if(!bindInfo.Zone)
00612                         return bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00613                 else
00614                 {
00615                         CVector         r0, r1;
00616 
00617                         // Compute our contribution.
00618                         r0= bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00619 
00620                         // Compute the coordinate on the border of the edge, and the coef of the blend.
00621                         float           se=s;
00622                         float           te=t;
00623                         float           coef=0.0;
00624                         if(smoothBorderX==-1)           se= noiseFloorF(se), coef=s-se;
00625                         else if(smoothBorderX==1)       se= noiseCeilF(se), coef=se-s;
00626                         else if(smoothBorderY==-1)      te= noiseFloorF(te), coef=t-te;
00627                         else if(smoothBorderY==1)       te= noiseCeilF(te), coef=te-t;
00628                         coef= 0.5f + coef*0.5f;
00629 
00630                         // Compute contribution of the normal on the neighbor, on the border of the edge.
00631                         CPatchUVLocator         uvLocator;
00632                         CVector2f       stIn, stOut;
00633                         CPatch          *patchOut;
00634                         uint            patchId;
00635 
00636                         uvLocator.build(this, edge, bindInfo);
00637                         stIn.set(se, te);
00638                         patchId= uvLocator.selectPatch(stIn);
00639                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00640 
00641                         bpatch= patchOut->unpackIntoCache();
00642                         r1= bpatch->evalNormal(stOut.x/patchOut->getOrderS(), stOut.y/patchOut->getOrderT());
00643 
00644                         // NB: don't bother problems with bind 1/X and the choice of the patch, because bind are C1, so normal is C0.
00645 
00646                         // Blend 2 result. For speed optim, don't normalize.
00647                         return r0*coef + r1*(1-coef);
00648                 }
00649         }
00650         // else blend with vector Null.
00651         else
00652         {
00653                 // compute coef.
00654                 float           se=s;
00655                 float           te=t;
00656                 float           coef=0.0;
00657                 if(smoothBorderX==-1)           se= noiseFloorF(se), coef=s-se;
00658                 else if(smoothBorderX==1)       se= noiseCeilF(se), coef=se-s;
00659                 else if(smoothBorderY==-1)      te= noiseFloorF(te), coef=t-te;
00660                 else if(smoothBorderY==1)       te= noiseCeilF(te), coef=te-t;
00661 
00662                 // Compute our contribution.
00663                 CVector         r0;
00664                 r0= bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00665 
00666                 // Blend with 0.
00667                 return r0*coef;
00668         }
00669 }
00670 
00671 
00672 // ***************************************************************************
00673 CVector         CPatch::computeNormalOnNeighbor(float s, float t, uint edgeExclude) const
00674 {
00675         sint    edge= -1;
00676 
00677         // look on what neighbor patch we must find the value (if any).
00678         if(s<1 && edgeExclude!=0)                               edge=0;
00679         else if(t>OrderT-1 && edgeExclude!=1)   edge=1;
00680         else if(s>OrderS-1 && edgeExclude!=2)   edge=2;
00681         else if(t<1 && edgeExclude!=3)                  edge=3;
00682 
00683 
00684         // If the location is In the patch, just return normal value. (case of a bind 1/X).
00685         if(edge==-1)
00686         {
00687                 CBezierPatch    *bpatch= unpackIntoCache();
00688                 return bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00689         }
00690         // else must find on neighbor.
00691         else
00692         {
00693                 CBindInfo       bindInfo;
00694                 getBindNeighbor(edge, bindInfo);
00695 
00696                 // Fast reject: if no neighbor on the edge, just do a simple computeDisplaceRaw()
00697                 if(!bindInfo.Zone)
00698                 {
00699                         CBezierPatch    *bpatch= unpackIntoCache();
00700                         return bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00701                 }
00702                 // else must find on neighbor.
00703                 else
00704                 {
00705                         CPatchUVLocator         uvLocator;
00706                         uvLocator.build(this, edge, bindInfo);
00707 
00708                         CVector2f       stIn;
00709                         CVector2f       stOut;
00710                         CPatch          *patchOut;
00711                         uint            patchId;
00712 
00713                         // look on neighbor. same reasoning as in computeDisplaceEdgeSmooth();
00714                         stIn.set(s, t);
00715                         patchId= uvLocator.selectPatch(stIn);
00716                         uvLocator.locateUV(stIn, patchId, patchOut, stOut);
00717                         CBezierPatch    *bpatch= patchOut->unpackIntoCache();
00718                         return bpatch->evalNormal(stOut.x/patchOut->getOrderS(), stOut.y/patchOut->getOrderT());
00719                 }
00720 
00721         }
00722 }
00723 
00724 
00725 // ***************************************************************************
00726 CVector         CPatch::computeNormalCornerSmooth(float s, float t, sint8 smoothBorderX, sint8 smoothBorderY) const
00727 {
00728         CBindInfo       bindInfoX;
00729         CBindInfo       bindInfoY;
00730         uint            edgeX=0;
00731         uint            edgeY=0;
00732         uint            corner;
00733         CBezierPatch    *bpatch;
00734         bpatch= unpackIntoCache();
00735 
00736         // both must be not null
00737         nlassert( (smoothBorderX!=0) && (smoothBorderY!=0) );
00738 
00739 
00740         // Get the edge against we must share displace.
00741         if(smoothBorderX==-1)   edgeX=0;
00742         else if(smoothBorderX==1)       edgeX=2;
00743         else nlstop;
00744         if(smoothBorderY==1)    edgeY=1;
00745         else if(smoothBorderY==-1)      edgeY=3;
00746         else nlstop;
00747 
00748         // Get the corner against we must share displace.
00749         if(smoothBorderX==-1)
00750         {
00751                 if(smoothBorderY==-1)   corner=0;
00752                 else                                    corner=1;
00753         }
00754         else
00755         {
00756                 if(smoothBorderY==-1)   corner=3;
00757                 else                                    corner=2;
00758         }
00759 
00760         // If this corner is smoothed, blend with 4 neighbors patchs.
00761         if(getCornerSmoothFlag(corner))
00762         {
00763                 // Build the bindInfo against the 2 edge.
00764                 getBindNeighbor(edgeX, bindInfoX);
00765                 getBindNeighbor(edgeY, bindInfoY);
00766 
00767                 // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
00768                 if(!bindInfoX.Zone || !bindInfoY.Zone)
00769                         return bpatch->evalNormal(s/getOrderS(), t/getOrderT());
00770                 else
00771                 {
00772                         CVector         ret;
00773 
00774 
00775                         // Compute the coordinate on the border of the edge, and the coef of the blend.
00776                         float           se=s;
00777                         float           te=t;
00778                         float           coefX;
00779                         float           coefY;
00780                         if(smoothBorderX==-1)   se= noiseFloorF(se), coefX=s-se;
00781                         else                                    se= noiseCeilF(se), coefX=se-s;
00782                         if(smoothBorderY==-1)   te= noiseFloorF(te), coefY=t-te;
00783                         else                                    te= noiseCeilF(te), coefY=te-t;
00784                         coefX= 0.5f + coefX*0.5f;
00785                         coefY= 0.5f + coefY*0.5f;
00786 
00787 
00788                         // Compute our contribution.
00789                         ret= bpatch->evalNormal(s/getOrderS(), t/getOrderT()) *coefX*coefY;
00790 
00791 
00792                         // compute Neighboring info.
00793                         CPatchUVLocator         uvLocatorX;
00794                         CPatchUVLocator         uvLocatorY;
00795                         CVector2f       stIn, stOut;
00796                         CPatch          *patchOut;
00797                         uint            patchId;
00798 
00799                         uvLocatorX.build(this, edgeX, bindInfoX);
00800                         uvLocatorY.build(this, edgeY, bindInfoY);
00801 
00802                         // Patch on our X side.
00803                         stIn.set(se, te);
00804                         patchId= uvLocatorX.selectPatch(stIn);
00805                         uvLocatorX.locateUV(stIn, patchId, patchOut, stOut);
00806                         bpatch= patchOut->unpackIntoCache();
00807                         ret+= bpatch->evalNormal(stOut.x/patchOut->getOrderS(), stOut.y/patchOut->getOrderT()) *(1-coefX)*coefY;
00808 
00809                         // Patch on our Y side.
00810                         stIn.set(se, te);
00811                         patchId= uvLocatorY.selectPatch(stIn);
00812                         uvLocatorY.locateUV(stIn, patchId, patchOut, stOut);
00813                         bpatch= patchOut->unpackIntoCache();
00814                         ret+= bpatch->evalNormal(stOut.x/patchOut->getOrderS(), stOut.y/patchOut->getOrderT()) *coefX*(1-coefY);
00815 
00816                         /* compute contribution of the patch adjacent to me.
00817                                 Same reasoning as in computeDisplaceCornerSmooth().
00818                         */
00819                         stIn.set(se, te);
00820                         patchId= uvLocatorY.selectPatch(stIn);
00821                         uvLocatorY.locateUV(stIn, patchId, patchOut, stOut);
00822                         // Because we compute the normal exactly on the edge, we must inform this method not to take us as neighbor.
00823                         // ugly but simpler.
00824                         ret+= patchOut->computeNormalOnNeighbor(stOut.x, stOut.y, bindInfoY.Edge[patchId]) *(1-coefX)*(1-coefY);
00825 
00826                         return ret;
00827                 }
00828         }
00829         // else must blend with 0.
00830         else
00831         {
00832                 // compute coef.
00833                 float           se=s;
00834                 float           te=t;
00835                 float           coefX;
00836                 float           coefY;
00837                 if(smoothBorderX==-1)   se= noiseFloorF(se), coefX=s-se;
00838                 else                                    se= noiseCeilF(se), coefX=se-s;
00839                 if(smoothBorderY==-1)   te= noiseFloorF(te), coefY=t-te;
00840                 else                                    te= noiseCeilF(te), coefY=te-t;
00841 
00842 
00843                 // To have smooth continuities with smooth on edge (if any), we must do this.
00844                 CVector         rx, ry;
00845                 // Compute a smooth with my X neighbor.
00846                 rx= computeNormalEdgeSmooth(s, t, smoothBorderX, 0);
00847                 // Compute a smooth with my Y neighbor.
00848                 ry= computeNormalEdgeSmooth(s, t, 0, smoothBorderY);
00849 
00850                 // Blend the 2 result.
00851                 if(coefY + coefX>0)
00852                 {
00853                         // This the weight used to blend to 0.
00854                         float   maxCoef= max(coefY, coefX);
00855                         // This the weight used to blend beetween rx and ry.
00856                         float   ooSum= 1.0f / (coefY + coefX);
00857                         float   blendCoefX= coefX * ooSum;
00858                         float   blendCoefY= coefY * ooSum;
00859 
00860                         return maxCoef* (rx*blendCoefY + ry*blendCoefX);
00861                 }
00862                 else
00863                 {
00864                         return CVector::Null;
00865                 }
00866         }
00867 }
00868 
00869 
00870 
00871 // ***************************************************************************
00872 void            CPatch::computeNoise(float s, float t, CVector &displace) const
00873 {
00874         float   so= s*OrderS;
00875         float   to= t*OrderT;
00876 
00877 
00878         // Pre-Compute Border Smothing.
00879         //=========================
00880         // If we are on a border, flag it.
00881         sint8   smoothNormalBorderX= 0;
00882         sint8   smoothNormalBorderY= 0;
00883         // NB: because OrderS and OrderT >=2, smoothNormalBorderX=-1 and smoothNormalBorderX=1 are exclusive (as smoothNormalBorderY).
00884         if(so < 1) smoothNormalBorderX= -1;
00885         else if(so > OrderS-1) smoothNormalBorderX= 1;
00886         if(to < 1) smoothNormalBorderY= -1;
00887         else if(to > OrderT-1) smoothNormalBorderY= 1;
00888 
00889         bool    smoothNormalEdge= (smoothNormalBorderX!=0) != (smoothNormalBorderY!=0);
00890         bool    smoothNormalCorner= (smoothNormalBorderX!=0) && (smoothNormalBorderY!=0);
00891 
00892 
00893         // Do same thing, but to know if we must compute a displace on an interior, on an edge or on a corner.
00894         sint8   smoothDisplaceBorderX= 0;
00895         sint8   smoothDisplaceBorderY= 0;
00896         // NB: because OrderS and OrderT >=2, smoothBorderX=-1 and smoothBorderX=1 are exclusive (as smoothBorderY).
00897         if(so < 0.5) smoothDisplaceBorderX= -1;
00898         else if(so > OrderS-0.5) smoothDisplaceBorderX= 1;
00899         if(to < 0.5) smoothDisplaceBorderY= -1;
00900         else if(to > OrderT-0.5) smoothDisplaceBorderY= 1;
00901 
00902         bool    smoothDisplaceEdge= (smoothDisplaceBorderX!=0) != (smoothDisplaceBorderY!=0);
00903         bool    smoothDisplaceCorner= (smoothDisplaceBorderX!=0) && (smoothDisplaceBorderY!=0);
00904 
00905 
00906         // Compute Displace value.
00907         //=========================
00908         float   displaceValue;
00909 
00910         if(smoothDisplaceCorner)
00911                 displaceValue= computeDisplaceCornerSmooth(so, to, smoothDisplaceBorderX, smoothDisplaceBorderY);
00912         else if(smoothDisplaceEdge)
00913                 displaceValue= computeDisplaceEdgeSmooth(so, to, smoothDisplaceBorderX, smoothDisplaceBorderY);
00914         else
00915                 displaceValue= computeDisplaceInteriorSmooth(so, to);
00916 
00917 
00918 
00919         // Compute Displace normal.
00920         //=========================
00921 
00922         // Evaluate the normal.
00923         CVector         displaceNormal;
00924 
00925 
00926         // smooth on edges and on corners.
00927         if(smoothNormalCorner)
00928                 displaceNormal= computeNormalCornerSmooth(so, to, smoothNormalBorderX, smoothNormalBorderY);
00929         else if(smoothNormalEdge)
00930                 displaceNormal= computeNormalEdgeSmooth(so, to, smoothNormalBorderX, smoothNormalBorderY);
00931         else
00932         {
00933                 // unpack...
00934                 CBezierPatch    *bpatch= unpackIntoCache();
00935                 // eval.
00936                 displaceNormal= bpatch->evalNormal(s, t);
00937         }
00938 
00939 
00940 
00941         // Final result.
00942         //=========================
00943         displace= displaceNormal * displaceValue;
00944 }
00945 
00946 
00947 
00948 // ***************************************************************************
00949 void                    CPatch::setCornerSmoothFlag(uint corner, bool smooth)
00950 {
00951         nlassert(corner<=3);
00952         uint    mask= 1<<corner;
00953         if(smooth)
00954                 _CornerSmoothFlag|= mask;
00955         else
00956                 _CornerSmoothFlag&= ~mask;
00957 }
00958 
00959 // ***************************************************************************
00960 bool                    CPatch::getCornerSmoothFlag(uint corner) const
00961 {
00962         nlassert(corner<=3);
00963         uint    mask= 1<<corner;
00964         return  (_CornerSmoothFlag& mask)!=0;
00965 }
00966 
00967 
00968 } // NL3D