00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00047
00048
00049
00050
00051
00052
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
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
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
00189 errorDesc.Errors.clear ();
00190
00191
00192
00193
00194 _TilesLayerStates.resize (patchInfo.size ());
00195
00196
00197 uint i;
00198 for (i=0; i<patchInfo.size (); i++)
00199 {
00200
00201 const CPatchInfo &patch = patchInfo[i];
00202 _TilesLayerStates[i].resize (0);
00203 _TilesLayerStates[i].resize (patch.OrderS * patch.OrderT, 0);
00204 }
00205
00206
00207 for (i=0; i<patchInfo.size (); i++)
00208 {
00209
00210 const CPatchInfo &patch = patchInfo[i];
00211
00212
00213 TState patchState;
00214 if (!setTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00215 {
00216
00217 errorDesc.Errors.push_back ("Patch n°"+toString (i)+" is invalid");
00218 }
00219
00220
00221 if (!setOrientedTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00222 {
00223
00224 errorDesc.Errors.push_back ("Patch n°"+toString (i)+" is invalid");
00225 }
00226 }
00227
00228
00229
00230
00231 for (i=0; i<patchInfo.size (); i++)
00232 {
00233
00234 const CPatchInfo &patch = patchInfo[i];
00235
00236
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
00245 errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00246 return false;
00247 }
00248 }
00249 }
00250 }
00251
00252
00253 for (i=0; i<patchInfo.size (); i++)
00254 {
00255
00256 const CPatchInfo &patch = patchInfo[i];
00257
00258
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
00267 errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00268 return false;
00269 }
00270 }
00271 }
00272 }
00273
00274
00275 return errorDesc.Errors.size () == 0;
00276 }
00277
00278
00279
00280 bool CZoneSymmetrisation::snapOnGrid (float& value, float resolution, float snap)
00281 {
00282
00283 float _floor = (float) ( resolution * floor (value / resolution) );
00284 nlassert (_floor<=value);
00285
00286
00287 float remainder = value - _floor;
00288
00289
00290
00291 if ( remainder <= snap )
00292 {
00293
00294 value = _floor;
00295
00296
00297 return true;
00298 }
00299 else if ( (resolution - remainder) <= snap )
00300 {
00301
00302 value = _floor + resolution;
00303
00304
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
00315 TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00316
00317
00318 sint32 vertPosU[4];
00319 sint32 vertPosV[4];
00320
00321
00322 uint i;
00323 for (i=0; i<4; i++)
00324 {
00325
00326 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00327 float valueU = original.x;
00328 float valueV = original.y;
00329
00330
00331 if (snapOnGrid (valueU, snapCell, weldThreshold))
00332 vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00333 else
00334 vertPosU[i] = 0x80000000;
00335
00336
00337 if (snapOnGrid (valueV, snapCell, weldThreshold))
00338 vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00339 else
00340 vertPosV[i] = 0x80000000;
00341 }
00342
00343
00344 bool regular = false;
00345 bool goofy = false;
00346 bool EdgeSnaped[4] = { false, false, false, false };
00347
00348
00349 for (i=0; i<4; i++)
00350 {
00351
00352 if ( (vertPosU[i] != 0x80000000) || (vertPosV[i] != 0x80000000) )
00353 {
00354
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
00359 if (snapU || snapV)
00360 {
00361
00362 if (snapU && snapV)
00363 return false;
00364
00365
00366 if (snapU)
00367 edgesState[i] = (i&1)?Goofy:Regular;
00368 else
00369 edgesState[i] = (i&1)?Regular:Goofy;
00370
00371
00372 if (edgesState[i] == Regular)
00373 regular = true;
00374 else
00375 goofy = true;
00376
00377
00378 EdgeSnaped[i] = true;
00379 }
00380 }
00381 }
00382
00383
00384 if (goofy && regular)
00385 return false;
00386
00387
00388 if ((!goofy) && (!regular))
00389 state = Nothing;
00390 else
00391 {
00392
00393 state = regular?Regular:Goofy;
00394
00395
00396
00397
00398 for (i=0; i<4; i++)
00399 {
00400
00401 if (EdgeSnaped[i])
00402 {
00403
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
00430 setTileBorderState (patchId, currentTile, state);
00431
00432
00433 uint layer;
00434 for (layer=0; layer<3; layer++)
00435 {
00436
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
00446 if (!bank.getTileSet (tileSet)->getOriented ())
00447 {
00448
00449 setTileState (patchId, currentTile, layer, state);
00450 }
00451 }
00452 }
00453
00454
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
00469 TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00470
00471
00472 sint32 vertPosU[4];
00473 sint32 vertPosV[4];
00474
00475
00476 uint i;
00477 for (i=0; i<4; i++)
00478 {
00479
00480 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00481 float valueU = original.x;
00482 float valueV = original.y;
00483
00484
00485 if (snapOnGrid (valueU, snapCell, weldThreshold))
00486 vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00487 else
00488 vertPosU[i] = 0x80000000;
00489
00490
00491 if (snapOnGrid (valueV, snapCell, weldThreshold))
00492 vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00493 else
00494 vertPosV[i] = 0x80000000;
00495 }
00496
00497
00498 bool regular = false;
00499 bool goofy = false;
00500 bool EdgeSnaped[4] = { false, false, false, false };
00501
00502
00503 for (i=0; i<4; i++)
00504 {
00505
00506 if ( (vertPosU[i] != 0x80000000) || (vertPosV[i] != 0x80000000) )
00507 {
00508
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
00513 if (snapU || snapV)
00514 {
00515
00516 if (snapU && snapV)
00517 return false;
00518
00519
00520 edgesState[i] = (i&1)?Goofy:Regular;
00521
00522
00523 if (edgesState[i] == Regular)
00524 regular = true;
00525 else
00526 goofy = true;
00527
00528
00529 EdgeSnaped[i] = true;
00530 }
00531 }
00532 }
00533
00534
00535
00536
00537 for (i=0; i<4; i++)
00538 {
00539
00540 if (EdgeSnaped[i])
00541 {
00542
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
00569 setOrientedTileBorderState (patchId, currentTile, edgesState[i]);
00570
00571
00572 uint layer;
00573 for (layer=0; layer<3; layer++)
00574 {
00575
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
00585 if (bank.getTileSet (tileSet)->getOriented ())
00586 {
00587 setTileState (patchId, currentTile, layer, edgesState[i]);
00588 }
00589 }
00590 }
00591
00592
00593 currentTile += delta;
00594 }
00595 }
00596 }
00597
00598
00599 for (i=0; i<4; i++)
00600 {
00601
00602 uint next = (i+1)&3;
00603 if (EdgeSnaped[i] && EdgeSnaped[next])
00604 {
00605
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
00661 uint layer;
00662 for (layer=0; layer<3; layer++)
00663 {
00664
00665 const CPatchInfo *currentPatchPtr = &(patchInfo[patch]);
00666
00667
00668 uint tile = s+t*currentPatchPtr->OrderS;
00669
00670
00671 uint tileIndex = currentPatchPtr->Tiles[tile].Tile[layer];
00672 if (tileIndex != NL_TILE_ELM_LAYER_EMPTY)
00673 {
00674
00675 if (tileIndex >= (uint)bank.getTileCount ())
00676 {
00677 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00678 return false;
00679 }
00680
00681
00682 int tileSetToPropagate;
00683 int number;
00684 CTileBank::TTileType type;
00685 bank.getTileXRef (tileIndex, tileSetToPropagate, number, type);
00686
00687
00688 bool oriented = bank.getTileSet (tileSetToPropagate)->getOriented ();
00689
00690
00691 if (!(oriented && getOrientedTileCorner (patch, tile)))
00692 {
00693
00694 CFillStackNode currentNode (patch, s, t, currentPatchPtr->Tiles[tile].getTileOrient(layer), getTileState (patch, tile, layer));
00695
00696
00697 if ( (!forceRegular && (currentNode.State != Nothing)) || (forceRegular && (currentNode.State == Nothing)) )
00698 {
00699
00700 if (forceRegular)
00701 {
00702 setTileState (patch, tile, layer, Regular);
00703 currentNode.State = Regular;
00704 }
00705
00706
00707 vector<CFillStackNode> stack;
00708 stack.push_back (currentNode);
00709
00710
00711 while (!stack.empty ())
00712 {
00713
00714 currentNode = stack.back ();
00715 stack.pop_back ();
00716
00717 do
00718 {
00719
00720 currentPatchPtr = &(patchInfo[currentNode.Patch]);
00721
00722
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
00741 if ( (neighborNode.S<0) || (neighborNode.S>=patchInfo[currentNode.Patch].OrderS) || (neighborNode.T<0) || (neighborNode.T>=patchInfo[currentNode.Patch].OrderT) )
00742 {
00743
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
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
00769 nlassert (patchOut != currentNode.Patch);
00770
00771
00772 neighborNode.Patch = patchOut;
00773
00774
00775 nlassert (sOut >= 0);
00776 nlassert (tOut >= 0);
00777 nlassert (sOut < patchInfo[neighborNode.Patch].OrderS);
00778 nlassert (tOut < patchInfo[neighborNode.Patch].OrderT);
00779
00780
00781 neighborNode.S = sOut;
00782 neighborNode.T = tOut;
00783
00784
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
00794 nlassert (edgePatch<(uint)neighborBindInfo.NPatchs);
00795
00796
00797 neighborNode.Rotate = (currentNode.Rotate + 2 + neighborBindInfo.Edge[edgePatch] - currentNode.Edge) & 3;
00798
00799
00800 if ((neighborNode.Rotate ^ currentNode.Rotate) & 1)
00801 {
00802
00803 neighborNode.State = (neighborNode.State == Regular) ? Goofy : Regular;
00804 }
00805 }
00806 else
00807 {
00808
00809 currentNode.Edge++;
00810 continue;
00811 }
00812 }
00813
00814
00815 const CPatchInfo *neighborPatchPtr = &(patchInfo[neighborNode.Patch]);
00816
00817
00818 uint neighborTile = neighborNode.S+neighborNode.T*neighborPatchPtr->OrderS;
00819
00820
00821 uint neighborLayer;
00822 for (neighborLayer=0; neighborLayer<3; neighborLayer++)
00823 {
00824
00825 uint neighborTileIndex = neighborPatchPtr->Tiles[neighborTile].Tile[neighborLayer];
00826
00827 if (neighborTileIndex != NL_TILE_ELM_LAYER_EMPTY)
00828 {
00829
00830 if (neighborTileIndex >= (uint)bank.getTileCount ())
00831 {
00832 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00833 return false;
00834 }
00835
00836
00837 int neighborTileSet;
00838 int neighborNumber;
00839 CTileBank::TTileType neighborType;
00840 bank.getTileXRef (neighborTileIndex, neighborTileSet, neighborNumber, neighborType);
00841
00842
00843 if ( (neighborTileSet == tileSetToPropagate) &&
00844 (neighborNode.Rotate == neighborPatchPtr->Tiles[neighborTile].getTileOrient(neighborLayer)) )
00845 break;
00846 }
00847 }
00848
00849
00850 if (neighborLayer<3)
00851 {
00852
00853 if (!(oriented && getOrientedTileCorner (neighborNode.Patch, neighborTile)))
00854 {
00855
00856 TState neighborState = getTileState (neighborNode.Patch, neighborTile, neighborLayer);
00857 if (neighborState == Nothing)
00858 {
00859
00860 setTileState (neighborNode.Patch, neighborTile, neighborLayer, neighborNode.State);
00861
00862
00863 if (currentNode.Edge < 3)
00864 {
00865 currentNode.Edge++;
00866 stack.push_back (currentNode);
00867 }
00868
00869
00870 currentNode = neighborNode;
00871 }
00872 else if (neighborState != neighborNode.State)
00873 {
00874
00875 nlwarning ("CZoneSymmetrisation::propagateTileState: error, find same iso surfaces with different state.");
00876
00877
00878 currentNode.Edge++;
00879 }
00880 else
00881 {
00882
00883 currentNode.Edge++;
00884 }
00885 }
00886 else
00887 {
00888
00889 currentNode.Edge++;
00890 }
00891 }
00892 else
00893
00894 currentNode.Edge++;
00895 }
00896 while (currentNode.Edge<4);
00897 }
00898 }
00899 }
00900 }
00901 }
00902
00903 return true;
00904 }
00905
00906
00907
00908 }