zone_symmetrisation.cpp

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

Generated on Thu Jan 7 08:26:32 2010 for NeL by  doxygen 1.6.1