00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00045
00046
00047
00048
00049
00050
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
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 bool CZoneSymmetrisation::build (const std::vector<CPatchInfo> &patchInfo, float snapCell, float weldThreshold, const CTileBank &bank, CError &errorDesc, const NLMISC::CMatrix &toOriginalSpace)
00185 {
00186
00187 errorDesc.Errors.clear ();
00188
00189
00190
00191
00192 _TilesLayerStates.resize (patchInfo.size ());
00193
00194
00195 uint i;
00196 for (i=0; i<patchInfo.size (); i++)
00197 {
00198
00199 const CPatchInfo &patch = patchInfo[i];
00200 _TilesLayerStates[i].resize (0);
00201 _TilesLayerStates[i].resize (patch.OrderS * patch.OrderT, 0);
00202 }
00203
00204
00205 for (i=0; i<patchInfo.size (); i++)
00206 {
00207
00208 const CPatchInfo &patch = patchInfo[i];
00209
00210
00211 TState patchState;
00212 if (!setTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00213 {
00214
00215 errorDesc.Errors.push_back ("Patch nb "+toString (i)+" is invalid");
00216 }
00217
00218
00219 if (!setOrientedTileState (patch, i, snapCell, weldThreshold, patchState, toOriginalSpace, bank))
00220 {
00221
00222 errorDesc.Errors.push_back ("Patch nb "+toString (i)+" is invalid");
00223 }
00224 }
00225
00226
00227
00228
00229 for (i=0; i<patchInfo.size (); i++)
00230 {
00231
00232 const CPatchInfo &patch = patchInfo[i];
00233
00234
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
00243 errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00244 return false;
00245 }
00246 }
00247 }
00248 }
00249
00250
00251 for (i=0; i<patchInfo.size (); i++)
00252 {
00253
00254 const CPatchInfo &patch = patchInfo[i];
00255
00256
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
00265 errorDesc.Errors.push_back ("Error during propagation. Topology invalid.");
00266 return false;
00267 }
00268 }
00269 }
00270 }
00271
00272
00273 return true;
00274 }
00275
00276
00277
00278 bool CZoneSymmetrisation::snapOnGrid (float& value, float resolution, float snap)
00279 {
00280
00281 float _floor = (float) ( resolution * floor (value / resolution) );
00282 nlassert (_floor<=value);
00283
00284
00285 float remainder = value - _floor;
00286
00287
00288
00289 if ( remainder <= snap )
00290 {
00291
00292 value = _floor;
00293
00294
00295 return true;
00296 }
00297 else if ( (resolution - remainder) <= snap )
00298 {
00299
00300 value = _floor + resolution;
00301
00302
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
00313 TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00314
00315
00316 sint32 vertPosU[4];
00317 sint32 vertPosV[4];
00318
00319
00320 uint i;
00321 for (i=0; i<4; i++)
00322 {
00323
00324 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00325 float valueU = original.x;
00326 float valueV = original.y;
00327
00328
00329 if (snapOnGrid (valueU, snapCell, weldThreshold))
00330 vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00331 else
00332 vertPosU[i] = 0x80000000;
00333
00334
00335 if (snapOnGrid (valueV, snapCell, weldThreshold))
00336 vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00337 else
00338 vertPosV[i] = 0x80000000;
00339 }
00340
00341
00342 bool regular = false;
00343 bool goofy = false;
00344 bool EdgeSnaped[4] = { false, false, false, false };
00345
00346
00347 for (i=0; i<4; i++)
00348 {
00349
00350 if ( ((uint32) vertPosU[i] != 0x80000000) || ((uint32) vertPosV[i] != 0x80000000) )
00351 {
00352
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
00357 if (snapU || snapV)
00358 {
00359
00360 if (snapU && snapV)
00361 return false;
00362
00363
00364 if (snapU)
00365 edgesState[i] = (i&1)?Goofy:Regular;
00366 else
00367 edgesState[i] = (i&1)?Regular:Goofy;
00368
00369
00370 if (edgesState[i] == Regular)
00371 regular = true;
00372 else
00373 goofy = true;
00374
00375
00376 EdgeSnaped[i] = true;
00377 }
00378 }
00379 }
00380
00381
00382 if (goofy && regular)
00383 return false;
00384
00385
00386 if ((!goofy) && (!regular))
00387 state = Nothing;
00388 else
00389 {
00390
00391 state = regular?Regular:Goofy;
00392
00393
00394
00395
00396 for (i=0; i<4; i++)
00397 {
00398
00399 if (EdgeSnaped[i])
00400 {
00401
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
00432 setTileBorderState (patchId, currentTile, state);
00433
00434
00435 uint layer;
00436 for (layer=0; layer<3; layer++)
00437 {
00438
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
00454 if (!bank.getTileSet (tileSet)->getOriented ())
00455 {
00456
00457 setTileState (patchId, currentTile, layer, state);
00458 }
00459 }
00460 }
00461
00462
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
00477 TState edgesState[4] = { Nothing, Nothing, Nothing, Nothing };
00478
00479
00480 sint32 vertPosU[4];
00481 sint32 vertPosV[4];
00482
00483
00484 uint i;
00485 for (i=0; i<4; i++)
00486 {
00487
00488 CVector original = toOriginalSpace * patch.Patch.Vertices[i];
00489 float valueU = original.x;
00490 float valueV = original.y;
00491
00492
00493 if (snapOnGrid (valueU, snapCell, weldThreshold))
00494 vertPosU[i] = (sint32)((valueU+0.5f) / snapCell);
00495 else
00496 vertPosU[i] = 0x80000000;
00497
00498
00499 if (snapOnGrid (valueV, snapCell, weldThreshold))
00500 vertPosV[i] = (sint32)((valueV+0.5f) / snapCell);
00501 else
00502 vertPosV[i] = 0x80000000;
00503 }
00504
00505
00506 bool regular = false;
00507 bool goofy = false;
00508 bool EdgeSnaped[4] = { false, false, false, false };
00509
00510
00511 for (i=0; i<4; i++)
00512 {
00513
00514 if ( ((uint32) vertPosU[i] != 0x80000000) || ((uint32) vertPosV[i] != 0x80000000) )
00515 {
00516
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
00521 if (snapU || snapV)
00522 {
00523
00524 if (snapU && snapV)
00525 return false;
00526
00527
00528 edgesState[i] = (i&1)?Goofy:Regular;
00529
00530
00531 if (edgesState[i] == Regular)
00532 regular = true;
00533 else
00534 goofy = true;
00535
00536
00537 EdgeSnaped[i] = true;
00538 }
00539 }
00540 }
00541
00542
00543
00544
00545 for (i=0; i<4; i++)
00546 {
00547
00548 if (EdgeSnaped[i])
00549 {
00550
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
00581 setOrientedTileBorderState (patchId, currentTile, edgesState[i]);
00582
00583
00584 uint layer;
00585 for (layer=0; layer<3; layer++)
00586 {
00587
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
00603 if (bank.getTileSet (tileSet)->getOriented ())
00604 {
00605 setTileState (patchId, currentTile, layer, edgesState[i]);
00606 }
00607 }
00608 }
00609
00610
00611 currentTile += delta;
00612 }
00613 }
00614 }
00615
00616
00617 for (i=0; i<4; i++)
00618 {
00619
00620 uint next = (i+1)&3;
00621 if (EdgeSnaped[i] && EdgeSnaped[next])
00622 {
00623
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
00679 uint layer;
00680 for (layer=0; layer<3; layer++)
00681 {
00682
00683 const CPatchInfo *currentPatchPtr = &(patchInfo[patch]);
00684
00685
00686 uint tile = s+t*currentPatchPtr->OrderS;
00687
00688
00689 uint tileIndex = currentPatchPtr->Tiles[tile].Tile[layer];
00690 if (tileIndex != NL_TILE_ELM_LAYER_EMPTY)
00691 {
00692
00693 if (tileIndex >= (uint)bank.getTileCount ())
00694 {
00695 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00696 return false;
00697 }
00698
00699
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
00712 bool oriented = bank.getTileSet (tileSetToPropagate)->getOriented ();
00713
00714
00715 if (!(oriented && getOrientedTileCorner (patch, tile)))
00716 {
00717
00718 CFillStackNode currentNode (patch, s, t, currentPatchPtr->Tiles[tile].getTileOrient(layer), getTileState (patch, tile, layer));
00719
00720
00721 if ( (!forceRegular && (currentNode.State != Nothing)) || (forceRegular && (currentNode.State == Nothing)) )
00722 {
00723
00724 if (forceRegular)
00725 {
00726 setTileState (patch, tile, layer, Regular);
00727 currentNode.State = Regular;
00728 }
00729
00730
00731 vector<CFillStackNode> stack;
00732 stack.push_back (currentNode);
00733
00734
00735 while (!stack.empty ())
00736 {
00737
00738 currentNode = stack.back ();
00739 stack.pop_back ();
00740
00741 do
00742 {
00743
00744 currentPatchPtr = &(patchInfo[currentNode.Patch]);
00745
00746
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
00765 if ( (neighborNode.S>=patchInfo[currentNode.Patch].OrderS) || (neighborNode.T>=patchInfo[currentNode.Patch].OrderT) )
00766 {
00767
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
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
00796 nlassert (patchOut != currentNode.Patch);
00797
00798
00799 neighborNode.Patch = patchOut;
00800
00801
00802 nlassert (sOut >= 0);
00803 nlassert (tOut >= 0);
00804 nlassert (sOut < patchInfo[neighborNode.Patch].OrderS);
00805 nlassert (tOut < patchInfo[neighborNode.Patch].OrderT);
00806
00807
00808 neighborNode.S = sOut;
00809 neighborNode.T = tOut;
00810
00811
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
00821 nlassert (edgePatch<(uint)neighborBindInfo.NPatchs);
00822
00823
00824 neighborNode.Rotate = (currentNode.Rotate + 2 + neighborBindInfo.Edge[edgePatch] - currentNode.Edge) & 3;
00825
00826
00827 if ((neighborNode.Rotate ^ currentNode.Rotate) & 1)
00828 {
00829
00830 neighborNode.State = (neighborNode.State == Regular) ? Goofy : Regular;
00831 }
00832 }
00833 else
00834 {
00835
00836 currentNode.Edge++;
00837 continue;
00838 }
00839 }
00840
00841
00842 const CPatchInfo *neighborPatchPtr = &(patchInfo[neighborNode.Patch]);
00843
00844
00845 uint neighborTile = neighborNode.S+neighborNode.T*neighborPatchPtr->OrderS;
00846
00847
00848 uint neighborLayer;
00849 for (neighborLayer=0; neighborLayer<3; neighborLayer++)
00850 {
00851
00852 uint neighborTileIndex = neighborPatchPtr->Tiles[neighborTile].Tile[neighborLayer];
00853
00854 if (neighborTileIndex != NL_TILE_ELM_LAYER_EMPTY)
00855 {
00856
00857 if (neighborTileIndex >= (uint)bank.getTileCount ())
00858 {
00859 nlwarning ("CZoneSymmetrisation::propagateTileState: Invalid tile index");
00860 return false;
00861 }
00862
00863
00864 int neighborTileSet;
00865 int neighborNumber;
00866 CTileBank::TTileType neighborType;
00867 bank.getTileXRef (neighborTileIndex, neighborTileSet, neighborNumber, neighborType);
00868
00869
00870 if ( (neighborTileSet == tileSetToPropagate) &&
00871 (neighborNode.Rotate == neighborPatchPtr->Tiles[neighborTile].getTileOrient(neighborLayer)) )
00872 break;
00873 }
00874 }
00875
00876
00877 if (neighborLayer<3)
00878 {
00879
00880 if (!(oriented && getOrientedTileCorner (neighborNode.Patch, neighborTile)))
00881 {
00882
00883 TState neighborState = getTileState (neighborNode.Patch, neighborTile, neighborLayer);
00884 if (neighborState == Nothing)
00885 {
00886
00887 setTileState (neighborNode.Patch, neighborTile, neighborLayer, neighborNode.State);
00888
00889
00890 if (currentNode.Edge < 3)
00891 {
00892 currentNode.Edge++;
00893 stack.push_back (currentNode);
00894 }
00895
00896
00897 currentNode = neighborNode;
00898 }
00899 else if (neighborState != neighborNode.State)
00900 {
00901
00902
00903
00904
00905 currentNode.Edge++;
00906 }
00907 else
00908 {
00909
00910 currentNode.Edge++;
00911 }
00912 }
00913 else
00914 {
00915
00916 currentNode.Edge++;
00917 }
00918 }
00919 else
00920
00921 currentNode.Edge++;
00922 }
00923 while (currentNode.Edge<4);
00924 }
00925 }
00926 }
00927 }
00928 }
00929 }
00930
00931 return true;
00932 }
00933
00934
00935
00936 }