# 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_symmetrisation.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 #include "3d/zone_symmetrisation.h"
00028 #include "3d/zone.h"
00029 #include "3d/tile_bank.h"
00030 
00031 using namespace std;
00032 using namespace NLMISC;
00033 
00034 namespace NL3D 
00035 {
00036 
00037 // ***************************************************************************
00038 
00039 CZoneSymmetrisation::CZoneSymmetrisation()
00040 {
00041 }
00042 
00043 // ***************************************************************************
00044 
00045 /*
00046 Bit field
00047         1-0 : state layer 0
00048         3-2 : state layer 1
00049         5-4 : state layer 2
00050         7-6 : border state
00051         9-8 : oriented border state
00052         10  : corner flag
00053 */
00054 
00055 // ***************************************************************************
00056 
00057 CZoneSymmetrisation::TState CZoneSymmetrisation::getTileState (uint patch, uint tile, uint layer) const
00058 {
00059         nlassert (layer<5);
00060         return (TState)((_TilesLayerStates[patch][tile]>>(layer*2))&0x3);
00061 }
00062 
00063 // ***************************************************************************
00064 
00065 CZoneSymmetrisation::TState CZoneSymmetrisation::getTileBorderState (uint patch, uint tile) const
00066 {
00067         return getTileState (patch, tile, 3);
00068 }
00069 
00070 // ***************************************************************************
00071 
00072 CZoneSymmetrisation::TState CZoneSymmetrisation::getOrientedTileBorderState (uint patch, uint tile) const
00073 {
00074         return getTileState (patch, tile, 4);
00075 }
00076 
00077 // ***************************************************************************
00078 
00079 bool CZoneSymmetrisation::getOrientedTileCorner (uint patch, uint tile)
00080 {
00081         return ( ( _TilesLayerStates[patch][tile] >> 10 ) & 1 ) != 0;
00082 }
00083 
00084 // ***************************************************************************
00085 
00086 void CZoneSymmetrisation::setTileState (uint patch, uint tile, uint layer, TState state)
00087 {
00088         uint16 &ref = _TilesLayerStates[patch][tile];
00089         ref &= ~(3<<(layer*2));
00090         ref |= ((uint16)state)<<(layer*2);
00091 }
00092 
00093 // ***************************************************************************
00094 
00095 void CZoneSymmetrisation::setTileBorderState (uint patch, uint tile, TState state)
00096 {
00097         setTileState (patch, tile, 3, state);
00098 }
00099 
00100 // ***************************************************************************
00101 
00102 void CZoneSymmetrisation::setOrientedTileBorderState (uint patch, uint tile, TState state)
00103 {
00104         setTileState (patch, tile, 4, state);
00105 }
00106 
00107 // ***************************************************************************
00108 
00109 void CZoneSymmetrisation::setOrientedTileCorner (uint patch, uint tile, bool corner)
00110 {
00111         uint16 &ref = _TilesLayerStates[patch][tile];
00112         ref &= ~(1<<10);
00113         ref |= ((uint16)corner)<<(10);
00114 }
00115 
00116 // ***************************************************************************
00117 
00118 /*
00119 
00120 REMARKS:
00121 - I call "isotile" the set of connected tiles in the zone using the same tileset and a continus rotation value.
00122 
00123 This method determines the state of each tile in the zone. This state will be used to transform
00124 the tile during symmetrisation of the zone.
00125 
00126 The state can be Regular, Goofy or Nothing.
00127 
00128 If the state is Nothing, this tile is in an "isotile" that is not connected to a zone border. No matter the method
00129 you use to tranform it, it will not influence the neighbor zones.
00130 
00131 If the state is Regular, the rotation of this tile after symmetrisation will by given by this formula : tilerot = (4-tilerot)&3
00132 If the state is Goofy, the rotation of this tile after symmetrisation will by given by this formula : tilerot = (4-tilerot+2)&3
00133 
00134 - Getting the state of the tile:
00135         - A) We flag all the zone patches as Nothing.
00136         - B) We need to select patches having an open edge on the zone border. To do so, we use the snapCell and weldThreshold
00137         parameters.
00138         - C) Then, for each patches on the zone border, we need to know if they are Goofy or Regular.
00139 
00140                 Y
00141   
00142                 /\
00143                 | 
00144                 |  0     3
00145                 |   *****
00146                 |   *   *   This patch is regular
00147                 |   *   *
00148                 |   *****
00149                 |  1     2
00150                 | 
00151                 |  2     1
00152                 |   *****
00153                 |   *   *   This patch is regular
00154                 |   *   *
00155                 |   *****
00156                 |  3     0
00157                 | 
00158                 |  3     2
00159                 |   *****
00160                 |   *   *   This patch is goofy
00161                 |   *   *
00162                 |   *****
00163                 |  0     1
00164                 | 
00165                 |  1     4
00166                 |   *****
00167                 |   *   *   This patch is goofy
00168                 |   *   *
00169                 |   *****
00170                 |  2     3
00171                 -----------------------------------------> X
00172 
00173         - D) We flag each tiles as Nothing
00174         - E) We flag each tile on an opened edge using this formula:
00175                 - If the patch is not Nothing do
00176                         - tileIsGoofy = (patchIsGoofy) XOR ((tileRotation&1) != 0)
00177         - F) Then, we propagate the tile A flag across the tiles in the zone following this rules:
00178                 - If A is not Nothing do
00179                         - For each neighbor B of A do
00180                                 - If B is different from A do
00181                                         - If A is Regular (res Goofy), and B is Nothing, B will be Regular (res Goofy)
00182                                         - If A is Regular (res Goofy), and B is Goofy (res Regular), -> Error
00183                                         - Propagate B
00184 */
00185 
00186 bool CZoneSymmetrisation::build (const std::vector<CPatchInfo> &patchInfo, float snapCell, float weldThreshold, const CTileBank &bank, CError &errorDesc, const NLMISC::CMatrix &toOriginalSpace)
00187 {
00188         // * Clear errors
00189         errorDesc.Errors.clear ();
00190 
00191         // * Build the patches state
00192         
00193         // A) Resize arrays
00194         _TilesLayerStates.resize (patchInfo.size ());
00195 
00196         // D) Resize the tile array
00197         uint i;
00198         for (i=0; i<patchInfo.size (); i++)
00199         {
00200                 // Ref on the patch
00201                 const CPatchInfo &patch = patchInfo[i];
00202                 _TilesLayerStates[i].resize (0);
00203                 _TilesLayerStates[i].resize (patch.OrderS * patch.OrderT, 0);
00204         }
00205 
00206         // B), C) and E) We need to select patches having an open edge on the zone border. To do so, we use the snapCell and weldThreshold parameters
00207         for (i=0; i<patchInfo.size (); i++)
00208         {
00209                 // Ref on the patch
00210                 const CPatchInfo &patch = patchInfo[i];
00211 
00212                 // Does this patch is over a border ?
00213                 TState patchState;
00214                 if (!setTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00215                 {
00216                         // Push an error
00217                         errorDesc.Errors.push_back ("Patch n°"+toString (i)+" is invalid");
00218                 }
00219 
00220                 // Set the oriented patch state
00221                 if (!setOrientedTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00222                 {
00223                         // Push an error
00224                         errorDesc.Errors.push_back ("Patch n°"+toString (i)+" is invalid");
00225                 }
00226         }
00227 
00228         // F) We flag each tile on an opened edge using this formula
00229         //      - If the patch is not Nothing do
00230         //              - tileIsGoofy = (patchIsGoofy) XOR ((tileRotation&1) != 0)
00231         for (i=0; i<patchInfo.size (); i++)
00232         {
00233                 // Ref on the patch
00234                 const CPatchInfo &patch = patchInfo[i];
00235 
00236                 // For each tile
00237                 uint s,t;
00238                 for (t=0; t<patch.OrderT; t++)
00239                 {
00240                         for (s=0; s<patch.OrderS; s++)
00241                         {
00242                                 if (!propagateTileState (i, s, t, patchInfo, bank, false))
00243                                 {
00244                                         // Push an error
00245                                         errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00246                                         return false;
00247                                 }
00248                         }
00249                 }
00250         }
00251 
00252         // G) Force all remaining Nothing tiles to Regular
00253         for (i=0; i<patchInfo.size (); i++)
00254         {
00255                 // Ref on the patch
00256                 const CPatchInfo &patch = patchInfo[i];
00257 
00258                 // For each tile
00259                 uint s,t;
00260                 for (t=0; t<patch.OrderT; t++)
00261                 {
00262                         for (s=0; s<patch.OrderS; s++)
00263                         {
00264                                 if (!propagateTileState (i, s, t, patchInfo, bank, true))
00265                                 {
00266                                         // Push an error
00267                                         errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00268                                         return false;
00269                                 }
00270                         }
00271                 }
00272         }
00273 
00274         // Returns true if no error
00275         return errorDesc.Errors.size () == 0;
00276 }
00277 
00278 // ***************************************************************************
00279 
00280 bool CZoneSymmetrisation::snapOnGrid (float& value, float resolution, float snap)
00281 {
00282         // Calc the floor
00283         float _floor = (float) ( resolution * floor (value / resolution) );
00284         nlassert (_floor<=value);
00285 
00286         // Calc the remainder
00287         float remainder = value - _floor;
00288         //nlassert ( (remainder>=0) && (remainder<resolution) );
00289 
00290         // Check the snape
00291         if ( remainder <= snap )
00292         {
00293                 // Flag it
00294                 value = _floor;
00295 
00296                 // Floor is good
00297                 return true;
00298         }
00299         else if ( (resolution - remainder) <= snap )
00300         {
00301                 // Flag it
00302                 value = _floor + resolution;
00303 
00304                 // Floor + resolution is good
00305                 return true;
00306         }
00307         return false;
00308 }
00309 
00310 // ***************************************************************************
00311 
00312 bool CZoneSymmetrisation::setTileState (const NL3D::CPatchInfo &patch, uint patchId, float snapCell, float weldThreshold, TState &state, const NLMISC::CMatrix &toOriginalSpace, const CTileBank &bank)
00313 {
00314         // Edges state
00315         TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00316 
00317         // Vertices position
00318         sint32 vertPosU[4];
00319         sint32 vertPosV[4];
00320         
00321         // For each vertices
00322         uint i;
00323         for (i=0; i<4; i++)
00324         {
00325                 // Snap the vertex
00326                 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00327                 float valueU = original.x;
00328                 float valueV = original.y;
00329 
00330                 // Snap on U
00331                 if (snapOnGrid (valueU, snapCell, weldThreshold))
00332                         vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00333                 else
00334                         vertPosU[i] = 0x80000000;
00335 
00336                 // Snap on V
00337                 if (snapOnGrid (valueV, snapCell, weldThreshold))
00338                         vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00339                 else
00340                         vertPosV[i] = 0x80000000;
00341         }
00342 
00343         // Patch flags
00344         bool regular = false;
00345         bool goofy = false;
00346         bool EdgeSnaped[4] = { false, false, false, false };
00347 
00348         // For each edges
00349         for (i=0; i<4; i++)
00350         {
00351                 // Vertex snapped and align on a common axis ?
00352                 if ( (vertPosU[i] != 0x80000000) || (vertPosV[i] != 0x80000000) )
00353                 {
00354                         // Snapped on U or V ?
00355                         bool snapU = (vertPosU[i] == vertPosU[(i+1)&3]) && (vertPosU[i] != 0x80000000);
00356                         bool snapV = (vertPosV[i] == vertPosV[(i+1)&3]) && (vertPosV[i] != 0x80000000);
00357                         
00358                         // If snapped on one, continue
00359                         if (snapU || snapV)
00360                         {
00361                                 // If snap on the both, error
00362                                 if (snapU && snapV)
00363                                         return false;
00364 
00365                                 // Is this edge Regular or Goofy ?
00366                                 if (snapU)
00367                                         edgesState[i] = (i&1)?Goofy:Regular;
00368                                 else // (snapV)
00369                                         edgesState[i] = (i&1)?Regular:Goofy;
00370 
00371                                 // Flag the patch
00372                                 if (edgesState[i] == Regular)
00373                                         regular = true;
00374                                 else
00375                                         goofy = true;
00376 
00377                                 // Edge snaped
00378                                 EdgeSnaped[i] = true;
00379                         }
00380                 }
00381         }
00382 
00383         // Goofy and regular ? Error
00384         if (goofy && regular)
00385                 return false;
00386 
00387         // Nothing ?
00388         if ((!goofy) && (!regular))
00389                 state = Nothing;
00390         else
00391         {
00392                 // Not nothing ?
00393                 state = regular?Regular:Goofy;
00394 
00395                 // * Set the tiles
00396 
00397                 // For each edges
00398                 for (i=0; i<4; i++)
00399                 {
00400                         // Edge snapped ?
00401                         if (EdgeSnaped[i])
00402                         {
00403                                 // For each tiles
00404                                 uint tileCount = ((i&1)!=0)?patch.OrderS:patch.OrderT;
00405                                 sint currentTile;
00406                                 sint delta;
00407                                 switch (i)
00408                                 {
00409                                 case 0:
00410                                         currentTile = 0;
00411                                         delta = patch.OrderS;
00412                                         break;
00413                                 case 1:
00414                                         currentTile = patch.OrderS*(patch.OrderT-1);
00415                                         delta = 1;
00416                                         break;
00417                                 case 2:
00418                                         currentTile = patch.OrderS-1;
00419                                         delta = patch.OrderS;
00420                                         break;
00421                                 case 3:
00422                                         currentTile = 0;
00423                                         delta = 1;
00424                                         break;
00425                                 }
00426                                 uint j;
00427                                 for (j=0; j<tileCount; j++)
00428                                 {
00429                                         // Set the border state
00430                                         setTileBorderState (patchId, currentTile, state);
00431 
00432                                         // For each layer
00433                                         uint layer;
00434                                         for (layer=0; layer<3; layer++)
00435                                         {
00436                                                 // Get the tiles set used here
00437                                                 uint tile = patch.Tiles[currentTile].Tile[layer];
00438                                                 if (tile != NL_TILE_ELM_LAYER_EMPTY)
00439                                                 {
00440                                                         int tileSet;
00441                                                         int number;
00442                                                         CTileBank::TTileType type;
00443                                                         bank.getTileXRef (tile, tileSet, number, type);
00444 
00445                                                         // Set it only if not oriented
00446                                                         if (!bank.getTileSet (tileSet)->getOriented ())
00447                                                         {
00448                                                                 // Set the tile state
00449                                                                 setTileState (patchId, currentTile, layer, state);
00450                                                         }
00451                                                 }
00452                                         }
00453 
00454                                         // Next tile
00455                                         currentTile += delta;
00456                                 }
00457                         }
00458                 }
00459         }
00460 
00461         return true;
00462 }
00463 
00464 // ***************************************************************************
00465 
00466 bool CZoneSymmetrisation::setOrientedTileState (const NL3D::CPatchInfo &patch, uint patchId, float snapCell, float weldThreshold, TState &state, const NLMISC::CMatrix &toOriginalSpace, const CTileBank &bank)
00467 {
00468         // Edges state
00469         TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00470 
00471         // Vertices position
00472         sint32 vertPosU[4];
00473         sint32 vertPosV[4];
00474         
00475         // For each vertices
00476         uint i;
00477         for (i=0; i<4; i++)
00478         {
00479                 // Snap the vertex
00480                 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00481                 float valueU = original.x;
00482                 float valueV = original.y;
00483 
00484                 // Snap on U
00485                 if (snapOnGrid (valueU, snapCell, weldThreshold))
00486                         vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00487                 else
00488                         vertPosU[i] = 0x80000000;
00489 
00490                 // Snap on V
00491                 if (snapOnGrid (valueV, snapCell, weldThreshold))
00492                         vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00493                 else
00494                         vertPosV[i] = 0x80000000;
00495         }
00496 
00497         // Patch flags
00498         bool regular = false;
00499         bool goofy = false;
00500         bool EdgeSnaped[4] = { false, false, false, false };
00501 
00502         // For each edges
00503         for (i=0; i<4; i++)
00504         {
00505                 // Vertex snapped and align on a common axis ?
00506                 if ( (vertPosU[i] != 0x80000000) || (vertPosV[i] != 0x80000000) )
00507                 {
00508                         // Snapped on U or V ?
00509                         bool snapU = (vertPosU[i] == vertPosU[(i+1)&3]) && (vertPosU[i] != 0x80000000);
00510                         bool snapV = (vertPosV[i] == vertPosV[(i+1)&3]) && (vertPosV[i] != 0x80000000);
00511                         
00512                         // If snapped on one, continue
00513                         if (snapU || snapV)
00514                         {
00515                                 // If snap on the both, error
00516                                 if (snapU && snapV)
00517                                         return false;
00518 
00519                                 // Is this edge Regular or Goofy ?
00520                                 edgesState[i] = (i&1)?Goofy:Regular;
00521 
00522                                 // Flag the patch
00523                                 if (edgesState[i] == Regular)
00524                                         regular = true;
00525                                 else
00526                                         goofy = true;
00527 
00528                                 // Edge snaped
00529                                 EdgeSnaped[i] = true;
00530                         }
00531                 }
00532         }
00533 
00534         // * Set the tiles
00535 
00536         // For each edges
00537         for (i=0; i<4; i++)
00538         {
00539                 // Edge snapped ?
00540                 if (EdgeSnaped[i])
00541                 {
00542                         // For each tiles
00543                         uint tileCount = ((i&1)!=0)?patch.OrderS:patch.OrderT;
00544                         sint currentTile;
00545                         sint delta;
00546                         switch (i)
00547                         {
00548                         case 0:
00549                                 currentTile = 0;
00550                                 delta = patch.OrderS;
00551                                 break;
00552                         case 1:
00553                                 currentTile = patch.OrderS*(patch.OrderT-1);
00554                                 delta = 1;
00555                                 break;
00556                         case 2:
00557                                 currentTile = patch.OrderS-1;
00558                                 delta = patch.OrderS;
00559                                 break;
00560                         case 3:
00561                                 currentTile = 0;
00562                                 delta = 1;
00563                                 break;
00564                         }
00565                         uint j;
00566                         for (j=0; j<tileCount; j++)
00567                         {
00568                                 // Set the border state
00569                                 setOrientedTileBorderState (patchId, currentTile, edgesState[i]);
00570 
00571                                 // For each layer
00572                                 uint layer;
00573                                 for (layer=0; layer<3; layer++)
00574                                 {
00575                                         // Get the tiles set used here
00576                                         uint tile = patch.Tiles[currentTile].Tile[layer];
00577                                         if (tile != NL_TILE_ELM_LAYER_EMPTY)
00578                                         {
00579                                                 int tileSet;
00580                                                 int number;
00581                                                 CTileBank::TTileType type;
00582                                                 bank.getTileXRef (tile, tileSet, number, type);
00583 
00584                                                 // Set it only if oriented
00585                                                 if (bank.getTileSet (tileSet)->getOriented ())
00586                                                 {
00587                                                         setTileState (patchId, currentTile, layer, edgesState[i]);
00588                                                 }
00589                                         }
00590                                 }
00591 
00592                                 // Next tile
00593                                 currentTile += delta;
00594                         }
00595                 }
00596         }
00597         
00598         // For each corners
00599         for (i=0; i<4; i++)
00600         {
00601                 // Corner snapped ?
00602                 uint next = (i+1)&3;
00603                 if (EdgeSnaped[i] && EdgeSnaped[next])
00604                 {
00605                         // Flag tile as corner
00606                         switch (i)
00607                         {
00608                         case 0:
00609                                 setOrientedTileCorner (patchId, patch.OrderS*(patch.OrderT-1), true);
00610                                 break;
00611                         case 1:
00612                                 setOrientedTileCorner (patchId, patch.OrderS*patch.OrderT-1, true);
00613                                 break;
00614                         case 2:
00615                                 setOrientedTileCorner (patchId, patch.OrderS-1, true);
00616                                 break;
00617                         case 3:
00618                                 setOrientedTileCorner (patchId, 0, true);
00619                                 break;
00620                         }
00621                 }
00622         }
00623         
00624         return true;
00625 }
00626 
00627 // ***************************************************************************
00628 
00629 CVector2f st2uv (sint s, sint t, const CPatchInfo &patch)
00630 {
00631         return CVector2f ((((float)s)+0.5f)/(float)patch.OrderS, (((float)t)+0.5f)/(float)patch.OrderT);
00632 }
00633 
00634 // ***************************************************************************
00635 
00636 void uv2st (const CVector2f &in, sint &s, sint &t, const CPatchInfo &patch)
00637 {
00638         s = (sint)(in.x*(float)patch.OrderS);
00639         t = (sint)(in.y*(float)patch.OrderT);
00640 }
00641 
00642 // ***************************************************************************
00643 
00644 class CFillStackNode
00645 {
00646 public:
00647         CFillStackNode (uint16 patch, uint16 s, uint16 t, uint8 rotate, CZoneSymmetrisation::TState     state) { Patch = patch; S = s; T = t; Edge = 0; Rotate = rotate; State = state; };
00648         uint16  S;
00649         uint16  T;
00650         uint16  Patch;
00651         uint8   Edge;
00652         uint8   Rotate;
00653         CZoneSymmetrisation::TState     State;
00654 };
00655 
00656 // ***************************************************************************
00657 
00658 bool CZoneSymmetrisation::propagateTileState (uint patch, uint s, uint t, const std::vector<CPatchInfo> &patchInfo, const CTileBank &bank, bool forceRegular)
00659 {
00660         // For each layer
00661         uint layer;
00662         for (layer=0; layer<3; layer++)
00663         {
00664                 // Get the patch ptr
00665                 const CPatchInfo *currentPatchPtr = &(patchInfo[patch]);
00666 
00667                 // Get the tile index
00668                 uint tile = s+t*currentPatchPtr->OrderS;
00669 
00670                 // Get the tiles set used here
00671                 uint tileIndex = currentPatchPtr->Tiles[tile].Tile[layer];
00672                 if (tileIndex != NL_TILE_ELM_LAYER_EMPTY)
00673                 {
00674                         // Valid tile number ?
00675                         if (tileIndex >= (uint)bank.getTileCount ())
00676                         {
00677                                 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00678                                 return false;
00679                         }
00680 
00681                         // Get the tile set used by this layer
00682                         int tileSetToPropagate;
00683                         int number;
00684                         CTileBank::TTileType type;
00685                         bank.getTileXRef (tileIndex, tileSetToPropagate, number, type);
00686 
00687                         // Oriented ?
00688                         bool oriented = bank.getTileSet (tileSetToPropagate)->getOriented ();
00689 
00690                         // If oriented, must not be a corner
00691                         if (!(oriented && getOrientedTileCorner (patch, tile)))
00692                         {
00693                                 // Current node
00694                                 CFillStackNode currentNode (patch, s, t, currentPatchPtr->Tiles[tile].getTileOrient(layer), getTileState (patch, tile, layer));
00695 
00696                                 // Propagate non-Nothing tiles
00697                                 if ( (!forceRegular && (currentNode.State != Nothing)) || (forceRegular && (currentNode.State == Nothing)) )
00698                                 {
00699                                         // Force to Regular ?
00700                                         if (forceRegular)
00701                                         {
00702                                                 setTileState (patch, tile, layer, Regular);
00703                                                 currentNode.State = Regular;
00704                                         }
00705 
00706                                         // Fill stack
00707                                         vector<CFillStackNode>  stack;
00708                                         stack.push_back (currentNode);
00709 
00710                                         // While people in the stack
00711                                         while (!stack.empty ())
00712                                         {               
00713                                                 // Pop last element
00714                                                 currentNode = stack.back ();
00715                                                 stack.pop_back ();
00716 
00717                                                 do
00718                                                 {
00719                                                         // Set current patch pointer
00720                                                         currentPatchPtr = &(patchInfo[currentNode.Patch]);
00721 
00722                                                         // Get neighbor
00723                                                         CFillStackNode neighborNode (currentNode.Patch, currentNode.S, currentNode.T, currentNode.Rotate, currentNode.State);
00724                                                         switch (currentNode.Edge)
00725                                                         {
00726                                                         case 0:
00727                                                                 neighborNode.S--;
00728                                                                 break;
00729                                                         case 1:
00730                                                                 neighborNode.T++;
00731                                                                 break;
00732                                                         case 2:
00733                                                                 neighborNode.S++;
00734                                                                 break;
00735                                                         case 3:
00736                                                                 neighborNode.T--;
00737                                                                 break;
00738                                                         }
00739 
00740                                                         // Is still in patch ?
00741                                                         if ( (neighborNode.S<0) || (neighborNode.S>=patchInfo[currentNode.Patch].OrderS) || (neighborNode.T<0) || (neighborNode.T>=patchInfo[currentNode.Patch].OrderT) )
00742                                                         {
00743                                                                 // No, found new patch
00744                                                                 uint position;
00745                                                                 switch (currentNode.Edge)
00746                                                                 {
00747                                                                 case 0:
00748                                                                         position = neighborNode.T;
00749                                                                         break;
00750                                                                 case 1:
00751                                                                         position = neighborNode.S;
00752                                                                         break;
00753                                                                 case 2:
00754                                                                         position = patchInfo[currentNode.Patch].OrderT - neighborNode.T - 1;
00755                                                                         break;
00756                                                                 case 3:
00757                                                                         position = patchInfo[currentNode.Patch].OrderS - neighborNode.S - 1;
00758                                                                         break;
00759                                                                 }
00760 
00761                                                                 // Get next patch
00762                                                                 uint patchOut;
00763                                                                 sint sOut;
00764                                                                 sint tOut;
00765                                                                 if (patchInfo[currentNode.Patch].getNeighborTile (currentNode.Patch, currentNode.Edge, position, 
00766                                                                         patchOut, sOut, tOut, patchInfo))
00767                                                                 {
00768                                                                         // Should be another patch
00769                                                                         nlassert (patchOut != currentNode.Patch);
00770 
00771                                                                         // Get patch id
00772                                                                         neighborNode.Patch = patchOut;
00773 
00774                                                                         // Coordinate must be IN the patch
00775                                                                         nlassert (sOut >= 0);
00776                                                                         nlassert (tOut >= 0);
00777                                                                         nlassert (sOut < patchInfo[neighborNode.Patch].OrderS);
00778                                                                         nlassert (tOut < patchInfo[neighborNode.Patch].OrderT);
00779 
00780                                                                         // Copy it
00781                                                                         neighborNode.S = sOut;
00782                                                                         neighborNode.T = tOut;
00783 
00784                                                                         // Find neighbor
00785                                                                         const CPatchInfo::CBindInfo &neighborBindInfo = patchInfo[currentNode.Patch].BindEdges[currentNode.Edge];
00786                                                                         uint edgePatch;
00787                                                                         for (edgePatch=0; edgePatch<(uint)neighborBindInfo.NPatchs; edgePatch++)
00788                                                                         {
00789                                                                                 if (neighborBindInfo.Next[edgePatch] == neighborNode.Patch)
00790                                                                                         break;
00791                                                                         }
00792 
00793                                                                         // Must find one patch
00794                                                                         nlassert (edgePatch<(uint)neighborBindInfo.NPatchs);
00795 
00796                                                                         // Rotation
00797                                                                         neighborNode.Rotate = (currentNode.Rotate + 2 + neighborBindInfo.Edge[edgePatch] - currentNode.Edge) & 3;
00798 
00799                                                                         // Toggle the state ?
00800                                                                         if ((neighborNode.Rotate ^ currentNode.Rotate) & 1)
00801                                                                         {
00802                                                                                 // Yes
00803                                                                                 neighborNode.State = (neighborNode.State == Regular) ? Goofy : Regular;
00804                                                                         }
00805                                                                 }
00806                                                                 else
00807                                                                 {
00808                                                                         // No propagation, continue
00809                                                                         currentNode.Edge++;
00810                                                                         continue;
00811                                                                 }
00812                                                         }
00813 
00814                                                         // Neighbor patch
00815                                                         const CPatchInfo *neighborPatchPtr = &(patchInfo[neighborNode.Patch]);
00816 
00817                                                         // Get the tile index
00818                                                         uint neighborTile = neighborNode.S+neighborNode.T*neighborPatchPtr->OrderS;
00819                                                         
00820                                                         // Look for the same tile set in the new tile
00821                                                         uint neighborLayer;
00822                                                         for (neighborLayer=0; neighborLayer<3; neighborLayer++)
00823                                                         {
00824                                                                 // Get the tile index
00825                                                                 uint neighborTileIndex = neighborPatchPtr->Tiles[neighborTile].Tile[neighborLayer];
00826 
00827                                                                 if (neighborTileIndex != NL_TILE_ELM_LAYER_EMPTY)
00828                                                                 {
00829                                                                         // Valid tile number ?
00830                                                                         if (neighborTileIndex >= (uint)bank.getTileCount ())
00831                                                                         {
00832                                                                                 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00833                                                                                 return false;
00834                                                                         }
00835 
00836                                                                         // Get tileset
00837                                                                         int neighborTileSet;
00838                                                                         int neighborNumber;
00839                                                                         CTileBank::TTileType neighborType;
00840                                                                         bank.getTileXRef (neighborTileIndex, neighborTileSet, neighborNumber, neighborType);
00841 
00842                                                                         // Same tileset ? Stop!
00843                                                                         if (    (neighborTileSet == tileSetToPropagate) && 
00844                                                                                         (neighborNode.Rotate == neighborPatchPtr->Tiles[neighborTile].getTileOrient(neighborLayer)) )
00845                                                                                 break;
00846                                                                 }
00847                                                         }
00848 
00849                                                         // Found ?
00850                                                         if (neighborLayer<3)
00851                                                         {
00852                                                                 // If oriented, must not be a corner
00853                                                                 if (!(oriented && getOrientedTileCorner (neighborNode.Patch, neighborTile)))
00854                                                                 {
00855                                                                         // Propagate in the new node ?
00856                                                                         TState neighborState = getTileState (neighborNode.Patch, neighborTile, neighborLayer);
00857                                                                         if (neighborState == Nothing)
00858                                                                         {
00859                                                                                 // Set the state
00860                                                                                 setTileState (neighborNode.Patch, neighborTile, neighborLayer, neighborNode.State);
00861 
00862                                                                                 // Stack current node if some neighbor left to visit
00863                                                                                 if (currentNode.Edge < 3)
00864                                                                                 {
00865                                                                                         currentNode.Edge++;
00866                                                                                         stack.push_back (currentNode);
00867                                                                                 }
00868 
00869                                                                                 // Continue with the new node
00870                                                                                 currentNode = neighborNode;
00871                                                                         }
00872                                                                         else if (neighborState != neighborNode.State)
00873                                                                         {
00874                                                                                 // Error, same tile but not same state
00875                                                                                 nlwarning ("CZoneSymmetrisation::propagateTileState: error, find same iso surfaces with different state.");
00876 
00877                                                                                 // No propagation, continue
00878                                                                                 currentNode.Edge++;
00879                                                                         }
00880                                                                         else
00881                                                                         {
00882                                                                                 // No propagation, continue
00883                                                                                 currentNode.Edge++;
00884                                                                         }
00885                                                                 }
00886                                                                 else
00887                                                                 {
00888                                                                         // No propagation, continue
00889                                                                         currentNode.Edge++;
00890                                                                 }
00891                                                         }
00892                                                         else
00893                                                                 // No propagation, continue
00894                                                                 currentNode.Edge++;
00895                                                 }
00896                                                 while (currentNode.Edge<4);
00897                                         }
00898                                 }
00899                         }
00900                 }
00901         }
00902 
00903         return true;
00904 }
00905 
00906 // ***************************************************************************
00907 
00908 } // NL3D