# 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  

zone.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 #include "3d/zone.h"
00029 #include "3d/landscape.h"
00030 #include "3d/zone_symmetrisation.h"
00031 #include "nel/misc/common.h"
00032 
00033 
00034 using namespace NLMISC;
00035 using namespace std;
00036 
00037 
00038 // define it only for debug bind.
00039 //#define       NL3D_DEBUG_DONT_BIND_PATCH
00040 
00041 
00042 namespace NL3D 
00043 {
00044 
00045 
00046 
00047 // ***************************************************************************
00048 // ***************************************************************************
00049 // CPatchInfo
00050 // ***************************************************************************
00051 // ***************************************************************************
00052 
00053 
00054 // ***************************************************************************
00055 void                    CPatchInfo::setCornerSmoothFlag(uint corner, bool smooth)
00056 {
00057         nlassert(corner<=3);
00058         uint    mask= 1<<corner;
00059         if(smooth)
00060                 _CornerSmoothFlag|= mask;
00061         else
00062                 _CornerSmoothFlag&= ~mask;
00063 }
00064 
00065 // ***************************************************************************
00066 bool                    CPatchInfo::getCornerSmoothFlag(uint corner) const
00067 {
00068         nlassert(corner<=3);
00069         uint    mask= 1<<corner;
00070         return  (_CornerSmoothFlag & mask)!=0;
00071 }
00072 
00073 
00074 // ***************************************************************************
00075 // ***************************************************************************
00076 // CZone
00077 // ***************************************************************************
00078 // ***************************************************************************
00079 
00080 
00081 // ***************************************************************************
00082 CZone::CZone()
00083 {
00084         ZoneId= 0;
00085         Compiled= false;
00086         Landscape= NULL;
00087         ClipResult= ClipOut;
00088 }
00089 // ***************************************************************************
00090 CZone::~CZone()
00091 {
00092         // release() must have been called.
00093         nlassert(!Compiled);
00094 }
00095 
00096 
00097 // ***************************************************************************
00098 void                    CZone::computeBBScaleBias(const CAABBox &bb)
00099 {
00100         ZoneBB= bb;
00101         // Take a security for noise. (usefull for zone clipping).
00102         ZoneBB.setHalfSize(ZoneBB.getHalfSize()+CVector(NL3D_NOISE_MAX, NL3D_NOISE_MAX, NL3D_NOISE_MAX));
00103         CVector hs= ZoneBB.getHalfSize();
00104         float   rmax= maxof(hs.x, hs.y, hs.z);
00105         PatchScale= rmax / 32760;               // Prevent from float imprecision by taking 32760 and not 32767.
00106         PatchBias= ZoneBB.getCenter();
00107 }
00108 
00109 
00110 // ***************************************************************************
00111 void                    CZone::build(uint16 zoneId, const std::vector<CPatchInfo> &patchs, const std::vector<CBorderVertex> &borderVertices, uint32 numVertices)
00112 {
00113         CZoneInfo       zinfo;
00114         zinfo.ZoneId= zoneId;
00115         zinfo.Patchs= patchs;
00116         zinfo.BorderVertices= borderVertices;
00117 
00118         build(zinfo, numVertices);
00119 }
00120 // ***************************************************************************
00121 void                    CZone::build(const CZoneInfo &zoneInfo, uint32 numVertices)
00122 {
00123         sint    i,j;
00124         nlassert(!Compiled);
00125 
00126         // Ref inupt
00127         uint16          zoneId= zoneInfo.ZoneId;
00128         const std::vector<CPatchInfo> &patchs= zoneInfo.Patchs;
00129         const std::vector<CBorderVertex> &borderVertices= zoneInfo.BorderVertices;
00130         
00131 
00132         ZoneId= zoneId;
00133         BorderVertices= borderVertices;
00134 
00135         // Compute the bbox and the bias/scale.
00136         //=====================================
00137         CAABBox         bb;
00138         if(patchs.size())
00139                 bb.setCenter(patchs[0].Patch.Vertices[0]);
00140         bb.setHalfSize(CVector::Null);
00141         for(j=0;j<(sint)patchs.size();j++)
00142         {
00143                 const CBezierPatch      &p= patchs[j].Patch;
00144                 for(i=0;i<4;i++)
00145                         bb.extend(p.Vertices[i]);
00146                 for(i=0;i<8;i++)
00147                         bb.extend(p.Tangents[i]);
00148                 for(i=0;i<4;i++)
00149                         bb.extend(p.Interiors[i]);
00150         }
00151         // Compute BBox, and Patch Scale Bias, according to Noise.
00152         computeBBScaleBias(bb);
00153 
00154 
00155         // Compute/compress Patchs.
00156         //=========================
00157         Patchs.resize(patchs.size());
00158         PatchConnects.resize(patchs.size());
00159         sint    maxVertex=-1;
00160         for(j=0;j<(sint)patchs.size();j++)
00161         {
00162                 const CPatchInfo        &pi= patchs[j];
00163                 const CBezierPatch      &p= pi.Patch;
00164                 CPatch                          &pa= Patchs[j];
00165                 CPatchConnect           &pc= PatchConnects[j];
00166 
00167                 // Smoothing flags
00168                 pa.Flags&=~NL_PATCH_SMOOTH_FLAG_MASK;
00169                 pa.Flags|=NL_PATCH_SMOOTH_FLAG_MASK&(pi.Flags<<NL_PATCH_SMOOTH_FLAG_SHIFT);
00170 
00171 
00172                 // Noise Data
00173                 // copy noise rotation.
00174                 pa.NoiseRotation= pi.NoiseRotation;
00175                 // copy all noise smoothing info.
00176                 for(i=0;i<4;i++)
00177                 {
00178                         pa.setCornerSmoothFlag(i, pi.getCornerSmoothFlag(i));
00179                 }
00180 
00181                 // Copy order of the patch
00182                 pa.OrderS= pi.OrderS;
00183                 pa.OrderT= pi.OrderT;
00184 
00185                 // Build the patch.
00186                 for(i=0;i<4;i++)
00187                         pa.Vertices[i].pack(p.Vertices[i], PatchBias, PatchScale);
00188                 for(i=0;i<8;i++)
00189                         pa.Tangents[i].pack(p.Tangents[i], PatchBias, PatchScale);
00190                 for(i=0;i<4;i++)
00191                         pa.Interiors[i].pack(p.Interiors[i], PatchBias, PatchScale);
00192                 pa.Tiles= pi.Tiles;
00193                 pa.TileColors= pi.TileColors;
00194                 /* Copy TileLightInfluences. It is possible that pi.TileLightInfluences.size()!= 0
00195                         and pi.TileLightInfluences.size()!= (uint)(pi.OrderS/2+1)*(pi.OrderT/2+1)
00196                         Because of a preceding bug where pa.OrderS and pa.OrderT were not initialized before the 
00197                         pa.resetTileLightInfluences();
00198                 */
00199                 if( pi.TileLightInfluences.size()!= (uint)(pi.OrderS/2+1)*(pi.OrderT/2+1) )
00200                 {
00201                         pa.resetTileLightInfluences();
00202                 }
00203                 else
00204                 {
00205                         pa.TileLightInfluences= pi.TileLightInfluences;
00206                 }
00207 
00208                 // Number of lumels in this patch
00209                 uint lumelCount=(pi.OrderS*NL_LUMEL_BY_TILE)*(pi.OrderT*NL_LUMEL_BY_TILE);
00210 
00211                 // Lumel empty ?
00212                 if (pi.Lumels.size ()==lumelCount)
00213                 {
00214                         // Pack the lumel map
00215                         pa.packShadowMap (&pi.Lumels[0]);
00216                 }
00217                 else
00218                 {
00219                         // Reset lightmap
00220                         pa.resetCompressedLumels ();
00221                 }
00222 
00223                 nlassert(pa.Tiles.size()== (uint)pi.OrderS*pi.OrderT);
00224                 nlassert(pa.TileColors.size()== (uint)(pi.OrderS+1)*(pi.OrderT+1));
00225 
00226                 // Build the patchConnect.
00227                 pc.ErrorSize= pi.ErrorSize;
00228                 for(i=0;i<4;i++)
00229                 {
00230                         pc.BaseVertices[i]= pi.BaseVertices[i];
00231                         maxVertex= max((sint)pc.BaseVertices[i], maxVertex);
00232                 }
00233                 for(i=0;i<4;i++)
00234                         pc.BindEdges[i]= pi.BindEdges[i];
00235         }
00236 
00237         NumVertices= maxVertex+1;
00238         NumVertices= max((uint32)NumVertices, numVertices);
00239 
00240 
00241         // Copy PointLights.
00242         //=========================
00243         // build array, lights are sorted
00244         std::vector<uint>       plRemap;
00245         _PointLightArray.build(zoneInfo.PointLights, plRemap);
00246         // Check TileLightInfluences integrity, and remap PointLight Indices.
00247         for(j=0;j<(sint)patchs.size();j++)
00248         {
00249                 CPatch                          &pa= Patchs[j];
00250                 for(uint k= 0; k<pa.TileLightInfluences.size(); k++)
00251                 {
00252                         CTileLightInfluence             &tli= pa.TileLightInfluences[k];
00253                         for(uint l=0; l<CTileLightInfluence::NumLightPerCorner; l++)
00254                         {
00255                                 // If NULL light, break and continue to next TileLightInfluence.
00256                                 if(tli.Light[l]== 0xFF)
00257                                         break;
00258                                 else
00259                                 {
00260                                         // Check good index.
00261                                         nlassert(tli.Light[l] < _PointLightArray.getPointLights().size());
00262                                         // Remap index, because of light sorting.
00263                                         tli.Light[l]= plRemap[tli.Light[l]];
00264                                 }
00265 
00266                         }
00267                 }
00268         }
00269 }
00270 
00271 // ***************************************************************************
00272 void                    CZone::retrieve(std::vector<CPatchInfo> &patchs, std::vector<CBorderVertex> &borderVertices)
00273 {
00274         CZoneInfo       zinfo;
00275 
00276         retrieve(zinfo);
00277 
00278         patchs= zinfo.Patchs;
00279         borderVertices= zinfo.BorderVertices;
00280 }
00281 
00282 // ***************************************************************************
00283 void                    CZone::retrieve(CZoneInfo &zoneInfo)
00284 {
00285         sint i,j;
00286 
00287         // Ref on input.
00288         std::vector<CPatchInfo> &patchs= zoneInfo.Patchs;
00289         std::vector<CBorderVertex> &borderVertices= zoneInfo.BorderVertices;
00290         // Copy zoneId.
00291         zoneInfo.ZoneId= getZoneId();
00292 
00293 
00294         // uncompress Patchs.
00295         //=========================
00296         patchs.resize(Patchs.size());
00297         for(j=0;j<(sint)patchs.size();j++)
00298         {
00299                 CPatchInfo                      &pi= patchs[j];
00300                 CBezierPatch            &p= pi.Patch;
00301                 CPatch                          &pa= Patchs[j];
00302                 CPatchConnect           &pc= PatchConnects[j];
00303 
00304 
00305                 // Smoothing flags
00306                 pi.Flags= (pa.Flags&NL_PATCH_SMOOTH_FLAG_MASK)>>NL_PATCH_SMOOTH_FLAG_SHIFT;
00307 
00308 
00309                 // Noise Data
00310                 // copy noise rotation.
00311                 pi.NoiseRotation= pa.NoiseRotation;
00312                 // copy all noise smoothing info.
00313                 for(i=0;i<4;i++)
00314                 {
00315                         pi.setCornerSmoothFlag(i, pa.getCornerSmoothFlag(i));
00316                 }
00317 
00318 
00319                 // re-Build the uncompressed bezier patch.
00320                 for(i=0;i<4;i++)
00321                         pa.Vertices[i].unpack(p.Vertices[i], PatchBias, PatchScale);
00322                 for(i=0;i<8;i++)
00323                         pa.Tangents[i].unpack(p.Tangents[i], PatchBias, PatchScale);
00324                 for(i=0;i<4;i++)
00325                         pa.Interiors[i].unpack(p.Interiors[i], PatchBias, PatchScale);
00326                 pi.Tiles= pa.Tiles;
00327                 pi.TileColors= pa.TileColors;
00328                 pi.TileLightInfluences= pa.TileLightInfluences;
00329                 pi.Lumels.resize ((pa.OrderS*4)*(pa.OrderT*4));
00330                 pi.Flags=(pa.Flags&NL_PATCH_SMOOTH_FLAG_MASK)>>NL_PATCH_SMOOTH_FLAG_SHIFT;
00331 
00332                 // Unpack the lumel map
00333                 pa.unpackShadowMap (&pi.Lumels[0]);
00334 
00335                 // from the patchConnect.
00336                 pi.OrderS= pa.OrderS;
00337                 pi.OrderT= pa.OrderT;
00338                 pi.ErrorSize= pc.ErrorSize;
00339                 for(i=0;i<4;i++)
00340                 {
00341                         pi.BaseVertices[i]= pc.BaseVertices[i];
00342                 }
00343                 for(i=0;i<4;i++)
00344                         pi.BindEdges[i]= pc.BindEdges[i];
00345         }
00346 
00347         // retrieve bordervertices.
00348         //=========================
00349         borderVertices= BorderVertices;
00350 
00351         // retrieve PointLights.
00352         //=========================
00353         zoneInfo.PointLights= _PointLightArray.getPointLights();
00354 
00355 }
00356 
00357 
00358 // ***************************************************************************
00359 void                    CZone::build(const CZone &zone)
00360 {
00361         nlassert(!Compiled);
00362 
00363         ZoneId= zone.ZoneId;
00364         BorderVertices= zone.BorderVertices;
00365 
00366         // Compute the bbox and the bias/scale.
00367         //=====================================
00368         ZoneBB= zone.ZoneBB;
00369         PatchScale= zone.PatchScale;
00370         PatchBias= zone.PatchBias;
00371 
00372 
00373         // Compute/compress Patchs.
00374         //=========================
00375         Patchs= zone.Patchs;
00376         PatchConnects= zone.PatchConnects;
00377 
00378         // copy pointLights.
00379         //=========================
00380         _PointLightArray= zone._PointLightArray;
00381 
00382 
00383         NumVertices= zone.NumVertices;
00384 }
00385 
00386 
00387 
00388 // ***************************************************************************
00389 void                    CBorderVertex::serial(NLMISC::IStream &f)
00390 {
00391         (void)f.serialVersion(0);
00392 
00393         f.xmlSerial (CurrentVertex, "CURRENT_VERTEX");
00394         f.xmlSerial (NeighborZoneId, "NEIGHTBOR_ZONE_ID");
00395         f.xmlSerial (NeighborVertex, "NEIGHTBOR_VERTEX");
00396 }
00397 void                    CZone::CPatchConnect::serial(NLMISC::IStream &f)
00398 {
00399         uint    ver= f.serialVersion(1);
00400 
00401         if (ver<1)
00402                 f.serial(OldOrderS, OldOrderT, ErrorSize);
00403         else
00404                 f.serial(ErrorSize);
00405         f.xmlSerial (BaseVertices[0], BaseVertices[1], BaseVertices[2], BaseVertices[3], "BASE_VERTICES");
00406         f.xmlSerial (BindEdges[0], BindEdges[1], BindEdges[2], BindEdges[3], "BIND_EDGES");
00407 }
00408 void                    CPatchInfo::CBindInfo::serial(NLMISC::IStream &f)
00409 {
00410         (void)f.serialVersion(0);
00411         f.xmlSerial(NPatchs, "NPATCH");
00412         nlassert ( (NPatchs==0) | (NPatchs==1) | (NPatchs==2) | (NPatchs==4) | (NPatchs==5) );
00413         f.xmlSerial (ZoneId, "ZONE_ID");
00414         f.xmlSerial (Next[0], Next[1], Next[2], Next[3], "NEXT_PATCH");
00415         f.xmlSerial (Edge[0], Edge[1], Edge[2], Edge[3], "NEXT_EDGE");
00416 }
00417 
00418 // ***************************************************************************
00419 void                    CZone::serial(NLMISC::IStream &f)
00420 {
00421         /*
00422         Version 4:
00423                 - PointLights
00424         Version 3:
00425                 - Lumels compression version 2.
00426         Version 2:
00427                 - Lumels.
00428         Version 1:
00429                 - Tile color.
00430         Version 0:
00431                 - base verison.
00432         */
00433         uint    ver= f.serialVersion(4);
00434 
00435         // No more compatibility before version 3
00436         if (ver<3)
00437         {
00438                 throw EOlderStream(f);
00439         }
00440 
00441         f.serialCheck((uint32)'ENOZ');
00442 
00443         f.xmlSerial (ZoneId, "ZONE_ID");
00444         f.xmlSerial (ZoneBB, "BB");
00445         f.xmlSerial (PatchBias, "PATCH_BIAS");
00446         f.xmlSerial (PatchScale, "PATCH_SCALE");
00447         f.xmlSerial (NumVertices, "NUM_VERTICES");
00448 
00449         f.xmlPush ("BORDER_VERTICES");
00450         f.serialCont(BorderVertices);
00451         f.xmlPop ();
00452 
00453         f.xmlPush ("PATCHES");
00454         f.serialCont(Patchs);
00455         f.xmlPop ();
00456 
00457         f.xmlPush ("PATCH_CONNECTS");
00458         f.serialCont(PatchConnects);
00459         f.xmlPop ();
00460 
00461         if (ver>=4)
00462         {
00463                 f.xmlPush ("POINT_LIGHTS");
00464                 f.serial(_PointLightArray);
00465                 f.xmlPop ();
00466         }
00467 
00468         // If read and version 0, must init default TileColors of patchs.
00469         //===============================================================
00470         // if(f.isReading() && ver<2) ... 
00471         // Deprecated, because ver<3 not supported
00472 }
00473 
00474 
00475 // ***************************************************************************
00476 void                    CZone::compile(CLandscape *landscape, TZoneMap &loadedZones)
00477 {
00478         sint    i,j;
00479         TZoneMap                neighborZones;
00480 
00481         //nlinfo("Compile Zone: %d \n", (sint32)getZoneId());
00482 
00483         // Can't compile if compiled.
00484         nlassert(!Compiled);
00485         Landscape= landscape;
00486 
00487         // Attach this to loadedZones.
00488         //============================
00489         nlassert(loadedZones.find(ZoneId)==loadedZones.end());
00490         loadedZones[ZoneId]= this;
00491         
00492         // Create/link the base vertices according to present neigbor zones.
00493         //============================
00494         BaseVertices.clear();
00495         BaseVertices.resize(NumVertices);
00496         // First try to link vertices to other.
00497         for(i=0;i<(sint)BorderVertices.size();i++)
00498         {
00499                 sint    cur= BorderVertices[i].CurrentVertex;
00500                 sint    vertto= BorderVertices[i].NeighborVertex;
00501                 sint    zoneto= BorderVertices[i].NeighborZoneId;
00502                 nlassert(cur<NumVertices);
00503 
00504                 if(loadedZones.find(zoneto)!=loadedZones.end())
00505                 {
00506                         CZone   *zone;
00507                         zone= (*loadedZones.find(zoneto)).second;
00508                         nlassert(zone!=this);
00509                         // insert the zone in the neigborood (if not done...).
00510                         neighborZones[zoneto]= zone;
00511                         // Doesn't matter if BaseVertices is already linked to an other zone... 
00512                         // This should be the same pointer in this case...
00513                         BaseVertices[cur]=  zone->getBaseVertex(vertto);
00514                 }
00515         }
00516         // Else, create unbounded vertices.
00517         for(i=0;i<(sint)BaseVertices.size();i++)
00518         {
00519                 if(BaseVertices[i]==NULL)
00520                 {
00521                         BaseVertices[i]=  new CTessBaseVertex;
00522                 }
00523         }
00524 
00525 
00526         // compile() the patchs.
00527         //======================
00528         for(j=0;j<(sint)Patchs.size();j++)
00529         {
00530                 CPatch                          &pa= Patchs[j];
00531                 CPatchConnect           &pc= PatchConnects[j];
00532                 CTessVertex                     *baseVertices[4];
00533 
00534                 baseVertices[0]= &(BaseVertices[pc.BaseVertices[0]]->Vert);
00535                 baseVertices[1]= &(BaseVertices[pc.BaseVertices[1]]->Vert);
00536                 baseVertices[2]= &(BaseVertices[pc.BaseVertices[2]]->Vert);
00537                 baseVertices[3]= &(BaseVertices[pc.BaseVertices[3]]->Vert);
00538                 pa.compile(this, j, pa.OrderS, pa.OrderT, baseVertices, pc.ErrorSize);
00539         };
00540 
00541         // bind() the patchs. (after all compiled).
00542         //===================
00543         for(j=0;j<(sint)Patchs.size();j++)
00544         {
00545                 CPatch                          &pa= Patchs[j];
00546                 CPatchConnect           &pc= PatchConnects[j];
00547 
00548                 // bind the patch. This is the original bind, not a rebind.
00549                 bindPatch(loadedZones, pa, pc, false);
00550         }
00551         
00552         
00553         // rebindBorder() on neighbor zones.
00554         //==================================
00555         ItZoneMap               zoneIt;
00556         // Traverse the neighborood.
00557         for(zoneIt= neighborZones.begin(); zoneIt!=neighborZones.end(); zoneIt++)
00558         {
00559                 (*zoneIt).second->rebindBorder(loadedZones);
00560         }
00561 
00562         // End!!
00563         Compiled= true;
00564 }
00565 
00566 // ***************************************************************************
00567 void                    CZone::release(TZoneMap &loadedZones)
00568 {
00569         sint    i,j;
00570 
00571         if(!Compiled)
00572                 return;
00573 
00574         // detach this zone to loadedZones.
00575         //=================================
00576         nlassert(loadedZones.find(ZoneId)!=loadedZones.end());
00577         loadedZones.erase(ZoneId);
00578         // It doesn't server to unbindPatch(), since patch is not binded to neigbors.
00579 
00580 
00581         // unbind() the patchs.
00582         //=====================
00583         for(j=0;j<(sint)Patchs.size();j++)
00584         {
00585                 CPatch                          &pa= Patchs[j];
00586                 unbindPatch(pa);
00587         }
00588 
00589 
00590         // rebindBorder() on neighbor zones.
00591         //==================================
00592         // Build the nieghborood.
00593         TZoneMap                neighborZones;
00594         for(i=0;i<(sint)BorderVertices.size();i++)
00595         {
00596                 sint    cur= BorderVertices[i].CurrentVertex;
00597                 sint    zoneto= BorderVertices[i].NeighborZoneId;
00598                 nlassert(cur<NumVertices);
00599 
00600                 if(loadedZones.find(zoneto)!=loadedZones.end())
00601                 {
00602                         CZone   *zone;
00603                         zone= (*loadedZones.find(zoneto)).second;
00604                         nlassert(zone!=this);
00605                         // insert the zone in the neigborood (if not done...).
00606                         neighborZones[zoneto]= zone;
00607                 }
00608         }
00609         // rebind borders.
00610         ItZoneMap               zoneIt;
00611         // Traverse the neighborood.
00612         for(zoneIt= neighborZones.begin(); zoneIt!=neighborZones.end(); zoneIt++)
00613         {
00614                 // Since 
00615                 (*zoneIt).second->rebindBorder(loadedZones);
00616         }
00617 
00618 
00619         // release() the patchs.
00620         //======================
00621         // unbind() need compiled neigbor patchs, so do the release after all unbind (so after rebindBorder() too...).
00622         for(j=0;j<(sint)Patchs.size();j++)
00623         {
00624                 CPatch                          &pa= Patchs[j];
00625                 pa.release();
00626         }
00627 
00628 
00629         // destroy/unlink the base vertices (internal..), according to present neigbor zones.
00630         //=================================
00631         // Just release the smartptrs (easy!!). Do it after patchs released...
00632         BaseVertices.clear();
00633         
00634 
00635         // End!!
00636         Compiled= false;
00637         Landscape= NULL;
00638         ClipResult= ClipOut;
00639 }
00640 
00641 
00642 // ***************************************************************************
00643 // ***************************************************************************
00644 // Private part.
00645 // ***************************************************************************
00646 // ***************************************************************************
00647 
00648 
00649 // ***************************************************************************
00650 void                    CZone::rebindBorder(TZoneMap &loadedZones)
00651 {
00652         sint    j;
00653 
00654         // rebind patchs which are on border.
00655         for(j=0;j<(sint)Patchs.size();j++)
00656         {
00657                 CPatch                          &pa= Patchs[j];
00658                 CPatchConnect           &pc= PatchConnects[j];
00659 
00660                 if(patchOnBorder(pc))
00661                 {
00662                         // rebind the patch. This is a rebind.
00663                         bindPatch(loadedZones, pa, pc, true);
00664                 }
00665         }
00666 }
00667 
00668 // ***************************************************************************
00669 CPatch          *CZone::getZonePatch(TZoneMap &loadedZones, sint zoneId, sint patch)
00670 {
00671 #ifdef NL3D_DEBUG_DONT_BIND_PATCH
00672         return NULL;
00673 #endif
00674         if(loadedZones.find(zoneId)==loadedZones.end())
00675                 return NULL;
00676         else
00677                 return (loadedZones[zoneId])->getPatch(patch);
00678 }
00679 
00680 
00681 // ***************************************************************************
00682 void            CZone::buildBindInfo(uint patchId, uint edge, CZone *neighborZone, CPatch::CBindInfo    &paBind)
00683 {
00684         nlassert(patchId < Patchs.size());
00685         nlassert(neighborZone);
00686 
00687         CPatchConnect   &pc= PatchConnects[patchId];
00688 
00689 
00690         // Get the bind info of this patch to his neighbor on "edge".
00691         CPatchInfo::CBindInfo   &pcBind= pc.BindEdges[edge];
00692         nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
00693 
00694 
00695         // copy zone ptr.
00696         paBind.Zone= neighborZone;
00697 
00698 
00699         // Special case of a small patch connected to a bigger.
00700         if(pcBind.NPatchs==5)
00701         {
00702                 paBind.NPatchs= 1;
00703                 paBind.Next[0]= neighborZone->getPatch(pcBind.Next[0]);
00704                 paBind.Edge[0]= pcBind.Edge[0];
00705                 
00706                 // Get the twin bindInfo of pcBind.
00707                 const CPatchInfo::CBindInfo     &pcBindNeighbor= 
00708                         neighborZone->getPatchConnect(pcBind.Next[0])->BindEdges[pcBind.Edge[0]];
00709                 // must have a multiple bind.   
00710                 nlassert(pcBindNeighbor.NPatchs == 2 || pcBindNeighbor.NPatchs == 4);
00711 
00712                 // number of bind is stored on the twin bindInfo.
00713                 paBind.MultipleBindNum= pcBindNeighbor.NPatchs;
00714 
00715                 // Search our patchId on neighbor;
00716                 paBind.MultipleBindId= 255;
00717                 for(sint i=0; i<paBind.MultipleBindNum; i++)
00718                 {
00719                         if(pcBindNeighbor.Next[i]==patchId)
00720                                 paBind.MultipleBindId= i;
00721                 }
00722                 nlassert(paBind.MultipleBindId!= 255);
00723         }
00724         else
00725         {
00726                 paBind.MultipleBindNum= 0;
00727                 paBind.NPatchs= pcBind.NPatchs;
00728                 for(sint i=0;i<paBind.NPatchs; i++)
00729                 {
00730                         paBind.Next[i]= neighborZone->getPatch(pcBind.Next[i]);
00731                         paBind.Edge[i]= pcBind.Edge[i];
00732                 }
00733         }
00734 
00735 
00736 }
00737 
00738 
00739 // ***************************************************************************
00740 void            CZone::bindPatch(TZoneMap &loadedZones, CPatch &pa, CPatchConnect &pc, bool rebind)
00741 {
00742         CPatch::CBindInfo       edges[4];
00743 
00744         // Fill all edges.
00745         for(sint i=0;i<4;i++)
00746         {
00747                 CPatchInfo::CBindInfo   &pcBind= pc.BindEdges[i];
00748                 CPatch::CBindInfo               &paBind= edges[i];
00749 
00750                 nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
00751                 paBind.NPatchs= pcBind.NPatchs;
00752 
00753 
00754                 // Find the zone.
00755                 TZoneMap::iterator      itZoneMap;
00756                 // If no neighbor, or if zone neighbor not loaded.
00757                 if( paBind.NPatchs==0 || (itZoneMap=loadedZones.find(pcBind.ZoneId)) == loadedZones.end() )
00758                         paBind.Zone= NULL;
00759                 else
00760                         paBind.Zone= itZoneMap->second;
00761 
00762 
00763                 // Special case of a small patch connected to a bigger.
00764                 if(paBind.NPatchs==5)
00765                 {
00766                         paBind.Edge[0]= pcBind.Edge[0];
00767                         paBind.Next[0]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[0]);
00768                         // If not loaded, don't bind to this edge.
00769                         if(!paBind.Next[0])
00770                                 paBind.NPatchs=0;
00771                         else
00772                         {
00773                                 // Get the BindInfo on me stored in our neighbor bigger CPatch
00774                                 CPatch::CBindInfo       nbOnMe;
00775                                 paBind.Next[0]->getBindNeighbor(paBind.Edge[0], nbOnMe);
00776                                 // if this patch has not already been binded on me, nbOnMe.Zone==NULL
00777                                 if( nbOnMe.Zone == NULL )
00778                                 {
00779                                         // Simple case: do nothing: don't need to rebind() to the bigger patch since 
00780                                         // himself is not bound
00781                                         paBind.NPatchs=0;
00782                                         paBind.Zone= NULL;
00783                                 }
00784                                 else
00785                                 {
00786                                         // pa.bind() will do the job.
00787                                         // Leave it flagged with NPatchs==5.
00788                                         continue;
00789                                 }
00790                         }
00791                 }
00792 
00793 
00794                 // Bind 1/1 and 1/2,1/4
00795                 if(paBind.NPatchs>=1)
00796                 {
00797                         paBind.Edge[0]= pcBind.Edge[0];
00798                         paBind.Next[0]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[0]);
00799                         // If not loaded, don't bind to this edge.
00800                         if(!paBind.Next[0])
00801                                 paBind.NPatchs=0;
00802                 }
00803                 if(paBind.NPatchs>=2)
00804                 {
00805                         paBind.Edge[1]= pcBind.Edge[1];
00806                         paBind.Next[1]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[1]);
00807                         // If not loaded, don't bind to this edge.
00808                         if(!paBind.Next[1])
00809                                 paBind.NPatchs=0;
00810                 }
00811                 if(paBind.NPatchs>=4)
00812                 {
00813                         paBind.Edge[2]= pcBind.Edge[2];
00814                         paBind.Edge[3]= pcBind.Edge[3];
00815                         paBind.Next[2]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[2]);
00816                         paBind.Next[3]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[3]);
00817                         // If not loaded, don't bind to this edge.
00818                         if(!paBind.Next[2] || !paBind.Next[3])
00819                                 paBind.NPatchs=0;
00820                 }
00821         }
00822 
00823         // First, unbind.
00824         pa.unbind();
00825 
00826         // Then bind.
00827         pa.bind(edges, rebind);
00828 }
00829 
00830 
00831 // ***************************************************************************
00832 void            CZone::unbindPatch(CPatch &pa)
00833 {
00834         /*
00835                 Remind: the old version with CPatch::unbindFrom*() doesn't work because of CZone::release(). This function
00836                 first erase the zone from loadedZones...
00837                 Not matter here. We use CPatch::unbind() which should do all the good job correctly (unbind pa from ohters
00838                 , and unbind others from pa at same time).
00839         */
00840 
00841         pa.unbind();
00842 }
00843 
00844 
00845 // ***************************************************************************
00846 bool                    CZone::patchOnBorder(const CPatchConnect &pc) const
00847 {
00848         // If only one of neighbor patch is not of this zone, we are on a border.
00849 
00850         // Test all edges.
00851         for(sint i=0;i<4;i++)
00852         {
00853                 const CPatchInfo::CBindInfo     &pcBind= pc.BindEdges[i];
00854 
00855                 nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
00856                 if(pcBind.NPatchs>=1)
00857                 {
00858                         if(pcBind.ZoneId != ZoneId)
00859                                 return true;
00860                 }
00861         }
00862 
00863         return false;
00864 }
00865 
00866 
00867 // ***************************************************************************
00868 // ***************************************************************************
00869 // Render part.
00870 // ***************************************************************************
00871 // ***************************************************************************
00872 
00873 
00874 // ***************************************************************************
00875 void                    CZone::clip(const std::vector<CPlane>   &pyramid)
00876 {
00877         nlassert(Compiled);
00878 
00879         // bkup old ClipResult. NB: by default, it is ClipOut (no VB created).
00880         sint    oldClipResult= ClipResult;
00881 
00882         // Compute ClipResult.
00883         //-------------------
00884         ClipResult= ClipIn;
00885         for(sint i=0;i<(sint)pyramid.size();i++)
00886         {
00887                 // If entirely out.
00888                 if(!ZoneBB.clipBack(pyramid[i]))
00889                 {
00890                         ClipResult= ClipOut;
00891                         // If out of only one plane, out of all.
00892                         break;
00893                 }
00894                 // If partially IN (ie not entirely out, and not entirely IN)
00895                 else if(ZoneBB.clipFront(pyramid[i]))
00896                 {
00897                         // Force ClipResult to be ClipSide, and not ClipIn.
00898                         ClipResult=ClipSide;
00899                 }
00900         }
00901 
00902 
00903         // Easy Clip  :)
00904         if(Patchs.size()==0)
00905         {
00906                 ClipResult= ClipOut;
00907                 // don't need to go below...
00908                 return;
00909         }
00910 
00911 
00912         // Clip By Patch Pass.
00913         //--------------------
00914         if(ClipResult==ClipOut)
00915         {
00916                 CPatch          *pPatch= &(*Patchs.begin());
00917                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
00918                 {
00919                         // The patch is entirely clipped, and so on for Render.
00920                         pPatch->forceClip();
00921                         pPatch->forceRenderClip();
00922                 }
00923         }
00924         else if(ClipResult==ClipIn)
00925         {
00926                 CPatch          *pPatch= &(*Patchs.begin());
00927                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
00928                 {
00929                         // The patch is entirely unclipped, and so on for Render.
00930                         pPatch->forceNoClip();
00931                         pPatch->forceNoRenderClip();
00932                 }
00933         }
00934         else
00935         {
00936                 CPatch          *pPatch= &(*Patchs.begin());
00937                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
00938                 {
00939                         pPatch->clip(pyramid);
00940                 }
00941         }
00942 
00943 
00944         // delete / reallocate / fill VBuffers.
00945         //-------------------
00946         // If there is a change in the Clip of the zone, or if patchs may have change (ie ClipSide is undetermined).
00947         if(oldClipResult!=ClipResult || oldClipResult==ClipSide)
00948         {
00949                 // Then, we must test by patch.
00950                 CPatch          *pPatch= &(*Patchs.begin());
00951                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
00952                 {
00953                         // For all patchs, we may delete or allocate / Fill VBs.
00954                         pPatch->updateClipPatchVB();
00955                 }
00956 
00957         }
00958 
00959 }
00960 
00961 
00962 // ***************************************************************************
00963 // DebugYoyo.
00964 // Code for Debug test Only.. Do not erase it, may be used later :)
00965 /*
00966 static  void    cleanTess(CTessFace *face)
00967 {
00968         if(!face->isLeaf())
00969         {
00970                 cleanTess(face->SonLeft);
00971                 cleanTess(face->SonRight);
00972         }
00973         // If has father, clean it.
00974         if(face->Father)
00975         {
00976                 CTessFace       *face1=face->Father;
00977                 CTessFace       *face2=face->Father->FBase;
00978                 face1->FLeft= face1->SonLeft->FBase;
00979                 face1->FRight= face1->SonRight->FBase;
00980                 if(face2!=NULL)
00981                 {
00982                         face2->FLeft= face2->SonLeft->FBase;
00983                         face2->FRight= face2->SonRight->FBase;
00984                 }
00985         }
00986 }
00987 static  void    testTess(CTessFace *face)
00988 {
00989         if(!face->isLeaf())
00990         {
00991                 testTess(face->SonLeft);
00992                 testTess(face->SonRight);
00993         }
00994         // Test validity.
00995         nlassert(!face->FBase || face->FBase->Patch!=(CPatch*)0xdddddddd);
00996         nlassert(!face->FLeft || face->FLeft->Patch!=(CPatch*)0xdddddddd);
00997         nlassert(!face->FRight || face->FRight->Patch!=(CPatch*)0xdddddddd);
00998 }
00999 static  void    checkTess()
01000 {
01001         // This test should be inserted at begin of CZone::refine().
01002         // And it needs hacking public/private.
01003         CPatch          *pPatch;
01004         sint            n;
01005         pPatch= &(*Patchs.begin());
01006         for(n=(sint)Patchs.size();n>0;n--, pPatch++)
01007         {
01008                 cleanTess(pPatch->Son0);
01009                 cleanTess(pPatch->Son1);
01010         }
01011         pPatch= &(*Patchs.begin());
01012         for(n=(sint)Patchs.size();n>0;n--, pPatch++)
01013         {
01014                 testTess(pPatch->Son0);
01015                 testTess(pPatch->Son1);
01016         }
01017 }
01018 */
01019 
01020 
01021 // ***************************************************************************
01022 void                    CZone::excludePatchFromRefineAll(uint patch, bool exclude)
01023 {
01024         nlassert(Compiled);
01025         nlassert(patch<Patchs.size());
01026 
01027         if(patch>=Patchs.size())
01028                 return;
01029 
01030         Patchs[patch].ExcludeFromRefineAll= exclude;
01031 }
01032 
01033 
01034 // ***************************************************************************
01035 void                    CZone::refineAll()
01036 {
01037         nlassert(Compiled);
01038 
01039         // Fuck stlport....
01040         if(Patchs.size()==0)
01041                 return;
01042 
01043         // Do a dummy clip.
01044         CPatch          *pPatch= &(*Patchs.begin());
01045         sint n;
01046         for(n=(sint)Patchs.size();n>0;n--, pPatch++)
01047         {
01048                 pPatch->forceNoClip();
01049                 // DO NOT do a forceNoRenderClip(), to avoid big allocation of Near/Far VB vertices in driver.
01050         }
01051         // DO NOT modify ClipResult, to avoid big allocation of Near/Far VB vertices in driver.
01052 
01053 
01054         // refine ALL patchs (even those which may be invisible).
01055         pPatch= &(*Patchs.begin());
01056         for(n=(sint)Patchs.size();n>0;n--, pPatch++)
01057         {
01058                 // For Pacs construction: may exclude some patch from refineAll (for speed improvement).
01059                 if(!pPatch->ExcludeFromRefineAll)
01060                         pPatch->refineAll();
01061         }
01062 
01063 }
01064 
01065 
01066 // ***************************************************************************
01067 void                    CZone::averageTesselationVertices()
01068 {
01069         nlassert(Compiled);
01070 
01071         // Fuck stlport....
01072         if(Patchs.size()==0)
01073                 return;
01074 
01075         // averageTesselationVertices of ALL patchs.
01076         CPatch          *pPatch= &(*Patchs.begin());
01077         for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01078         {
01079                 pPatch->averageTesselationVertices();
01080         }
01081 }
01082 
01083 
01084 // ***************************************************************************
01085 void                    CZone::preRender()
01086 {
01087         nlassert(Compiled);
01088 
01089         // Must be 2^X-1.
01090         static const    sint    updateFarRefineFreq= 15;
01091         // Take the renderDate here.
01092         sint            curDateMod= CLandscapeGlobals::CurrentRenderDate & updateFarRefineFreq;
01093 
01094         // If no patchs, do nothing.
01095         if(Patchs.empty())
01096                 return;
01097 
01098         /* If patchs invisible, must still update their Far Textures,
01099                 else, there may be slowdown when we turn the head.
01100         */
01101 
01102 
01103         // If all the zone is invisible.
01104         if(ClipResult==ClipOut)
01105         {
01106                 // No patchs are visible, but maybe update the far textures.
01107                 if( curDateMod==(ZoneId & updateFarRefineFreq) )
01108                 {
01109                         // updateTextureFarOnly for all patchs.
01110                         CPatch          *pPatch= &(*Patchs.begin());
01111                         for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01112                                 pPatch->updateTextureFarOnly();
01113                 }
01114         }
01115         // else If some patchs only are visible.
01116         else if(ClipResult==ClipSide)
01117         {
01118                 // PreRender Pass, or updateTextureFarOnly(), according to RenderClipped state.
01119                 CPatch          *pPatch= &(*Patchs.begin());
01120                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01121                 {
01122                         // If the patch is visible
01123                         if(!pPatch->isRenderClipped())
01124                         {
01125                                 // Then preRender it.
01126                                 pPatch->preRender();
01127                         }
01128                         else
01129                         {
01130                                 // else maybe updateFar it.
01131                                 // ZoneId+n for better repartition.
01132                                 if( curDateMod==((ZoneId+n) & updateFarRefineFreq) )
01133                                         pPatch->updateTextureFarOnly();
01134                         }
01135                 }
01136         }
01137         else    // ClipResult==ClipIn
01138         {
01139                 // PreRender Pass for All
01140                 CPatch          *pPatch= &(*Patchs.begin());
01141                 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01142                         pPatch->preRender();
01143         }
01144 
01145 }
01146 
01147 
01148 // ***************************************************************************
01149 void                    CZone::resetRenderFarAndDeleteVBFV()
01150 {
01151         CPatch          *pPatch=0;
01152         if(Patchs.size()>0)
01153                 pPatch= &(*Patchs.begin());
01154         for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01155         {
01156                 // If patch is visible
01157                 if(!pPatch->RenderClipped)
01158                 {
01159                         // release VertexBuffer, and FaceBuffer
01160                         pPatch->deleteVBAndFaceVector();
01161                         // Flag.
01162                         pPatch->RenderClipped= true;
01163                 }
01164 
01165                 pPatch->resetRenderFar();
01166         }
01167 }
01168 
01169 
01170 // ***************************************************************************
01171 void                    CZone::forceMergeAtTileLevel()
01172 {
01173         CPatch          *pPatch=0;
01174         if(Patchs.size()>0)
01175                 pPatch= &(*Patchs.begin());
01176         for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
01177         {
01178                 pPatch->forceMergeAtTileLevel();
01179         }
01180 }
01181 
01182 
01183 // ***************************************************************************
01184 // ***************************************************************************
01185 // Misc part.
01186 // ***************************************************************************
01187 // ***************************************************************************
01188 
01189 
01190 // ***************************************************************************
01191 void                    CZone::changePatchTextureAndColor (sint numPatch, const std::vector<CTileElement> *tiles, const std::vector<CTileColor> *colors)
01192 {
01193         nlassert(numPatch>=0);
01194         nlassert(numPatch<getNumPatchs());
01195         
01196 
01197         // Update the patch texture.
01198         if (tiles)
01199         {
01200                 nlassert( Patchs[numPatch].Tiles.size() == tiles->size() );
01201                 Patchs[numPatch].Tiles = *tiles;
01202         }
01203 
01204         // Update the patch colors.
01205         if (colors)
01206         {
01207                 nlassert( Patchs[numPatch].TileColors.size() == colors->size() );
01208                 Patchs[numPatch].TileColors = *colors;
01209         }
01210 
01211         if (Compiled)
01212         {
01213                 // If the patch is visible, then we must LockBuffers, because new VertexVB may be created.
01214                 if(!Patchs[numPatch].RenderClipped)
01215                         Landscape->updateGlobalsAndLockBuffers(CVector::Null);
01216 
01217                 // Recompute UVs for new setup of Tiles.
01218                 Patchs[numPatch].deleteTileUvs();
01219                 Patchs[numPatch].recreateTileUvs();
01220 
01221                 // unlockBuffers() if necessary.
01222                 if(!Patchs[numPatch].RenderClipped)
01223                 {
01224                         Landscape->unlockBuffers();
01225                         // This patch is visible, and TileFaces have been deleted / added.
01226                         // So must update TessBlock.
01227                         Landscape->updateTessBlocksFaceVector();
01228                 }
01229         }
01230 }
01231 
01232 
01233 // ***************************************************************************
01234 void                    CZone::refreshTesselationGeometry(sint numPatch)
01235 {
01236         nlassert(numPatch>=0);
01237         nlassert(numPatch<getNumPatchs());
01238         nlassert(Compiled);
01239 
01240         // At next render, we must re-fill the entire unclipped VB, so change are taken into account.
01241         Landscape->_RenderMustRefillVB= true;
01242 
01243         Patchs[numPatch].refreshTesselationGeometry();
01244 }
01245 
01246 
01247 // ***************************************************************************
01248 const std::vector<CTileElement> &CZone::getPatchTexture(sint numPatch) const
01249 {
01250         nlassert(numPatch>=0);
01251         nlassert(numPatch<getNumPatchs());
01252 
01253         // Update the patch texture.
01254         return Patchs[numPatch].Tiles;
01255 }
01256 
01257 
01258 // ***************************************************************************
01259 const std::vector<CTileColor> &CZone::getPatchColor(sint numPatch) const
01260 {
01261         nlassert(numPatch>=0);
01262         nlassert(numPatch<getNumPatchs());
01263 
01264         // Update the patch texture.
01265         return Patchs[numPatch].TileColors;
01266 }
01267 
01268 
01269 // ***************************************************************************
01270 void                    CZone::debugBinds(FILE *f)
01271 {
01272         fprintf(f, "*****************************\n");
01273         fprintf(f, "ZoneId: %d. NPatchs:%d\n", ZoneId, PatchConnects.size());
01274         sint i;
01275         for(i=0;i<(sint)PatchConnects.size();i++)
01276         {
01277                 CPatchConnect   &pc= PatchConnects[i];
01278                 fprintf(f, "patch%d:\n", i);
01279                 for(sint j=0;j<4;j++)
01280                 {
01281                         CPatchInfo::CBindInfo   &bd= pc.BindEdges[j];
01282                         fprintf(f, "    edge%d: Zone:%d. NPatchs:%d. ", j, bd.ZoneId, bd.NPatchs);
01283                         for(sint k=0;k<bd.NPatchs;k++)
01284                         {
01285                                 fprintf(f, "p%de%d - ", bd.Next[k], bd.Edge[k]);
01286                         }
01287                         fprintf(f, "\n");
01288                 }
01289         }
01290 
01291         fprintf(f,"Vertices :\n");
01292         for(i=0;i<(sint)BorderVertices.size();i++)
01293         {
01294                 fprintf(f,"current : %d -> (zone %d) vertex %d\n",BorderVertices[i].CurrentVertex,
01295                                                                                         BorderVertices[i].NeighborZoneId,
01296                                                                                         BorderVertices[i].NeighborVertex);
01297         }
01298 }
01299 
01300 
01301 // ***************************************************************************
01302 void                    CZone::applyHeightField(const CLandscape &landScape)
01303 {
01304         sint    i,j;
01305         vector<CBezierPatch>    patchs;
01306 
01307         // no patch, do nothing.
01308         if(Patchs.size()==0)
01309                 return;
01310 
01311         // 0. Unpack patchs to Bezier Patchs.
01312         //===================================
01313         patchs.resize(Patchs.size());
01314         for(j=0;j<(sint)patchs.size();j++)
01315         {
01316                 CBezierPatch            &p= patchs[j];
01317                 CPatch                          &pa= Patchs[j];
01318 
01319                 // re-Build the uncompressed bezier patch.
01320                 for(i=0;i<4;i++)
01321                         pa.Vertices[i].unpack(p.Vertices[i], PatchBias, PatchScale);
01322                 for(i=0;i<8;i++)
01323                         pa.Tangents[i].unpack(p.Tangents[i], PatchBias, PatchScale);
01324                 for(i=0;i<4;i++)
01325                         pa.Interiors[i].unpack(p.Interiors[i], PatchBias, PatchScale);
01326         }
01327 
01328         // 1. apply heightfield on bezier patchs.
01329         //===================================
01330         for(j=0;j<(sint)patchs.size();j++)
01331         {
01332                 CBezierPatch            &p= patchs[j];
01333 
01334                 // apply delta.
01335                 for(i=0;i<4;i++)
01336                         p.Vertices[i]+= landScape.getHeightFieldDeltaZ(p.Vertices[i].x, p.Vertices[i].y);
01337                 for(i=0;i<8;i++)
01338                         p.Tangents[i]+= landScape.getHeightFieldDeltaZ(p.Tangents[i].x, p.Tangents[i].y);
01339                 for(i=0;i<4;i++)
01340                         p.Interiors[i]+= landScape.getHeightFieldDeltaZ(p.Interiors[i].x, p.Interiors[i].y);
01341         }
01342 
01343 
01344         // 2. Re-compute Patch Scale/Bias, and Zone BBox.
01345         //===================================
01346         CAABBox         bb;
01347         bb.setCenter(patchs[0].Vertices[0]);
01348         bb.setHalfSize(CVector::Null);
01349         for(j=0;j<(sint)patchs.size();j++)
01350         {
01351                 // extend bbox.
01352                 const CBezierPatch      &p= patchs[j];
01353                 for(i=0;i<4;i++)
01354                         bb.extend(p.Vertices[i]);
01355                 for(i=0;i<8;i++)
01356                         bb.extend(p.Tangents[i]);
01357                 for(i=0;i<4;i++)
01358                         bb.extend(p.Interiors[i]);
01359         }
01360         // Compute BBox, and Patch Scale Bias, according to Noise.
01361         computeBBScaleBias(bb);
01362 
01363 
01364         // 3. Re-pack patchs.
01365         //===================================
01366         for(j=0;j<(sint)patchs.size();j++)
01367         {
01368                 CBezierPatch            &p= patchs[j];
01369                 CPatch                          &pa= Patchs[j];
01370 
01371                 // Build the packed patch.
01372                 for(i=0;i<4;i++)
01373                         pa.Vertices[i].pack(p.Vertices[i], PatchBias, PatchScale);
01374                 for(i=0;i<8;i++)
01375                         pa.Tangents[i].pack(p.Tangents[i], PatchBias, PatchScale);
01376                 for(i=0;i<4;i++)
01377                         pa.Interiors[i].pack(p.Interiors[i], PatchBias, PatchScale);
01378         }
01379 }
01380 
01381 // ***************************************************************************
01382 void CZone::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
01383 {
01384         for (uint k = 0; k < Patchs.size(); ++k)
01385         {
01386                 Patchs[k].setupColorsFromTileFlags(colors);
01387         }
01388 }
01389 
01390 
01391 // ***************************************************************************
01392 void CZone::copyTilesFlags(sint destPatchId, const CPatch *srcPatch)
01393 {
01394         CPatch *destPatch = getPatch(destPatchId);
01395         
01396         destPatch->copyTileFlagsFromPatch(srcPatch);
01397 }
01398 
01399 
01400 // ***************************************************************************
01401 bool CPatchInfo::getNeighborTile (uint patchId, uint edge, sint position, uint &patchOut, sint &sOut, sint &tOut, 
01402                                                                   const vector<CPatchInfo> &patchInfos) const
01403 {
01404         nlassert (edge<4);
01405 
01406         // S or T ?
01407         uint length = (edge&1) ? OrderS : OrderT;
01408         nlassert ((uint)position<length);
01409 
01410         // What kind of case ?
01411         switch (BindEdges[edge].NPatchs)
01412         {
01413         case 1:
01414         case 2:
01415         case 4:
01416                 {
01417                         // Get neighbor index and position in neighbor
01418                         uint neighborLength = (length / BindEdges[edge].NPatchs);
01419                         uint neighbor = position / neighborLength;
01420                         uint neighborPosition = neighborLength - (position % neighborLength) - 1;
01421                         uint neighborEdge = BindEdges[edge].Edge[neighbor];
01422 
01423                         // Patch id
01424                         patchOut = BindEdges[edge].Next[neighbor];
01425 
01426                         // Check neighbor
01427                         uint neighborRealLength = (neighborEdge&1) ? patchInfos[patchOut].OrderS : patchInfos[patchOut].OrderT;
01428                         if (neighborRealLength == neighborLength)
01429                         {
01430                                 // Get final coordinate
01431                                 switch (neighborEdge)
01432                                 {
01433                                 case 0:
01434                                         sOut = 0;
01435                                         tOut = neighborPosition;
01436                                         break;
01437                                 case 1:
01438                                         sOut = neighborPosition;
01439                                         tOut = patchInfos[patchOut].OrderT-1;
01440                                         break;
01441                                 case 2:
01442                                         sOut = patchInfos[patchOut].OrderS-1;
01443                                         tOut = patchInfos[patchOut].OrderT-neighborPosition-1;
01444                                         break;
01445                                 case 3:
01446                                         sOut = patchInfos[patchOut].OrderS-neighborPosition-1;
01447                                         tOut = 0;
01448                                         break;
01449                                 }
01450 
01451                                 // Ok todo remove
01452                                 return true;
01453                         }
01454                 }
01455                 break;
01456         
01457         case 5:
01458                 {
01459                         // Find in the neighbor where we are
01460                         patchOut = BindEdges[edge].Next[0];
01461                         uint neighborEdge = BindEdges[edge].Edge[0];
01462                         uint neighborEdgeCount = patchInfos[patchOut].BindEdges[neighborEdge].NPatchs;
01463 
01464                         // Check neighbor
01465                         uint neighborRealLength = (neighborEdge&1) ? patchInfos[patchOut].OrderS : patchInfos[patchOut].OrderT;
01466 
01467                         // Good length ?
01468                         if ((neighborRealLength / neighborEdgeCount) == length)
01469                         {
01470                                 // Find us in the neighbor
01471                                 uint neighborPosition;
01472                                 for (neighborPosition=0; neighborPosition<neighborEdgeCount; neighborPosition++)
01473                                 {
01474                                         // Found ?
01475                                         if (patchInfos[patchOut].BindEdges[neighborEdge].Next[neighborPosition] == patchId)
01476                                                 break;
01477                                 }
01478 
01479                                 // Must be found
01480                                 nlassert (neighborPosition!=neighborEdgeCount);
01481                                 neighborPosition = (neighborPosition + 1) * (neighborRealLength / neighborEdgeCount) - position - 1;
01482 
01483                                 // Get final coordinate
01484                                 switch (neighborEdge)
01485                                 {
01486                                 case 0:
01487                                         sOut = 0;
01488                                         tOut = neighborPosition;
01489                                         break;
01490                                 case 1:
01491                                         sOut = neighborPosition;
01492                                         tOut = patchInfos[patchOut].OrderT-1;
01493                                         break;
01494                                 case 2:
01495                                         sOut = patchInfos[patchOut].OrderS-1;
01496                                         tOut = patchInfos[patchOut].OrderT-neighborPosition-1;
01497                                         break;
01498                                 case 3:
01499                                         sOut = patchInfos[patchOut].OrderS-neighborPosition-1;
01500                                         tOut = 0;
01501                                         break;
01502                                 }
01503 
01504                                 // Ok
01505                                 return true;
01506                         }
01507                 }
01508                 break;
01509         }
01510 
01511         return false;
01512 }
01513 
01514 
01515 // ***************************************************************************
01516 
01517 bool CPatchInfo::getTileSymmetryRotate (const CTileBank &bank, uint tile, bool &symmetry, uint &rotate)
01518 {
01519         // Need check the tile ?
01520         if ( (symmetry || (rotate != 0)) && (tile != 0xffffffff) )
01521         {
01522                 // Tile exist ?
01523                 if (tile < (uint)bank.getTileCount())
01524                 {
01525                         // Get xref
01526                         int tileSet;
01527                         int number;
01528                         CTileBank::TTileType type;
01529 
01530                         // Get tile xref
01531                         bank.getTileXRef ((int)tile, tileSet, number, type);
01532 
01533                         // Is it an oriented tile ?
01534                         if (bank.getTileSet (tileSet)->getOriented())
01535                         {
01536                                 // New rotation value
01537                                 rotate = 0;
01538                         }
01539 
01540                         // Ok
01541                         return true;
01542                 }
01543 
01544                 return false;
01545         }
01546         else
01547                 return true;
01548 }
01549 
01550 // ***************************************************************************
01551 
01552 bool CPatchInfo::transformTile (const CTileBank &bank, uint &tile, uint &tileRotation, bool symmetry, uint rotate, bool goofy)
01553 {
01554         // Tile exist ?
01555         if ( (rotate!=0) || symmetry )
01556         {
01557                 if (tile < (uint)bank.getTileCount())
01558                 {
01559                         // Get xref
01560                         int tileSet;
01561                         int number;
01562                         CTileBank::TTileType type;
01563 
01564                         // Get tile xref
01565                         bank.getTileXRef ((int)tile, tileSet, number, type);
01566 
01567                         // Transition ?
01568                         if (type == CTileBank::transition)
01569                         {
01570                                 // Rotation for transition
01571                                 uint transRotate = rotate;
01572 
01573                                 // Number should be ok
01574                                 nlassert (number>=0);
01575                                 nlassert (number<CTileSet::count);
01576 
01577                                 // Tlie set number
01578                                 const CTileSet *pTileSet = bank.getTileSet (tileSet);
01579 
01580                                 // Get border desc
01581                                 CTileSet::TFlagBorder oriented[4] = 
01582                                 {       
01583                                         pTileSet->getOrientedBorder (CTileSet::left, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::left)),
01584                                         pTileSet->getOrientedBorder (CTileSet::bottom, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::bottom)),
01585                                         pTileSet->getOrientedBorder (CTileSet::right, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::right)),
01586                                         pTileSet->getOrientedBorder (CTileSet::top, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::top))
01587                                 };
01588 
01589                                 // Symmetry ?
01590                                 if (symmetry)
01591                                 {
01592                                         if ( (tileRotation & 1) ^ goofy )
01593                                         {
01594                                                 CTileSet::TFlagBorder tmp = oriented[1];
01595                                                 oriented[1] = CTileSet::getInvertBorder (oriented[3]);
01596                                                 oriented[3] = CTileSet::getInvertBorder (tmp);
01597                                                 oriented[2] = CTileSet::getInvertBorder (oriented[2]);
01598                                                 oriented[0] = CTileSet::getInvertBorder (oriented[0]);
01599                                         }
01600                                         else
01601                                         {
01602                                                 CTileSet::TFlagBorder tmp = oriented[0];
01603                                                 oriented[0] = CTileSet::getInvertBorder (oriented[2]);
01604                                                 oriented[2] = CTileSet::getInvertBorder (tmp);
01605                                                 oriented[1] = CTileSet::getInvertBorder (oriented[1]);
01606                                                 oriented[3] = CTileSet::getInvertBorder (oriented[3]);
01607                                         }
01608                                 }
01609 
01610                                 // Rotation
01611                                 CTileSet::TFlagBorder edges[4];
01612                                 edges[0] = pTileSet->getOrientedBorder (CTileSet::left, oriented[(0 + transRotate )&3]);
01613                                 edges[1] = pTileSet->getOrientedBorder (CTileSet::bottom, oriented[(1 + transRotate )&3]);
01614                                 edges[2] = pTileSet->getOrientedBorder (CTileSet::right, oriented[(2 + transRotate )&3]);
01615                                 edges[3] = pTileSet->getOrientedBorder (CTileSet::top, oriented[(3 + transRotate )&3]);
01616 
01617                                 // Get the good tile number
01618                                 CTileSet::TTransition transition = pTileSet->getTransitionTile (edges[3], edges[1], edges[0], edges[2]);
01619                                 nlassert ((CTileSet::TTransition)transition != CTileSet::notfound);
01620                                 tile = (uint)(pTileSet->getTransition (transition)->getTile ());
01621                         }
01622 
01623                         // Transform rotation: invert rotation
01624                         tileRotation += rotate;
01625 
01626                         // If goofy, add +2
01627                         if (goofy && symmetry)
01628                                 tileRotation += 2;
01629 
01630                         // Mask the rotation
01631                         tileRotation &= 3;
01632                 }
01633                 else
01634                         return false;
01635         }
01636 
01637         // Ok
01638         return true;
01639 }
01640 
01641 // ***************************************************************************
01642 
01643 void CPatchInfo::transform256Case (const CTileBank &bank, uint8 &case256, uint tileRotation, bool symmetry, uint rotate, bool goofy)
01644 {
01645         // Tile exist ?
01646         if ( (rotate!=0) || symmetry )
01647         {
01648                 // Symmetry ?
01649                 if (symmetry)
01650                 {
01651                         // Take the symmetry
01652                         uint symArray[4] = {3, 2, 1, 0};
01653                         case256 = symArray[case256];
01654 
01655                         if (goofy && ((tileRotation & 1) ==0))
01656                                 case256 += 2;
01657                         if ((!goofy) && (tileRotation & 1))
01658                                 case256 += 2;
01659                 }
01660 
01661                 // Rotation ?
01662                 case256 -= rotate;
01663                 case256 &= 3;
01664         }
01665 }
01666 
01667 // ***************************************************************************
01668 
01669 bool CPatchInfo::transform (std::vector<CPatchInfo> &patchInfo, NL3D::CZoneSymmetrisation &zoneSymmetry, const NL3D::CTileBank &bank, bool symmetry, uint rotate, float snapCell, float weldThreshold, const NLMISC::CMatrix &toOriginalSpace)
01670 {
01671         uint patchCount = patchInfo.size ();
01672         uint i;
01673 
01674         // --- Export tile info Symmetry of the bind info.
01675         // --- Parse each patch and each edge
01676 
01677         // For each patches
01678         NL3D::CZoneSymmetrisation::CError error;
01679         
01680         // Build the structure
01681         if (!zoneSymmetry.build (patchInfo, snapCell, weldThreshold, bank, error, toOriginalSpace))
01682         {
01683                 return false;
01684         }
01685         
01686         // Symmetry ?
01687         if (symmetry)
01688         {
01689                 for(i=0 ; i<patchCount; i++)
01690                 {
01691                         // Ref on the current patch
01692                         CPatchInfo &pi = patchInfo[i];
01693 
01694                         // --- Symmetry vertex indexes
01695 
01696                         // Vertices
01697                         CVector tmp = pi.Patch.Vertices[0];
01698                         pi.Patch.Vertices[0] = pi.Patch.Vertices[3];
01699                         pi.Patch.Vertices[3] = tmp;
01700                         tmp = pi.Patch.Vertices[1];
01701                         pi.Patch.Vertices[1] = pi.Patch.Vertices[2];
01702                         pi.Patch.Vertices[2] = tmp;
01703 
01704                         // Tangents
01705                         tmp = pi.Patch.Tangents[0];
01706                         pi.Patch.Tangents[0] = pi.Patch.Tangents[5];
01707                         pi.Patch.Tangents[5] = tmp;
01708                         tmp = pi.Patch.Tangents[1];
01709                         pi.Patch.Tangents[1] = pi.Patch.Tangents[4];
01710                         pi.Patch.Tangents[4] = tmp;
01711                         tmp = pi.Patch.Tangents[2];
01712                         pi.Patch.Tangents[2] = pi.Patch.Tangents[3];
01713                         pi.Patch.Tangents[3] = tmp;
01714                         tmp = pi.Patch.Tangents[6];
01715                         pi.Patch.Tangents[6] = pi.Patch.Tangents[7];
01716                         pi.Patch.Tangents[7] = tmp;
01717 
01718                         // Interior
01719                         tmp = pi.Patch.Interiors[0];
01720                         pi.Patch.Interiors[0] = pi.Patch.Interiors[3];
01721                         pi.Patch.Interiors[3] = tmp;
01722                         tmp = pi.Patch.Interiors[1];
01723                         pi.Patch.Interiors[1] = pi.Patch.Interiors[2];
01724                         pi.Patch.Interiors[2] = tmp;
01725 
01726                         // ** Symmetries tile colors
01727 
01728                         uint u,v;
01729                         uint countU = pi.OrderS/2+1;
01730                         uint countV = pi.OrderT+1;
01731                         for (v=0; v<countV; v++)
01732                         for (u=0; u<countU; u++)
01733                         {
01734                                 // Store it in the tile info
01735                                 uint index0 = u+v*(pi.OrderS+1);
01736                                 uint index1 = (pi.OrderS-u)+v*(pi.OrderS+1);
01737 
01738                                 // XChg
01739                                 uint16 tmp = pi.TileColors[index0].Color565;
01740                                 pi.TileColors[index0].Color565 = pi.TileColors[index1].Color565;
01741                                 pi.TileColors[index1].Color565 = tmp;
01742                         }
01743 
01744                         // Smooth flags
01745                         uint backupFlag = pi.Flags;
01746                         for (int edge=0; edge<4; edge+=2)
01747                         {
01748                                 // Clear smooth flags
01749                                 pi.Flags &= (1<<edge);
01750 
01751                                 // Symmetry edge
01752                                 uint symEdge = ((edge+2)&3);
01753 
01754                                 // Copy the flag
01755                                 pi.Flags |= (((backupFlag>>symEdge)&1)<<edge);
01756                         }
01757                 }
01758 
01759                 // --- Symmetry of the bind info.
01760                 // --- Parse each patch and each edge
01761                 // For each patches
01762                 for (i=0 ; i<patchCount; i++)
01763                 {
01764                         // Ref on the patch info
01765                         CPatchInfo &pi = patchInfo[i];
01766 
01767                         // Xchg left and right
01768                         swap (pi.BindEdges[0], pi.BindEdges[2]);
01769                         swap (pi.BaseVertices[0], pi.BaseVertices[3]);
01770                         swap (pi.BaseVertices[1], pi.BaseVertices[2]);
01771 
01772                         // Flip edges
01773                         for (uint edge=0; edge<4; edge++)
01774                         {
01775                                 // Ref on the patch info
01776                                 CPatchInfo::CBindInfo &bindEdge = pi.BindEdges[edge];
01777 
01778                                 uint next;
01779                                 // Look if it is a bind ?
01780                                 if ( (bindEdge.NPatchs>1) && (bindEdge.NPatchs!=5) )
01781                                 {
01782                                         for (next=0; next<(uint)bindEdge.NPatchs/2; next++)
01783                                         {
01784                                                 swap (bindEdge.Next[bindEdge.NPatchs - next - 1], bindEdge.Next[next]);
01785                                                 swap (bindEdge.Edge[bindEdge.NPatchs - next - 1], bindEdge.Edge[next]);
01786                                         }
01787                                 }
01788 
01789                                 // Look if we are binded on a reversed edge
01790                                 uint bindCount = (bindEdge.NPatchs==5) ? 1 : bindEdge.NPatchs;
01791                                 for (next=0; next<bindCount; next++)
01792                                 {
01793                                         // Left or right ?
01794                                         if ( (bindEdge.Edge[next] & 1) == 0)
01795                                         {
01796                                                 // Invert
01797                                                 bindEdge.Edge[next] += 2;
01798                                                 bindEdge.Edge[next] &= 3;
01799                                         }
01800                                 }
01801                         }
01802                 }
01803         }
01804 
01805         // For each patches
01806         for (i=0 ; i<patchCount; i++)
01807         {
01808                 // Tile infos
01809                 CPatchInfo &pi = patchInfo[i];
01810 
01811                 // Backup tiles
01812                 std::vector<CTileElement>       tiles = pi.Tiles;
01813 
01814                 int u,v;
01815                 for (v=0; v<pi.OrderT; v++)
01816                 for (u=0; u<pi.OrderS; u++)
01817                 {
01818                         // U tile
01819                         int uSymmetry = symmetry ? (pi.OrderS-u-1) : u;
01820 
01821                         // Destination tile
01822                         CTileElement &element = pi.Tiles[u+v*pi.OrderS];
01823 
01824                         // Copy the orginal symmetrical element
01825                         element = tiles[uSymmetry+v*pi.OrderS];
01826 
01827                         // For each layer
01828                         for (int l=0; l<3; l++)
01829                         {
01830                                 // Empty ?
01831                                 if (element.Tile[l] != 0xffff)
01832                                 {
01833                                         // Get the tile index
01834                                         uint tile = element.Tile[l];
01835                                         uint tileRotation = element.getTileOrient (l);
01836 
01837                                         // Get rot and symmetry for this tile
01838                                         uint tileRotate = rotate;
01839                                         bool tileSymmetry = symmetry;
01840                                         bool goofy = symmetry && (zoneSymmetry.getTileState (i, uSymmetry+v*pi.OrderS, l) == CZoneSymmetrisation::Goofy);
01841 
01842                                         // Transform the transfo
01843                                         if (getTileSymmetryRotate (bank, tile, tileSymmetry, tileRotate))
01844                                         {
01845                                                 // Transform the tile
01846                                                 if (!transformTile (bank, tile, tileRotation, tileSymmetry, (4-tileRotate)&3, goofy))
01847                                                 {
01848                                                         // Info
01849                                                         nlwarning ("Error getting symmetrical / rotated zone tile.");
01850                                                         return false;
01851                                                 }
01852                                         }
01853                                         else
01854                                         {
01855                                                 // Info
01856                                                 nlwarning ("Error getting symmetrical / rotated zone tile.");
01857                                                 return false;
01858                                         }
01859 
01860                                         // Set the tile
01861                                         element.Tile[l] = tile;
01862                                         element.setTileOrient (l, (uint8)tileRotation);
01863                                 }
01864                         }
01865 
01866                         // Empty ?
01867                         if (element.Tile[0]!=0xffff)
01868                         {
01869                                 // Get 256 info
01870                                 bool is256x256;
01871                                 uint8 uvOff;
01872                                 element.getTile256Info (is256x256, uvOff);
01873 
01874                                 // 256 ?
01875                                 if (is256x256)
01876                                 {
01877                                         // Get rot and symmetry for this tile
01878                                         uint tileRotate = rotate;
01879                                         bool tileSymmetry = symmetry;
01880                                         uint tileRotation = tiles[uSymmetry+v*pi.OrderS].getTileOrient (0);
01881                                         bool goofy = symmetry && (zoneSymmetry.getTileState (i, uSymmetry+v*pi.OrderS, 0) == CZoneSymmetrisation::Goofy);
01882 
01883                                         // Transform the transfo
01884                                         getTileSymmetryRotate (bank, element.Tile[0], tileSymmetry, tileRotate);
01885 
01886                                         // Transform the case
01887                                         transform256Case (bank, uvOff, tileRotation, tileSymmetry, (4-tileRotate)&3, goofy);
01888 
01889                                         element.setTile256Info (true, uvOff);
01890                                 }
01891                         }
01892                 }
01893         }
01894 
01895         // Ok
01896         return true;
01897 }
01898 
01899 // ***************************************************************************
01900 
01901 } // NL3D