1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/3d/tessellation.h"
23 #include "nel/3d/patch.h"
24 #include "nel/3d/zone.h"
25 #include "nel/misc/common.h"
26 #include "nel/3d/landscape_profile.h"
27 #include "nel/3d/landscape.h"
28 #include "nel/3d/patchdlm_context.h"
30 using namespace NLMISC
;
41 // ***************************************************************************
42 #define NL3D_TESS_USE_QUADRANT_THRESHOLD 0.1f
45 // ***************************************************************************
46 // The normal Uvs format.
47 const uint8 TileUvFmtNormal1
= 0;
48 const uint8 TileUvFmtNormal2
= 1;
49 const uint8 TileUvFmtNormal3
= 2;
50 const uint8 TileUvFmtNormal4
= 3;
51 const uint8 TileUvFmtNormal5
= 4;
54 // ***************************************************************************
55 const float TileSize
= 128;
58 // ***************************************************************************
59 // ***************************************************************************
61 // ***************************************************************************
62 // ***************************************************************************
65 // ***************************************************************************
66 CTileMaterial::CTileMaterial()
68 // By default, all pass are NULL.
69 for(uint i
=0; i
<NL3D_MAX_TILE_FACE
; i
++)
71 TileFaceVectors
[i
]= NULL
;
76 // ***************************************************************************
77 void CTileMaterial::appendTileToEachRenderPass(uint patchNumRenderableFaces
)
79 for(uint i
=0;i
<NL3D_MAX_TILE_PASS
;i
++)
81 // If RdrPass exist, add this Material Id
82 CPatchRdrPass
*rdrPass
= Pass
[i
].PatchRdrPass
;
85 /* enlarge the capacity of the pass so it can renders the tile faces of this patch.
86 * NumRenderableFaces is really too big since the tile-material surely doesn't use all
87 * faces of the patch (except if same texture...)
88 * But doesn't matter. Even if all the visible Tile Surface (80m*80m) is in the same pass,
89 * it leads to only 76K final in CLandscapeGlobals::PassTriArray:
90 * 80*80(Visible surface at 80m max) /4 (2m*2m) *2(triangles) *2 (over-estimate) *3*4(triSize)=
93 rdrPass
->appendRdrPatchTile(i
, &Pass
[i
], patchNumRenderableFaces
);
99 // ***************************************************************************
100 // ***************************************************************************
102 // ***************************************************************************
103 // ***************************************************************************
106 // ***************************************************************************
107 void CTessVertex::computeGeomPos()
109 // Compute Basic ErrorMetric.
110 float sqrDist
= (StartPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
111 float pgeom
= MaxFaceSize
* CLandscapeGlobals::OORefineThreshold
/ sqrDist
;
113 // Compute ErrorMetric modified by TileNear transition, only if TileNear transition.
114 if( sqrDist
< CLandscapeGlobals::TileDistFarSqr
)
116 // Soft optim: do it only if necessary, ie result of max(errorMetric, errorMetricModified) is foreseeable here.
117 if(pgeom
< MaxNearLimit
)
119 float f
= (CLandscapeGlobals::TileDistFarSqr
- sqrDist
) * CLandscapeGlobals::OOTileDistDeltaSqr
;
121 // ^4 gives better smooth result
124 // interpolate the errorMetric
125 pgeom
= MaxNearLimit
*f
+ pgeom
*(1-f
);
129 // Interpolate StartPos to EndPos, between 1 and 2.
136 float f
= pgeom
- 1.0f
;
137 Pos
= f
* (EndPos
-StartPos
) + StartPos
;
142 // ***************************************************************************
143 // ***************************************************************************
145 // ***************************************************************************
146 // ***************************************************************************
149 // ***************************************************************************
150 CTessFace
CTessFace::CantMergeFace
;
151 CTessFace
CTessFace::MultipleBindFace
;
154 // ***************************************************************************
155 CTessFace::CTessFace()
157 // Don't modify any of it!!
158 // Patch, SonLeft and SonRight nullity are very useful for MultiplePatch faces, and CantMergeFace.
161 VBase
=VLeft
=VRight
= NULL
;
162 FBase
=FLeft
=FRight
= NULL
;
163 Father
=SonLeft
=SonRight
= NULL
;
166 // Size, Center, paramcoord undetermined.
169 // Very important (for split reasons). Init Tilefaces to NULL.
170 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
175 RecursMarkCanMerge
=false;
176 RecursMarkForceMerge
=false;
179 NL3D_PROFILE_LAND_ADD(ProfNTessFace
, 1);
185 // ***************************************************************************
186 CTessFace::~CTessFace()
188 // Old Code. This is not sufficient to clear the CTessFace.
189 // Vertices and Uvs must be correctly cleared too (but difficult because of sharing).
191 Patch->getLandscape()->deleteTessFace(SonLeft);
192 Patch->getLandscape()->deleteTessFace(SonRight);
195 if(FBase) FBase->changeNeighbor(this, NULL);
196 if(FLeft) FLeft->changeNeighbor(this, NULL);
197 if(FRight) FRight->changeNeighbor(this, NULL);
199 FBase=FLeft=FRight= NULL;
202 NL3D_PROFILE_LAND_ADD(ProfNTessFace
, -1);
204 // Ensure correclty removed from landscape ShadowMap.
205 nlassert(ShadowMapTriId
== -1);
209 // ***************************************************************************
210 float CTessFace::computeNearLimit()
212 // General formula for Level, function of Size, threshold etc...:
213 // WantedLevel= log2(BaseSize / sqrdist / RefineThreshold);
214 // <=> WantedLevel= log2( CurSize*2^Level / sqrdist / RefineThreshold).
215 // <=> WantedLevel= log2( ProjectedSize* 2^Level / RefineThreshold).
216 // <=> 2^WantedLevel= ProjectedSize* 2^Level / RefineThreshold.
217 // <=> ProjectedSize= (2^WantedLevel) * RefineThreshold / (2^Level);
218 // <=> ProjectedSize= (1<<WantedLevel) * RefineThreshold / (1<<Level);
219 // UnOptimised formula: limit= (1<<Patch->TileLimitLevel) / (1<<Level);
221 static const uint BigValue
= 1<<20;
222 static const float OOBigValue
= 1.0f
/ BigValue
;
223 return (1<<Patch
->TileLimitLevel
) * (OOBigValue
*(BigValue
>>Level
));
227 // ***************************************************************************
228 void CTessFace::computeTileErrorMetric()
230 // We must take a more correct errometric here: We must have sons face which have
231 // lower projectedsize than father. This is not the case if Center of face is taken (but when not in
232 // tile mode this is nearly the case). So take the min dist from 3 points.
233 float s0
= (VBase
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
234 float s1
= (VLeft
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
235 float s2
= (VRight
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
236 float sqrdist
= minof(s0
, s1
, s2
);
237 // It is also VERY important to take the min of 3, to ensure the split in TileMode when Far1 vertex begin
238 // to blend (see Patch::renderFar1() render).
240 // NB: VertexProgram geomorph take sqrdist= (SplitPoint - RefineCenter).sqrnorm();
241 // It's OK because geomorph will start "far" after the split.
243 if(sqrdist
< CLandscapeGlobals::TileDistFarSqr
)
246 nearLimit
= CLandscapeGlobals::RefineThreshold
* computeNearLimit();
247 // If we are not so subdivided.
248 if(ErrorMetric
<nearLimit
)
250 if(sqrdist
< CLandscapeGlobals::TileDistNearSqr
)
252 ErrorMetric
=nearLimit
;
256 // Smooth transition to the nearLimit of tesselation.
257 float f
= ( CLandscapeGlobals::TileDistFarSqr
- sqrdist
) * CLandscapeGlobals::OOTileDistDeltaSqr
;
258 // sqr gives better result, by smoothing more the start of transition.
261 ErrorMetric
= ErrorMetric
+ (nearLimit
-ErrorMetric
)*f
;
263 // If threshold is big like 0.5, transition is still hard, and pops occurs. But The goal is
264 // 0.005 and less, so don't bother.
271 // ***************************************************************************
272 void CTessFace::updateErrorMetric()
274 // If already updated for this pass...
275 if(ErrorMetricDate
>= CLandscapeGlobals::CurrentDate
)
278 CVector viewdir
= SplitPoint
- CLandscapeGlobals::RefineCenter
;
279 float sqrdist
= viewdir
.sqrnorm();
283 ErrorMetric
= Size
/ sqrdist
;
286 // Hoppe97 formula: k^2= a^2 * ("v-e"^2 - ((v-e).n)^2) / "v-e"^4.
288 // Can't do it because geomorph is made on Graphic card, so the simplier is the better.
293 /* TileMode Impact. We must split at least at TileLimitLevel, but only if the triangle
294 has a chance to enter in the TileDistFar sphere.
296 if( Level
<Patch
->TileLimitLevel
&& sqrdist
< sqr(CLandscapeGlobals::TileDistFar
+MaxDistToSplitPoint
) )
298 computeTileErrorMetric();
301 ErrorMetricDate
= CLandscapeGlobals::CurrentDate
;
305 // ***************************************************************************
306 inline float CTessFace::computeTileEMForUpdateRefine(float distSplitPoint
, float distMinFace
, float nearLimit
)
309 // Normal ErrorMetric simulation.
310 ema
= Size
/ sqr(distSplitPoint
);
312 // TileErrorMetric simulation.
313 if(distMinFace
< CLandscapeGlobals::TileDistFar
)
315 // If we are not so subdivided.
318 if( distMinFace
< CLandscapeGlobals::TileDistNear
)
324 // Smooth transition to the nearLimit of tesselation.
325 float f
= ( CLandscapeGlobals::TileDistFarSqr
- sqr(distMinFace
) ) * CLandscapeGlobals::OOTileDistDeltaSqr
;
326 // sqr gives better result, by smoothing more the start of transition.
329 ema
= ema
+ (nearLimit
-ema
)*f
;
334 return ema
* CLandscapeGlobals::OORefineThreshold
;
338 // ***************************************************************************
339 void CTessFace::computeSplitPoint()
343 // If it is a rectangular triangle, it will be splitted on the middle of VBase/VLeft.
344 // see splitRectangular() conventions.
345 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
346 SplitPoint
= (VLeft
->EndPos
+ VBase
->EndPos
)/2;
350 // If it is a square triangle, it will be splitted on middle of VLeft/VRight.
351 // So for good geomorph compute per vertex, we must have this SplitPoint on this middle.
352 SplitPoint
= (VLeft
->EndPos
+ VRight
->EndPos
)/2;
355 // compute MaxDistToSplitPoint
356 float d0
= (VBase
->EndPos
- SplitPoint
).sqrnorm();
357 float d1
= (VLeft
->EndPos
- SplitPoint
).sqrnorm();
358 float d2
= (VRight
->EndPos
- SplitPoint
).sqrnorm();
359 MaxDistToSplitPoint
= max(d0
, d1
);
360 MaxDistToSplitPoint
= max(MaxDistToSplitPoint
, d2
);
362 MaxDistToSplitPoint
= sqrtf(MaxDistToSplitPoint
);
365 // ***************************************************************************
366 void CTessFace::allocTileUv(TTileUvId id
)
368 // TileFaces must have been build.
369 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
372 CTessVertex
*vertexSrc
;
375 case IdUvBase
: vertexSrc
= VBase
; break;
376 case IdUvLeft
: vertexSrc
= VLeft
; break;
377 case IdUvRight
: vertexSrc
= VRight
; break;
378 default: vertexSrc
= 0; nlstop
; break;
381 // Do it for all possible pass
382 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
386 CTessNearVertex
*newNear
= Patch
->getLandscape()->newTessNearVertex();
387 newNear
->Src
= vertexSrc
;
388 TileFaces
[i
]->V
[id
]= newNear
;
389 Patch
->appendNearVertexToRenderList(TileMaterial
, newNear
);
391 // May Allocate/Fill VB. Do it after allocTileUv, because UVs are not comuted yet.
396 // ***************************************************************************
397 void CTessFace::checkCreateFillTileVB(TTileUvId id
)
399 // TileFaces must have been build.
400 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
402 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
406 CTessNearVertex
*vertNear
;
407 vertNear
= TileFaces
[i
]->V
[id
];
409 // May Allocate/Fill VB.
410 Patch
->checkCreateVertexVBNear(vertNear
);
411 Patch
->checkFillVertexVBNear(vertNear
);
417 // ***************************************************************************
418 void CTessFace::checkFillTileVB(TTileUvId id
)
420 // TileFaces must have been build.
421 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
423 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
427 CTessNearVertex
*vertNear
;
428 vertNear
= TileFaces
[i
]->V
[id
];
431 Patch
->checkFillVertexVBNear(vertNear
);
437 // ***************************************************************************
438 void CTessFace::deleteTileUv(TTileUvId id
)
440 // TileFaces must still exist.
441 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
443 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
447 CTessNearVertex
*oldNear
;
448 oldNear
= TileFaces
[i
]->V
[id
];
449 TileFaces
[i
]->V
[id
]=NULL
;
451 // May delete this vertex from VB.
452 Patch
->checkDeleteVertexVBNear(oldNear
);
454 Patch
->removeNearVertexFromRenderList(TileMaterial
, oldNear
);
455 Patch
->getLandscape()->deleteTessNearVertex(oldNear
);
459 // ***************************************************************************
460 void CTessFace::copyTileUv(TTileUvId dstId
, CTessFace
*srcFace
, TTileUvId srcId
)
462 // TileFaces must have been build.
463 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
465 // Since this a ptr-copy, no need to add/remove the renderlist of near vertices.
467 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
471 // The srcface should have the same tileFaces enabled.
472 nlassert(srcFace
->TileFaces
[i
]);
475 CTessNearVertex
*copyNear
;
476 copyNear
= srcFace
->TileFaces
[i
]->V
[srcId
];
479 TileFaces
[i
]->V
[dstId
]= copyNear
;
483 // ***************************************************************************
484 void CTessFace::heritTileUv(CTessFace
*baseFace
)
486 // TileFaces must have been build.
487 nlassert(TileFaces
[NL3D_TILE_PASS_RGB0
]);
489 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
493 // The baseface should have the same tileFaces enabled.
494 nlassert(baseFace
->TileFaces
[i
]);
495 // VBase should be allocated.
496 nlassert(TileFaces
[i
]->V
[IdUvBase
]);
497 TileFaces
[i
]->V
[IdUvBase
]->initMiddleUv(
498 *baseFace
->TileFaces
[i
]->V
[IdUvLeft
], *baseFace
->TileFaces
[i
]->V
[IdUvRight
]);
504 // ***************************************************************************
505 void CTessFace::buildTileFaces()
507 nlassert(TileMaterial
);
509 // Do nothgin for lightmap pass, of course.
510 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
512 if(TileMaterial
->Pass
[i
].PatchRdrPass
)
514 TileFaces
[i
]= Patch
->getLandscape()->newTileFace();
515 TileFaces
[i
]->V
[IdUvBase
]= NULL
;
516 TileFaces
[i
]->V
[IdUvLeft
]= NULL
;
517 TileFaces
[i
]->V
[IdUvRight
]= NULL
;
521 // ***************************************************************************
522 void CTessFace::deleteTileFaces()
524 nlassert(TileMaterial
);
526 // Do nothgin for lightmap pass, of course.
527 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
529 if(TileMaterial
->Pass
[i
].PatchRdrPass
)
531 nlassert(TileFaces
[i
]);
532 Patch
->getLandscape()->deleteTileFace(TileFaces
[i
]);
537 nlassert(TileFaces
[i
]==NULL
);
542 // ***************************************************************************
543 bool CTessFace::emptyTileFaces()
545 // Do nothgin for lightmap pass, of course.
546 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
548 // Some TileFace exist??
558 // ***************************************************************************
559 void CTessFace::initTileUvRGBA(sint pass
, bool alpha
, CParamCoord pointCoord
, CParamCoord middle
, CUV
&uv
)
561 // Get good coordinate according to patch orientation.
562 uv
.U
= pointCoord
.S
<=middle
.S
? 0.0f
: 1.0f
;
563 uv
.V
= pointCoord
.T
<=middle
.T
? 0.0f
: 1.0f
;
565 // Get Tile Uv info: orientation and scale.
570 Patch
->getTileUvInfo(TileId
, pass
, alpha
, orient
, uvScaleBias
, is256
, uvOff
);
600 if(uvOff
==2 || uvOff
==3)
602 if(uvOff
==1 || uvOff
==2)
607 // Do the HalfPixel scale bias.
608 float hBiasXY
, hBiasZ
;
611 hBiasXY
= CLandscapeGlobals::TilePixelBias256
;
612 hBiasZ
= CLandscapeGlobals::TilePixelScale256
;
616 hBiasXY
= CLandscapeGlobals::TilePixelBias128
;
617 hBiasZ
= CLandscapeGlobals::TilePixelScale128
;
622 uv
.U
*= uvScaleBias
.z
*hBiasZ
;
623 uv
.V
*= uvScaleBias
.z
*hBiasZ
;
624 uv
.U
+= uvScaleBias
.x
+hBiasXY
;
625 uv
.V
+= uvScaleBias
.y
+hBiasXY
;
629 // ***************************************************************************
630 void CTessFace::initTileUvLightmap(CParamCoord pointCoord
, CParamCoord middle
, CUV
&uv
)
632 // Get good coordinate according to patch orientation.
633 uv
.U
= pointCoord
.S
<=middle
.S
? 0.0f
: 1.0f
;
634 uv
.V
= pointCoord
.T
<=middle
.T
? 0.0f
: 1.0f
;
636 // Get Tile Lightmap Uv info: bias and scale.
638 Patch
->getTileLightMapUvInfo(TileMaterial
->TileS
, TileMaterial
->TileT
, uvScaleBias
);
641 uv
.U
*= uvScaleBias
.z
;
642 uv
.V
*= uvScaleBias
.z
;
643 uv
.U
+= uvScaleBias
.x
;
644 uv
.V
+= uvScaleBias
.y
;
648 // ***************************************************************************
649 void CTessFace::initTileUvDLM(CParamCoord pointCoord
, CUV
&uv
)
651 // get the dlm context from the patch.
652 CPatchDLMContext
*dlmCtx
= Patch
->_DLMContext
;
653 // mmust exist at creation of the tile.
656 // get coord in 0..1 range, along the patch.
657 uv
.U
= pointCoord
.getS();
658 uv
.V
= pointCoord
.getT();
660 // ScaleBias according to the context.
661 uv
.U
*= dlmCtx
->DLMUScale
;
662 uv
.V
*= dlmCtx
->DLMVScale
;
663 uv
.U
+= dlmCtx
->DLMUBias
;
664 uv
.V
+= dlmCtx
->DLMVBias
;
668 // ***************************************************************************
669 void CTessFace::computeTileMaterial()
671 // 0. Compute TileId.
672 //-------------------
673 // Square Order Patch assumption: assume that when a CTessFace become a tile, his base can ONLY be diagonal...
683 Here, if OrderS*OrderT=2*2, ABC is a new CTessFace of a Tile, and AB is the diagonal of the tile.
684 Hence the middle of the tile is the middle of AB.
686 C must be created, but A and B may be created or copied from neighbor.
688 CParamCoord
middle(PVLeft
,PVRight
);
689 uint16 ts
= ((uint16
)middle
.S
* (uint16
)Patch
->OrderS
) / 0x8000;
690 uint16 tt
= ((uint16
)middle
.T
* (uint16
)Patch
->OrderT
) / 0x8000;
691 TileId
= (uint8
)(tt
*Patch
->OrderS
+ ts
);
694 // 1. Compute Tile Material.
695 //--------------------------
696 // if base neighbor is already at TileLimitLevel just ptr-copy, else create the TileMaterial...
697 nlassert(!FBase
|| FBase
->Patch
!=Patch
|| FBase
->Level
<=Patch
->TileLimitLevel
);
699 copyFromBase
= (FBase
&& FBase
->Patch
==Patch
);
700 copyFromBase
= copyFromBase
&& (FBase
->Level
==Patch
->TileLimitLevel
&& FBase
->TileMaterial
!=NULL
);
701 // NB: because of delete/recreateTileUvs(), FBase->TileMaterial may be NULL, even if face is at good TileLimitLevel.
704 TileMaterial
= FBase
->TileMaterial
;
705 nlassert(FBase
->TileId
== TileId
);
710 TileMaterial
= Patch
->getLandscape()->newTileMaterial();
711 TileMaterial
->TileS
= uint8(ts
);
712 TileMaterial
->TileT
= uint8(tt
);
714 // Add this new material to the render list.
715 Patch
->appendTileMaterialToRenderList(TileMaterial
);
717 // First, get a lightmap for this tile. NB: important to do this after appendTileMaterialToRenderList(),
718 // because use TessBlocks.
719 Patch
->getTileLightMap(ts
, tt
, TileMaterial
->Pass
[NL3D_TILE_PASS_LIGHTMAP
].PatchRdrPass
);
721 // Fill pass of multi pass material.
722 for(i
=0;i
<NL3D_MAX_TILE_PASS
;i
++)
724 // Get the correct render pass, according to the tile number, and the pass.
725 if(i
!=NL3D_TILE_PASS_LIGHTMAP
)
726 TileMaterial
->Pass
[i
].PatchRdrPass
= Patch
->getTileRenderPass(TileId
, i
);
730 for(i
=0;i
<NL3D_MAX_TILE_PASS
;i
++)
732 TileMaterial
->Pass
[i
].TileMaterial
= TileMaterial
;
735 // Do not append this tile to each RenderPass, done in preRender().
741 // NB: TileMaterial is already setup. Useful for initTileUvLightmap() and initTileUvRGBA().
743 // First, must create The TileFaces, according to the TileMaterial passes.
746 // Must allocate the Base, and insert into list.
747 allocTileUv(IdUvBase
);
750 // Init LightMap UV, in RGB0 pass, UV1..
751 initTileUvLightmap(PVBase
, middle
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvBase
]->PUv1
);
752 // Init DLM Uv, in RGB0 pass, UV2.
753 initTileUvDLM(PVBase
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvBase
]->PUv2
);
755 // Init UV RGBA, for all pass (but lightmap).
756 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
758 nlassert(i
!=NL3D_TILE_PASS_LIGHTMAP
);
760 if( TileMaterial
->Pass
[i
].PatchRdrPass
)
763 nlassert(TileFaces
[i
]);
764 // Compute RGB UV in UV0.
765 initTileUvRGBA(i
, false, PVBase
, middle
, TileFaces
[i
]->V
[IdUvBase
]->PUv0
);
766 // If transition tile, compute alpha UV in UV1.
767 // Do it also for Additive, because may have Transition
768 if(i
== NL3D_TILE_PASS_RGB1
|| i
==NL3D_TILE_PASS_RGB2
|| i
==NL3D_TILE_PASS_ADD
)
769 initTileUvRGBA(i
, true, PVBase
, middle
, TileFaces
[i
]->V
[IdUvBase
]->PUv1
);
773 // UVs are computed, may create and fill VB.
774 checkCreateFillTileVB(IdUvBase
);
777 // if base neighbor is already at TileLimitLevel just ptr-copy, else create the left/right TileUvs...
780 // Just cross-copy the pointers.
781 // Make Left near vertices be the Right vertices of FBase
782 copyTileUv(IdUvLeft
, FBase
, IdUvRight
);
783 // Make Right near vertices be the Left vertices of FBase
784 copyTileUv(IdUvRight
, FBase
, IdUvLeft
);
788 // Must allocate the left/right uv (and insert into list).
789 allocTileUv(IdUvLeft
);
790 allocTileUv(IdUvRight
);
793 // Init LightMap UV, in UvPass 0, UV1..
794 initTileUvLightmap(PVLeft
, middle
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvLeft
]->PUv1
);
795 initTileUvLightmap(PVRight
, middle
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvRight
]->PUv1
);
796 // Init DLM Uv, in RGB0 pass, UV2.
797 initTileUvDLM(PVLeft
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvLeft
]->PUv2
);
798 initTileUvDLM(PVRight
, TileFaces
[NL3D_TILE_PASS_RGB0
]->V
[IdUvRight
]->PUv2
);
801 for(sint i
=0;i
<NL3D_MAX_TILE_FACE
;i
++)
803 nlassert(i
!=NL3D_TILE_PASS_LIGHTMAP
);
805 if(TileMaterial
->Pass
[i
].PatchRdrPass
)
808 nlassert(TileFaces
[i
]);
809 // Compute RGB UV in UV0.
810 initTileUvRGBA(i
, false, PVLeft
, middle
, TileFaces
[i
]->V
[IdUvLeft
]->PUv0
);
811 initTileUvRGBA(i
, false, PVRight
, middle
, TileFaces
[i
]->V
[IdUvRight
]->PUv0
);
812 // If transition tile, compute alpha UV in UV1.
813 // Do it also for Additive, because may have Transition
814 if(i
== NL3D_TILE_PASS_RGB1
|| i
==NL3D_TILE_PASS_RGB2
|| i
==NL3D_TILE_PASS_ADD
)
816 initTileUvRGBA(i
, true, PVLeft
, middle
, TileFaces
[i
]->V
[IdUvLeft
]->PUv1
);
817 initTileUvRGBA(i
, true, PVRight
, middle
, TileFaces
[i
]->V
[IdUvRight
]->PUv1
);
822 // UVs are computed, may create and fill VB.
823 checkCreateFillTileVB(IdUvLeft
);
824 checkCreateFillTileVB(IdUvRight
);
828 // ***************************************************************************
829 void CTessFace::releaseTileMaterial()
831 // Hence, must release the tile. TileUvBase is differnet for each of leaves.
832 deleteTileUv(IdUvBase
);
834 nlassert(!FBase
|| FBase
->Level
<=Patch
->TileLimitLevel
);
835 if(FBase
&& FBase
->Level
==Patch
->TileLimitLevel
&& FBase
->TileMaterial
!=NULL
)
837 // Do not release Uvs, since neighbor need it...
838 // But release faces.
840 // Do not release TileMaterial, since neighbor need it...
846 deleteTileUv(IdUvLeft
);
847 deleteTileUv(IdUvRight
);
849 // After, release Tile faces.
852 // Release the tile lightmap part. Do it before removeTileMaterialFromRenderList().
853 Patch
->releaseTileLightMap(TileMaterial
->TileS
, TileMaterial
->TileT
);
855 // Remove this material from the render list. DO it before deletion of course :).
856 // NB: TileS/TileT still valid.
857 Patch
->removeTileMaterialFromRenderList(TileMaterial
);
859 Patch
->getLandscape()->deleteTileMaterial(TileMaterial
);
866 // ***************************************************************************
867 void CTessFace::updateNearFarVertices()
869 nlassert(VBase
&& FVBase
);
870 nlassert(VLeft
&& FVLeft
);
871 nlassert(VRight
&& FVRight
);
875 FVRight
->Src
= VRight
;
876 FVBase
->PCoord
= PVBase
;
877 FVLeft
->PCoord
= PVLeft
;
878 FVRight
->PCoord
= PVRight
;
880 // Update VB for far vertices (if needed)
881 Patch
->checkFillVertexVBFar(FVBase
);
882 Patch
->checkFillVertexVBFar(FVLeft
);
883 Patch
->checkFillVertexVBFar(FVRight
);
885 // Near Vertices update (Src only).
886 for(sint i
=0; i
<NL3D_MAX_TILE_FACE
; i
++)
890 TileFaces
[i
]->V
[IdUvBase
]->Src
= VBase
;
891 TileFaces
[i
]->V
[IdUvLeft
]->Src
= VLeft
;
892 TileFaces
[i
]->V
[IdUvRight
]->Src
= VRight
;
894 // Update VB for near vertices (if needed)
895 Patch
->checkFillVertexVBNear(TileFaces
[i
]->V
[IdUvBase
]);
896 Patch
->checkFillVertexVBNear(TileFaces
[i
]->V
[IdUvLeft
]);
897 Patch
->checkFillVertexVBNear(TileFaces
[i
]->V
[IdUvRight
]);
904 // ***************************************************************************
905 void CTessFace::splitRectangular(bool propagateSplit
)
908 CTessFace
*f1
= FBase
;
909 // Rectangular case: FBase must exist.
912 // In rectangular case, we split at the same time this and FBase (f0 and f1).
919 --------------------- ---------------------
921 | ---- f1 | | \ f1l | \ f1r |
922 | ---- | --> | \ | \ |
923 | f0 ---- | | f0r \ | f0l \ |
925 --------------------- ---------------------
928 Why? For symetry and bind/split reasons: FBase->SonLeft->VBase is always the good vertex to take
929 (see vertex binding).
931 CParamCoord pclt
= f1
->PVLeft
;
932 CParamCoord pclb
= f0
->PVBase
;
933 CParamCoord pcrt
= f1
->PVBase
;
934 CParamCoord pcrb
= f1
->PVRight
;
935 CTessVertex
*vlt
= f1
->VLeft
;
936 CTessVertex
*vlb
= f0
->VBase
;
937 CTessVertex
*vrt
= f1
->VBase
;
938 CTessVertex
*vrb
= f1
->VRight
;
940 CTessFarVertex
*farvlt
= f1
->FVLeft
;
941 CTessFarVertex
*farvlb
= f0
->FVBase
;
942 CTessFarVertex
*farvrt
= f1
->FVBase
;
943 CTessFarVertex
*farvrb
= f1
->FVRight
;
946 // 1. create new vertices.
947 //------------------------
949 // Create splitted vertices.
950 CParamCoord
pctop(f1
->PVBase
, f1
->PVLeft
);
951 CParamCoord
pcbot(f0
->PVBase
, f0
->PVLeft
);
952 CTessVertex
*vtop
= NULL
;
953 CTessVertex
*vbot
= NULL
;
955 if(f1
->FLeft
==NULL
|| f1
->FLeft
->isLeaf())
957 // The base neighbor is a leaf or NULL. So must create the new vertex.
958 vtop
= Patch
->getLandscape()->newTessVertex();
961 vtop
->StartPos
= (f1
->VLeft
->EndPos
+ f1
->VBase
->EndPos
)/2;
962 vtop
->EndPos
= f1
->Patch
->computeVertex(pctop
.getS(), pctop
.getT());
963 // Init Pos= InitialPos. Important in the case of enforced split.
964 vtop
->Pos
= vtop
->StartPos
;
966 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
967 vtop
->MaxFaceSize
= f1
->Size
;
968 vtop
->MaxNearLimit
= f1
->computeNearLimit();
972 // Else, get from neighbor.
973 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
974 // NB: this work with both rectangular and square triangles.
975 vtop
= f1
->FLeft
->SonLeft
->VBase
;
977 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
978 vtop
->MaxFaceSize
= max( vtop
->MaxFaceSize
, f1
->Size
);
979 vtop
->MaxNearLimit
= max( vtop
->MaxNearLimit
, f1
->computeNearLimit());
982 if(f0
->FLeft
==NULL
|| f0
->FLeft
->isLeaf())
984 // The base neighbor is a leaf or NULL. So must create the new vertex.
985 vbot
= Patch
->getLandscape()->newTessVertex();
988 vbot
->StartPos
= (f0
->VLeft
->EndPos
+ f0
->VBase
->EndPos
)/2;
989 vbot
->EndPos
= Patch
->computeVertex(pcbot
.getS(), pcbot
.getT());
990 // Init Pos= InitialPos. Important in the case of enforced split.
991 vbot
->Pos
= vbot
->StartPos
;
993 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
994 vbot
->MaxFaceSize
= f0
->Size
;
995 vbot
->MaxNearLimit
= f0
->computeNearLimit();
999 // Else, get from neighbor.
1000 // NB: since *FLeft is not a leaf, FBase->SonLeft!=NULL...
1001 // NB: this work with both rectangular and square triangles.
1002 vbot
= f0
->FLeft
->SonLeft
->VBase
;
1004 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
1005 vbot
->MaxFaceSize
= max( vbot
->MaxFaceSize
, f0
->Size
);
1006 vbot
->MaxNearLimit
= max( vbot
->MaxNearLimit
, f0
->computeNearLimit());
1009 // In all case, must create new FarVertices, since rect split occurs on border!!
1010 CTessFarVertex
*farvtop
= Patch
->getLandscape()->newTessFarVertex();
1011 CTessFarVertex
*farvbot
= Patch
->getLandscape()->newTessFarVertex();
1014 farvtop
->PCoord
= pctop
;
1015 farvbot
->PCoord
= pcbot
;
1016 Patch
->appendFarVertexToRenderList(farvtop
);
1017 Patch
->appendFarVertexToRenderList(farvbot
);
1018 // May Allocate/Fill VB.
1019 // NB: vtop / vbot are well computed and ready for the fill in VB.
1020 Patch
->checkCreateVertexVBFar(farvtop
);
1021 Patch
->checkFillVertexVBFar(farvtop
);
1022 Patch
->checkCreateVertexVBFar(farvbot
);
1023 Patch
->checkFillVertexVBFar(farvbot
);
1025 // For VertexProgram only, must refill the Far vertex of neighbor(s),
1026 // because MaxFaceSize, and MaxNearLimit may have change.
1027 if( CLandscapeGlobals::VertexProgramEnabled
)
1030 if( ! (f0
->FLeft
==NULL
|| f0
->FLeft
->isLeaf()) )
1031 f0
->FLeft
->Patch
->checkFillVertexVBFar(f0
->FLeft
->SonLeft
->FVBase
);
1033 if( ! (f1
->FLeft
==NULL
|| f1
->FLeft
->isLeaf()) )
1034 f1
->FLeft
->Patch
->checkFillVertexVBFar(f1
->FLeft
->SonLeft
->FVBase
);
1038 // 2. Create sons, and update links.
1039 //----------------------------------
1041 CTessFace
*f0l
, *f0r
;
1042 CTessFace
*f1l
, *f1r
;
1044 // create and bind Sons.
1045 f0l
= f0
->SonLeft
= Patch
->getLandscape()->newTessFace();
1046 f0r
= f0
->SonRight
= Patch
->getLandscape()->newTessFace();
1047 f1l
= f1
->SonLeft
= Patch
->getLandscape()->newTessFace();
1048 f1r
= f1
->SonRight
= Patch
->getLandscape()->newTessFace();
1050 // subdivision left.
1051 f0l
->Patch
= f0
->Patch
;
1053 f0l
->Level
= f0
->Level
+1;
1054 f0l
->Size
= f0
->Size
*0.5f
;
1055 // subdivision right.
1056 f0r
->Patch
= f0
->Patch
;
1058 f0r
->Level
= f0
->Level
+1;
1059 f0r
->Size
= f0
->Size
*0.5f
;
1060 // subdivision left.
1061 f1l
->Patch
= f1
->Patch
;
1063 f1l
->Level
= f1
->Level
+1;
1064 f1l
->Size
= f1
->Size
*0.5f
;
1065 // subdivision right.
1066 f1r
->Patch
= f1
->Patch
;
1068 f1r
->Level
= f1
->Level
+1;
1069 f1r
->Size
= f1
->Size
*0.5f
;
1071 // Patch coordinates.
1076 f1l
->PVLeft
= f0r
->PVRight
;
1077 f1l
->PVRight
= f0r
->PVLeft
;
1079 f0l
->PVRight
= pctop
;
1083 f1r
->PVLeft
= f0l
->PVRight
;
1084 f1r
->PVRight
= f0l
->PVLeft
;
1086 // link existing vertex.
1091 f1l
->VLeft
= f0r
->VRight
;
1092 f1l
->VRight
= f0r
->VLeft
;
1098 f1r
->VLeft
= f0l
->VRight
;
1099 f1r
->VRight
= f0l
->VLeft
;
1101 // link Far vertices.
1102 f0r
->FVRight
= farvlt
;
1103 f0r
->FVBase
= farvlb
;
1104 f0r
->FVLeft
= farvbot
;
1105 f1l
->FVBase
= farvtop
;
1106 f1l
->FVLeft
= f0r
->FVRight
;
1107 f1l
->FVRight
= f0r
->FVLeft
;
1109 f0l
->FVRight
= farvtop
;
1110 f0l
->FVBase
= farvbot
;
1111 f0l
->FVLeft
= farvrb
;
1112 f1r
->FVBase
= farvrt
;
1113 f1r
->FVLeft
= f0l
->FVRight
;
1114 f1r
->FVRight
= f0l
->FVLeft
;
1116 // link neigbhor faces.
1123 f0r
->FRight
= f0
->FRight
;
1125 f0
->FRight
->changeNeighbor(f0
, f0r
);
1126 f1r
->FRight
= f1
->FRight
;
1128 f1
->FRight
->changeNeighbor(f1
, f1r
);
1129 // 4 links (all FLeft sons ) are stil invalid here.
1135 // Neigbors pointers of undetermined splitted face are not changed. Must Doesn't change this.
1136 // Used and Updated in section 5. ...
1139 // 3. Update Tile infos.
1140 //----------------------
1141 // There is no update tileinfo with rectangular patch, since tiles are always squares. (TileLimitLevel>SquareLimitLevel).
1143 // NB: but must test update of tile info for neighboring, ie 2 faces around the splits.
1144 // For Vertex program only
1145 if( CLandscapeGlobals::VertexProgramEnabled
)
1147 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
1148 // because MaxFaceSize and MaxNearLimit may have changed.
1149 if( f0
->FLeft
!=NULL
&& !f0
->FLeft
->isLeaf() && f0
->FLeft
->Patch
!=Patch
)
1151 // If neighbors sons at tile level, must update their Tile vertices.
1152 if( f0
->FLeft
->SonLeft
->Level
>= f0
->FLeft
->Patch
->TileLimitLevel
)
1154 f0
->FLeft
->SonLeft
->checkFillTileVB(IdUvBase
);
1155 f0
->FLeft
->SonRight
->checkFillTileVB(IdUvBase
);
1159 if( f1
->FLeft
!=NULL
&& !f1
->FLeft
->isLeaf() && f1
->FLeft
->Patch
!=Patch
)
1161 // If neighbors sons at tile level, must update their Tile vertices.
1162 if( f1
->FLeft
->SonLeft
->Level
>= f1
->FLeft
->Patch
->TileLimitLevel
)
1164 f1
->FLeft
->SonLeft
->checkFillTileVB(IdUvBase
);
1165 f1
->FLeft
->SonRight
->checkFillTileVB(IdUvBase
);
1171 // 4. Compute centers.
1172 //--------------------
1173 f0r
->computeSplitPoint();
1174 f0l
->computeSplitPoint();
1175 f1r
->computeSplitPoint();
1176 f1l
->computeSplitPoint();
1179 // 5. Propagate, or link sons of base.
1180 //------------------------------------
1181 for(sint i
=0;i
<2;i
++)
1183 CTessFace
*f
, *fl
, *fr
;
1199 // If current face and FBase has sons, just links.
1202 // Just update sons neighbors.
1206 else if(!f
->FLeft
->isLeaf())
1208 CTessFace
*toLeft
, *toRight
;
1209 toLeft
= f
->FLeft
->SonLeft
;
1210 toRight
= f
->FLeft
->SonRight
;
1211 // Cross connection of sons.
1212 if( !f
->FLeft
->isRectangular() )
1214 // Case neigbhor is square.
1222 // Case neigbhor is rectangle.
1229 else if (propagateSplit
)
1231 // Warning: at each iteration, the pointer of FLeft may change (because of split() which can change the neighbor
1233 while(f
->FLeft
->isLeaf())
1236 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
1237 // And problems may arise because this face hasn't yet good connectivity (especially for rectangles!! :) ).
1238 nlassert(fl
->isLeaf() && fr
->isLeaf());
1243 // 6. Must remove father from rdr list, and insert sons.
1244 //------------------------------------------------------
1245 // UGLY REFCOUNT SIDE EFFECT: do the append first.
1246 Patch
->appendFaceToRenderList(f0l
);
1247 Patch
->appendFaceToRenderList(f0r
);
1248 Patch
->appendFaceToRenderList(f1l
);
1249 Patch
->appendFaceToRenderList(f1r
);
1250 Patch
->removeFaceFromRenderList(f0
);
1251 Patch
->removeFaceFromRenderList(f1
);
1254 // 7. Update priority list.
1255 //------------------------------------------------------
1256 // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look
1257 // now when should merge.
1258 Patch
->getLandscape()->_MergePriorityList
.insert(0, 0, f0
);
1259 Patch
->getLandscape()->_MergePriorityList
.insert(0, 0, f1
);
1261 // Since we are split, no need to test father for merge, because it cannot!
1264 // remove father from any priority list.
1265 f0
->Father
->unlinkInPList();
1269 // remove father from any priority list.
1270 f1
->Father
->unlinkInPList();
1276 // ***************************************************************************
1277 void CTessFace::split(bool propagateSplit
)
1280 // 0. Some easy ending.
1281 //---------------------
1282 // Already splitted??
1286 //if(Level>=LS_MAXLEVEL)
1288 // since split() may reach LS_MAXLEVEL, but enforce splits which outpass this stage!!
1290 NL3D_PROFILE_LAND_ADD(ProfNSplits
, 1);
1293 // Special Rectangular case.
1296 splitRectangular(propagateSplit
);
1300 // 1. Create sons, and update links.
1301 //----------------------------------
1303 // create and bind Sons.
1304 SonLeft
= Patch
->getLandscape()->newTessFace();
1305 SonRight
= Patch
->getLandscape()->newTessFace();
1307 // subdivision left.
1308 SonLeft
->Patch
= Patch
;
1309 SonLeft
->Father
= this;
1310 SonLeft
->Level
= Level
+1;
1311 SonLeft
->Size
= Size
*0.5f
;
1312 // subdivision right.
1313 SonRight
->Patch
= Patch
;
1314 SonRight
->Father
= this;
1315 SonRight
->Level
= Level
+1;
1316 SonRight
->Size
= Size
*0.5f
;
1320 // link neighbor face.
1321 SonLeft
->FBase
= FLeft
;
1322 if(FLeft
) FLeft
->changeNeighbor(this, SonLeft
);
1323 SonLeft
->FLeft
= SonRight
;
1324 SonLeft
->FRight
= NULL
; // Temporary. updated later.
1325 // link neighbor vertex.
1326 SonLeft
->VLeft
= VBase
;
1327 SonLeft
->VRight
= VLeft
;
1328 // link neighbor Far vertex.
1329 SonLeft
->FVLeft
= FVBase
;
1330 SonLeft
->FVRight
= FVLeft
;
1331 // Patch coordinates.
1332 SonLeft
->PVBase
= CParamCoord(PVLeft
, PVRight
);
1333 SonLeft
->PVLeft
= PVBase
;
1334 SonLeft
->PVRight
= PVLeft
;
1337 // link neighbor face.
1338 SonRight
->FBase
= FRight
;
1339 if(FRight
) FRight
->changeNeighbor(this, SonRight
);
1340 SonRight
->FLeft
= NULL
; // Temporary. updated later.
1341 SonRight
->FRight
= SonLeft
;
1342 // link neighbor vertex.
1343 SonRight
->VLeft
= VRight
;
1344 SonRight
->VRight
= VBase
;
1345 // link neighbor Far vertex.
1346 SonRight
->FVLeft
= FVRight
;
1347 SonRight
->FVRight
= FVBase
;
1348 // Patch coordinates.
1349 SonRight
->PVBase
= CParamCoord(PVLeft
, PVRight
);
1350 SonRight
->PVLeft
= PVRight
;
1351 SonRight
->PVRight
= PVBase
;
1354 // FBase->FBase==this. Must Doesn't change this. Used and Updated in section 5. ...
1357 // 2. Update/Create Vertex infos.
1358 //-------------------------------
1360 // Must create/link *->VBase.
1361 if(FBase
==NULL
|| FBase
->isLeaf())
1363 // The base neighbor is a leaf or NULL. So must create the new vertex.
1364 CTessVertex
*newVertex
= Patch
->getLandscape()->newTessVertex();
1365 SonRight
->VBase
= newVertex
;
1366 SonLeft
->VBase
= newVertex
;
1369 newVertex
->StartPos
= (VLeft
->EndPos
+ VRight
->EndPos
)/2;
1370 newVertex
->EndPos
= Patch
->computeVertex(SonLeft
->PVBase
.getS(), SonLeft
->PVBase
.getT());
1372 // Init Pos= InitialPos. Important in the case of enforced split.
1373 newVertex
->Pos
= newVertex
->StartPos
;
1375 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
1376 newVertex
->MaxFaceSize
= Size
;
1377 newVertex
->MaxNearLimit
= computeNearLimit();
1381 // Else, get from neighbor.
1382 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
1383 // NB: this work with both rectangular and square triangles (see splitRectangular()).
1384 SonRight
->VBase
= FBase
->SonLeft
->VBase
;
1385 SonLeft
->VBase
= FBase
->SonLeft
->VBase
;
1387 // For geomorph (VertexProgram or soft), compute MaxFaceSize and MaxNearLimit.
1388 SonLeft
->VBase
->MaxFaceSize
= max( SonLeft
->VBase
->MaxFaceSize
, Size
);
1389 SonLeft
->VBase
->MaxNearLimit
= max( SonLeft
->VBase
->MaxNearLimit
, computeNearLimit());
1393 // Must create/link *->FVBase.
1394 // HERE, we must create a FarVertex too if the neighbor is not of the same patch as me.
1395 if(FBase
==NULL
|| FBase
->isLeaf() || FBase
->Patch
!=Patch
)
1397 // The base neighbor is a leaf or NULL. So must create the new far vertex.
1398 CTessFarVertex
*newFar
= Patch
->getLandscape()->newTessFarVertex();
1399 SonRight
->FVBase
= newFar
;
1400 SonLeft
->FVBase
= newFar
;
1403 newFar
->Src
= SonLeft
->VBase
;
1404 newFar
->PCoord
= SonLeft
->PVBase
;
1407 Patch
->appendFarVertexToRenderList(newFar
);
1409 // May Allocate/Fill VB.
1410 // NB: SonLeft->VBase->Pos is well computed and ready for the fill in VB.
1411 Patch
->checkCreateVertexVBFar(newFar
);
1412 Patch
->checkFillVertexVBFar(newFar
);
1414 // For VertexProgram only, must refill the Far vertex of neighbor,
1415 // because MaxFaceSize, and MaxNearLimit may have change.
1416 if( CLandscapeGlobals::VertexProgramEnabled
&& ! (FBase
==NULL
|| FBase
->isLeaf()) )
1417 FBase
->Patch
->checkFillVertexVBFar(FBase
->SonLeft
->FVBase
);
1421 // Else, get from neighbor.
1422 // NB: since *FBase is not a leaf, FBase->SonLeft!=NULL...
1423 // NB: this work with both rectangular and square triangles (see splitRectangular()).
1424 SonRight
->FVBase
= FBase
->SonLeft
->FVBase
;
1425 SonLeft
->FVBase
= FBase
->SonLeft
->FVBase
;
1427 // NB For VertexProgram only: no need to refill the Far vertex of neighbor, because neighbor is of same Patch
1428 // So MaxNearLimit and MaxFaceSize should be the same.
1432 // 3. Update Tile infos.
1433 //----------------------
1434 // NB: must do it before appendFaceToRenderList().
1435 // NB: must do it after compute of SonLeft->VBase->Pos for good filling in VBuffer.
1436 // There is no problem with rectangular patch, since tiles are always squares.
1438 if(SonLeft
->Level
==Patch
->TileLimitLevel
)
1440 SonLeft
->computeTileMaterial();
1441 SonRight
->computeTileMaterial();
1444 else if(SonLeft
->Level
> Patch
->TileLimitLevel
)
1446 heritTileMaterial();
1449 // For Vertex program only
1450 if( CLandscapeGlobals::VertexProgramEnabled
)
1452 // if neighbor face splitted, and if 2 different patchs, we must update the Tile vertices
1453 // because MaxFaceSize and MaxNearLimit may have changed.
1454 if( FBase
!=NULL
&& !FBase
->isLeaf() && FBase
->Patch
!=Patch
)
1456 // If neighbors sons at tile level, must update their Tile vertices.
1457 if( FBase
->SonLeft
->Level
>= FBase
->Patch
->TileLimitLevel
)
1459 FBase
->SonLeft
->checkFillTileVB(IdUvBase
);
1460 FBase
->SonRight
->checkFillTileVB(IdUvBase
);
1466 // 4. Compute centers.
1467 //--------------------
1468 SonRight
->computeSplitPoint();
1469 SonLeft
->computeSplitPoint();
1472 // 5. Propagate, or link sons of base.
1473 //------------------------------------
1474 // If current face and FBase has sons, just links.
1477 // Just update sons neighbors.
1478 SonLeft
->FRight
= NULL
;
1479 SonRight
->FLeft
= NULL
;
1481 else if(!FBase
->isLeaf())
1483 CTessFace
*toLeft
, *toRight
;
1487 toLeft
= FBase
->SonLeft
;
1488 toRight
= FBase
->SonRight
;
1489 // Cross connection of sons.
1490 if(!FBase
->isRectangular())
1492 // Case neigbhor is square.
1493 fl
->FRight
= toRight
;
1500 // Case neigbhor is rectangular.
1507 else if (propagateSplit
)
1509 // Warning: at each iteration, the pointer of FBase may change (because of split() which can change the neighbor
1511 while(FBase
->isLeaf())
1514 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
1515 // And problems may arise because this face hasn't yet good connectivity.
1516 nlassert(SonLeft
->isLeaf() && SonRight
->isLeaf());
1520 // 6. Must remove father from rdr list, and insert sons.
1521 //------------------------------------------------------
1522 // UGLY REFCOUNT SIDE EFFECT: do the append first.
1523 Patch
->appendFaceToRenderList(SonLeft
);
1524 Patch
->appendFaceToRenderList(SonRight
);
1525 Patch
->removeFaceFromRenderList(this);
1528 // 7. Update priority list.
1529 //------------------------------------------------------
1530 // Since we are freshly splitted, unlink from any list, and link to the MergePriorityList, because must look
1531 // now when should merge.
1532 Patch
->getLandscape()->_MergePriorityList
.insert(0, 0, this);
1534 // Since we are split, no need to test father for merge, because it cannot!
1537 // remove father from any priority list.
1538 Father
->unlinkInPList();
1542 // ***************************************************************************
1543 bool CTessFace::canMerge(bool testEm
)
1545 if(this== &CantMergeFace
)
1548 nlassert(!isLeaf());
1550 // Test diamond config (sons must be leaves).
1551 if(!SonLeft
->isLeaf())
1553 if(!SonRight
->isLeaf())
1555 // If Errormetric must be considered for this test.
1558 updateErrorMetric();
1559 float ps2
= ErrorMetric
;
1560 ps2
*= CLandscapeGlobals::OORefineThreshold
;
1565 // Then test neighbors.
1566 RecursMarkCanMerge
= true;
1568 if(!isRectangular())
1570 if(FBase
&& !FBase
->RecursMarkCanMerge
)
1572 if(!FBase
->canMerge(testEm
))
1578 // Rectangular case. May have a longer propagation...
1579 if(FBase
&& !FBase
->RecursMarkCanMerge
)
1581 if(!FBase
->canMerge(testEm
))
1584 if(ok
&& FLeft
&& !FLeft
->RecursMarkCanMerge
)
1586 if(!FLeft
->canMerge(testEm
))
1590 // Must not return false in preceding tests, because must set RecursMarkCanMerge to false.
1591 RecursMarkCanMerge
= false;
1597 // ***************************************************************************
1598 void CTessFace::doMerge()
1600 // Assume that canMerge() return true.
1601 // And Assume that !isLeaf().
1602 nlassert(!isLeaf());
1604 if(!isRectangular())
1606 // 1. Let's merge vertex.
1607 //-----------------------
1608 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
1609 // NB: this work even if neigbor is rectnagular.
1610 if(!FBase
|| !FBase
->isLeaf())
1611 Patch
->getLandscape()->deleteTessVertex(SonLeft
->VBase
);
1613 // Delete Far Vertex. Idem, but test too if != patch...
1614 if(!FBase
|| !FBase
->isLeaf() || FBase
->Patch
!=Patch
)
1616 // May delete this vertex from VB.
1617 Patch
->checkDeleteVertexVBFar(SonLeft
->FVBase
);
1619 Patch
->removeFarVertexFromRenderList(SonLeft
->FVBase
);
1620 Patch
->getLandscape()->deleteTessFarVertex(SonLeft
->FVBase
);
1624 // 2. Must remove sons from rdr list, and insert father.
1625 //------------------------------------------------------
1626 // Must do it BEFORE the TileFaces are released.
1627 // UGLY REFCOUNT SIDE EFFECT: do the append first.
1628 Patch
->appendFaceToRenderList(this);
1629 Patch
->removeFaceFromRenderList(SonLeft
);
1630 Patch
->removeFaceFromRenderList(SonRight
);
1633 // 3. Let's merge Uv.
1634 //-------------------
1636 // Must do it for this and FBase separately, since they may not have same tile level (if != patch).
1637 if(SonLeft
->Level
== Patch
->TileLimitLevel
)
1639 // Square patch assumption: the sons are not of the same TileId/Patch.
1640 nlassert(!sameTile(SonLeft
, SonRight
));
1641 // release tiles: NearVertices, TileFaces, and TileMaterial.
1642 SonLeft
->releaseTileMaterial();
1643 SonRight
->releaseTileMaterial();
1645 else if(SonLeft
->Level
> Patch
->TileLimitLevel
)
1647 // Delete Uv, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
1648 // But Always delete if neighbor exist and has not same tile as me.
1649 // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
1650 if(!FBase
|| !FBase
->isLeaf() || !sameTile(this, FBase
))
1652 SonLeft
->deleteTileUv(IdUvBase
);
1654 // In all case, must delete the tilefaces of those face.
1655 SonLeft
->deleteTileFaces();
1656 SonRight
->deleteTileFaces();
1660 // 4. Let's merge Face.
1661 //-------------------
1662 // Change father 's neighbor pointers.
1663 FLeft
= SonLeft
->FBase
;
1664 if(FLeft
) FLeft
->changeNeighbor(SonLeft
, this);
1665 FRight
= SonRight
->FBase
;
1666 if(FRight
) FRight
->changeNeighbor(SonRight
, this);
1668 Patch
->getLandscape()->deleteTessFace(SonLeft
);
1669 Patch
->getLandscape()->deleteTessFace(SonRight
);
1673 // If not already done, merge the neighbor.
1674 if(FBase
!=NULL
&& !FBase
->isLeaf())
1682 // Rectangular case.
1683 // Since minimum Order is 2, Sons of rectangular face are NEVER at TileLimitLevel. => no Uv merge to do.
1684 nlassert(SonLeft
->Level
< Patch
->TileLimitLevel
);
1687 // 1. Let's merge vertex.
1688 //-----------------------
1689 // Delete vertex, only if not already done by the neighbor (ie neighbor not already merged to a leaf).
1690 // NB: this work even if neigbor is rectangular (see tesselation rules in splitRectangular()).
1691 if(!FLeft
|| !FLeft
->isLeaf())
1692 Patch
->getLandscape()->deleteTessVertex(SonLeft
->VBase
);
1694 // Delete Far Vertex. Rect patch: neightb must be of a != pathc as me => must delete FarVertex.
1695 nlassert(!FLeft
|| FLeft
->Patch
!=Patch
);
1696 // May delete this vertex from VB.
1697 Patch
->checkDeleteVertexVBFar(SonLeft
->FVBase
);
1699 Patch
->removeFarVertexFromRenderList(SonLeft
->FVBase
);
1700 Patch
->getLandscape()->deleteTessFarVertex(SonLeft
->FVBase
);
1703 // 2. Must remove sons from rdr list, and insert father.
1704 //------------------------------------------------------
1705 // UGLY REFCOUNT SIDE EFFECT: do the append first.
1706 Patch
->appendFaceToRenderList(this);
1707 Patch
->removeFaceFromRenderList(SonLeft
);
1708 Patch
->removeFaceFromRenderList(SonRight
);
1711 // 3. Let's merge Face.
1712 //-------------------
1713 // Change father 's neighbor pointers (see splitRectangular()).
1714 FRight
= SonRight
->FRight
;
1715 if(FRight
) FRight
->changeNeighbor(SonRight
, this);
1717 Patch
->getLandscape()->deleteTessFace(SonLeft
);
1718 Patch
->getLandscape()->deleteTessFace(SonRight
);
1722 // First, do it for my rectangular co-worker FBase (if not already done).
1723 if(!FBase
->isLeaf())
1727 // If not already done, merge the neighbor.
1728 if(FLeft
!=NULL
&& !FLeft
->isLeaf())
1735 // Update priority list.
1736 //------------------------------------------------------
1737 // Since we are freshly merged, unlink from any list, and link to the SplitPriorityList, because must look
1738 // now when we should split again.
1739 Patch
->getLandscape()->_SplitPriorityList
.insert(0, 0, this);
1741 // since we are now merged maybe re-insert father in priority list.
1744 nlassert(!Father
->isLeaf());
1745 // If sons of father are both leaves (ie this, and the other (complexe case if rectangle) )
1746 if( Father
->SonLeft
->isLeaf() && Father
->SonRight
->isLeaf() )
1748 Patch
->getLandscape()->_MergePriorityList
.insert(0, 0, Father
);
1755 // ***************************************************************************
1756 bool CTessFace::merge()
1758 // Must not be a leaf.
1759 nlassert(!isLeaf());
1761 // 0. Verify if merge is posible.
1762 //----------------------------
1763 if(!canMerge(false))
1766 NL3D_PROFILE_LAND_ADD(ProfNMerges
, 1);
1768 // 1. Let's merge the face.
1769 //-----------------------
1770 // Propagation is done in doMerge().
1776 // ***************************************************************************
1777 void CTessFace::refineAll()
1779 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces
, 1);
1780 NL3D_PROFILE_LAND_ADD(ProfNRefineLeaves
, isLeaf()?1:0);
1783 if(ps<RefineThreshold), the face must be merged (ie have no leaves).
1784 if(ps E [RefineThreshold, RefineThreshold*2]), the face must be splitted (ave leaves), and is geomorphed.
1785 if(ps>RefineThreshold*2), the face is fully splitted/geomoprhed (tests reported on sons...).
1788 // Test for Split or merge.
1789 //-----------------------
1791 NL3D_PROFILE_LAND_ADD(ProfNRefineComputeFaces
, 1);
1793 updateErrorMetric();
1794 float ps
=ErrorMetric
;
1795 ps
*= CLandscapeGlobals::OORefineThreshold
;
1796 // 1.0f is the point of split().
1797 // 2.0f is the end of geomorph.
1800 // Test split/merge.
1801 //---------------------
1802 // If wanted, not already done, and limit not reached, split().
1805 if(ps
>1.0f
&& Level
< (Patch
->TileLimitLevel
+ CLandscapeGlobals::TileMaxSubdivision
) )
1810 // Else, if splitted, must merge (if not already the case).
1813 // Merge only if agree, and neighbors agree.
1814 // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
1815 // The test is propagated to neighbors.
1825 //-----------------------
1828 SonLeft
->refineAll();
1829 SonRight
->refineAll();
1835 // ***************************************************************************
1836 // Some updateRefine***() Doc:
1838 // Split or merge, and meaning of errorMetric:
1840 if(errorMetric<RefineThreshold), the face must be merged (ie have no leaves).
1841 if(errorMetric E [RefineThreshold, RefineThreshold*2]), the face must be splitted (ave leaves), and is geomorphed.
1842 if(errorMetric>RefineThreshold*2), the face is fully splitted/geomoprhed.
1846 // Compute distNormalSplitMerge: distance from refineCenter to normal split/merge (ie without tile transition):
1848 normal ErrorMetric formula is:
1849 em = Size*OORefineThreshold/ dist^2; with dist == (SplitPoint - CLandscapeGlobals::RefineCenter).norm()
1850 So inverse this function and we have:
1851 dist= sqrt(Size*OORefineThreshold/em).
1852 Split or merge is when em==1, so
1853 distSplitMerge= sqrt(Size*OORefineThreshold)
1857 // Compute distTileTransSplitMerge.
1858 /* When we are sure that CLandscapeGlobals::TileDistNear < distMinFace < CLandscapeGlobals::TileDistFar,
1859 the clamp in the original formula is skipped
1861 So the TileErrorMetric formula is:
1864 ema= Sife*OORefineThreshold / distSP^2.
1865 f= (TileDistFar^2 - distMinFace^2) * OOTileDeltaDist^2
1866 f= f ^ 4. // no clamp. see above.
1867 emb= NL*f + ema*(1-f)
1868 emFinal= max(ema, emb).
1871 The problem is that the formula is too complex (degree 8 equation).
1872 So search for the result recursively.
1876 // Quadrant Selection
1878 Quadrant/Direction is interesting for updateRefineSplit() only.
1879 In the 2 most simples cases, the action we want is "Know when we enters in a bounding volume"
1880 This fit well for Quadrant notion.
1882 In the case "TileDistNear to TileDistFar", the rule is too complicated and there is also
1883 the notion of "Know when we LEAVE the TileDistFar sphere around the face" which is incompatible
1884 with Quadrant behavior (since can go in any direction to leave the sphere).
1886 updateRefineMerge() are at least all notion of "Know when we LEAVE the SplitSphere around the SplitPoint"
1887 which is incompatible with Quadrant behavior.
1888 This is why updateRefineMerge() don't bother at all quadrant, and so the _MergePriorityList is inited with 0
1893 // ***************************************************************************
1894 void CTessFace::updateRefineSplit()
1896 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces
, 1);
1899 // The face must be not splitted, because tested for split.
1903 NB: see above for some updateRefine*** doc.
1907 //-----------------------
1908 bool splitted
= false;
1910 updateErrorMetric();
1911 float ps
=ErrorMetric
;
1912 ps
*= CLandscapeGlobals::OORefineThreshold
;
1913 // 1.0f is the point of split().
1914 // 2.0f is the end of geomorph.
1918 //---------------------
1919 // If wanted and limit not reached, split().
1920 if(ps
>1.0f
&& Level
< (Patch
->TileLimitLevel
+ CLandscapeGlobals::TileMaxSubdivision
) )
1933 // Insert the face in the priority list.
1934 //-----------------------
1935 // If splitted, then insertion in Landscape->MergePriorityList at 0 has been done. so nothing to update.
1936 // Else, must compute when whe should re-test.
1939 // the face is not splitted here.
1942 float minDeltaDistToUpdate
;
1944 // by default insert in the quadrant-less rolling table.
1948 CVector dirToSplitPoint
= SplitPoint
- CLandscapeGlobals::RefineCenter
;
1949 // The distance of SplitPoint to center.
1950 float distSplitPoint
= dirToSplitPoint
.norm();
1951 // The distance where we should split/merge. see updateRefin() doc.
1952 float distNormalSplitMerge
= (float)sqrt(Size
*CLandscapeGlobals::OORefineThreshold
);
1955 // If the face is at its max subdivision
1956 if(Level
>=Patch
->TileLimitLevel
+CLandscapeGlobals::TileMaxSubdivision
)
1958 // special case: the face do not need to be tested for splitting, because Max subdivision reached.
1959 // Hence just unlink from any list, and return.
1963 else if(Level
>=Patch
->TileLimitLevel
)
1965 // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently
1966 // of "Tile ErrorMetric".
1968 // The test is "when do we enter in the Split area?", so we can use Quadrant PriorityList
1969 quadrantId
= Patch
->getLandscape()->_SplitPriorityList
.selectQuadrant(dirToSplitPoint
);
1971 // compute distance to split as default "No Quadrant"
1972 minDeltaDistToUpdate
= distSplitPoint
- distNormalSplitMerge
;
1974 // If a quadrant is selected, try to use it
1977 const CVector
&quadrantDir
= Patch
->getLandscape()->_SplitPriorityList
.getQuadrantDirection(quadrantId
);
1979 // We must not approach the SplitPoint at distNormalSplitMerge
1980 float dMin
= quadrantDir
*dirToSplitPoint
- distNormalSplitMerge
;
1982 // If the dist with quadrant is too small then use the std way (without quadrant).
1983 if( dMin
<NL3D_TESS_USE_QUADRANT_THRESHOLD
)
1985 // else ok, use quadrant behavior
1987 minDeltaDistToUpdate
= dMin
;
1992 // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
1993 CVector dirToV0
= VBase
->EndPos
- CLandscapeGlobals::RefineCenter
;
1994 CVector dirToV1
= VLeft
->EndPos
- CLandscapeGlobals::RefineCenter
;
1995 CVector dirToV2
= VRight
->EndPos
- CLandscapeGlobals::RefineCenter
;
1996 float s0
= dirToV0
.sqrnorm();
1997 float s1
= dirToV1
.sqrnorm();
1998 float s2
= dirToV2
.sqrnorm();
1999 float distMinFace
= (float)sqrt( minof(s0
, s1
, s2
) );
2001 // compute the delta distance to the normal split point. See above for doc.
2002 float normalEMDeltaDist
;
2003 normalEMDeltaDist
= distSplitPoint
- distNormalSplitMerge
;
2007 There is 3 possibles cases, according to level, and the distances minFaceDist:
2009 /// TileDistFar to +oo.
2010 if( distMinFace
> CLandscapeGlobals::TileDistFar
)
2012 // The test is "when do we enter in the Split area OR in TileDistFar area?", so we can use Quadrant PriorityList
2013 quadrantId
= Patch
->getLandscape()->_SplitPriorityList
.selectQuadrant(dirToSplitPoint
);
2015 // compute deltaDist as default "Direction less quadrant"
2016 minDeltaDistToUpdate
= normalEMDeltaDist
;
2017 // We must know when we enter in TileErrorMetric zone, because the computing is different.
2018 minDeltaDistToUpdate
= min(minDeltaDistToUpdate
, distMinFace
- CLandscapeGlobals::TileDistFar
);
2020 // try with quadrant if > 0.
2023 const CVector
&quadrantDir
= Patch
->getLandscape()->_SplitPriorityList
.getQuadrantDirection(quadrantId
);
2025 // We must not approach the SplitPoint at distNormalSplitMerge
2026 float dMin
= quadrantDir
*dirToSplitPoint
- distNormalSplitMerge
;
2027 // and we must not reach one of the 3 sphere (Vi, TileDistFar).
2028 float d0
= quadrantDir
*dirToV0
- CLandscapeGlobals::TileDistFar
;
2029 float d1
= quadrantDir
*dirToV1
- CLandscapeGlobals::TileDistFar
;
2030 float d2
= quadrantDir
*dirToV2
- CLandscapeGlobals::TileDistFar
;
2032 dMin
= minof(dMin
, d0
, d1
, d2
);
2034 // If the dist with quadrant is too small then use the std way (without quadrant).
2035 if( dMin
<NL3D_TESS_USE_QUADRANT_THRESHOLD
)
2037 // else ok, use quadrant behavior
2039 minDeltaDistToUpdate
= dMin
;
2042 /// TileDistNear to TileDistFar.
2043 else if( distMinFace
> CLandscapeGlobals::TileDistNear
)
2045 // NB: can't use quadrant behavior here. Leave quadrantId at 0.
2048 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition
, 1);
2050 // Compute distance to split/Merge in TileTransition
2051 float distTileTransSplitMerge
;
2052 float maxDeltaDist
= 8;
2053 float minDeltaDist
= 0;
2056 nearLimit
= CLandscapeGlobals::RefineThreshold
* computeNearLimit();
2057 // search the distance to split recursively.
2058 for(uint i
=0; i
< nbRecurs
; i
++)
2060 float pivotDeltaDist
= (maxDeltaDist
-minDeltaDist
)/2;
2061 // If the em computed with this distance is still <1 (ie merged), then we can move further.
2062 if ( computeTileEMForUpdateRefine(distSplitPoint
-pivotDeltaDist
, distMinFace
-pivotDeltaDist
, nearLimit
) < 1)
2063 minDeltaDist
= pivotDeltaDist
;
2064 // else we must move not as far
2066 maxDeltaDist
= pivotDeltaDist
;
2068 // And so take the minimum resulting delta distance
2069 distTileTransSplitMerge
= minDeltaDist
;
2071 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
2073 minDeltaDistToUpdate
= min(distTileTransSplitMerge
, CLandscapeGlobals::TileDistFar
- distMinFace
);
2074 minDeltaDistToUpdate
= min(minDeltaDistToUpdate
, distMinFace
- CLandscapeGlobals::TileDistNear
);
2076 /// 0 to TileDistNear.
2079 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted,
2080 // and won't merge until reaching at least the TileDistNear sphere.
2081 // if not splited (should not arise), force the split next time.
2082 minDeltaDistToUpdate
= 0;
2088 if(minDeltaDistToUpdate
<0.0625)
2090 NL3D_PROFILE_LAND_ADD(ProfNRefineWithLowDistance
, 1);
2094 // insert in the Split priority list.
2095 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
2096 Patch
->getLandscape()->_SplitPriorityList
.insert(quadrantId
, minDeltaDistToUpdate
, this);
2101 // ***************************************************************************
2102 void CTessFace::updateRefineMerge()
2104 NL3D_PROFILE_LAND_ADD(ProfNRefineFaces
, 1);
2107 // The face must be splitted, because tested for merge.
2108 nlassert(!isLeaf());
2111 NB: see above for some updateRefine*** doc.
2115 //-----------------------
2118 updateErrorMetric();
2119 float ps
=ErrorMetric
;
2120 ps
*= CLandscapeGlobals::OORefineThreshold
;
2121 // 1.0f is the point of split().
2122 // 2.0f is the end of geomorph.
2126 //---------------------
2127 // Else, must merge ??
2130 // Merge only if agree, and neighbors agree.
2131 // canMerge() test all the good thing: FBase==CantMergeFace, or this is rectangular etc...
2132 // The test is propagated to neighbors.
2137 // NB: here, merge() is not propagated to fathers (supposed to be not very useful).
2148 // Insert the face in the priority list.
2149 //-----------------------
2150 // If merged, then insertion in Landscape->SplitPriorityList at 0 has been done. so nothing to update.
2151 // Else, must compute when whe should re-test.
2154 // the face is splitted here.
2155 nlassert(!isLeaf());
2157 float minDeltaDistToUpdate
;
2160 // The distance of SplitPoint to center.
2161 float distSplitPoint
= (SplitPoint
- CLandscapeGlobals::RefineCenter
).norm();
2162 // Compute distance from refineCenter to normal split/merge (ie without tile transition).
2163 float distNormalSplitMerge
= (float)sqrt(Size
*CLandscapeGlobals::OORefineThreshold
);
2166 // If the face is at its max subdivision
2167 if(Level
>=Patch
->TileLimitLevel
+CLandscapeGlobals::TileMaxSubdivision
)
2169 // since the face is splitted, then must test always this face, because we must merge it (as soon as it is possible).
2170 minDeltaDistToUpdate
= 0;
2172 else if(Level
>=Patch
->TileLimitLevel
)
2174 // Always normal ErrorMetric. Because Faces at Tile level decide to split or merge their sons independently
2175 // of "Tile ErrorMetric".
2176 // since splitted, compute distance to merge.
2177 minDeltaDistToUpdate
= distNormalSplitMerge
- distSplitPoint
;
2178 // NB: it is possible that minDeltaDistToUpdate<0. A good example is when we are enforced split.
2179 // Then, distSplitMerge may be < distSplitPoint, meaning we should have not split, but a neigbhor has enforced us.
2180 // So now, must test every frame if we can merge....
2181 minDeltaDistToUpdate
= max( 0.f
, minDeltaDistToUpdate
);
2185 // Compute Distance of the face from RefineCenter. It is the min of the 3 points, as in computeTileErrorMetric().
2186 float s0
= (VBase
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
2187 float s1
= (VLeft
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
2188 float s2
= (VRight
->EndPos
- CLandscapeGlobals::RefineCenter
).sqrnorm();
2189 float distMinFace
= (float)sqrt( minof(s0
, s1
, s2
) );
2191 // compute the delta distance to the normal split point. See above for doc.
2192 float normalEMDeltaDist
;
2193 normalEMDeltaDist
= distNormalSplitMerge
- distSplitPoint
;
2194 normalEMDeltaDist
= max( 0.f
, normalEMDeltaDist
);
2198 There is 3 possibles cases, according to level, and the distances minFaceDist:
2200 /// TileDistFar to +oo.
2201 if( distMinFace
> CLandscapeGlobals::TileDistFar
)
2203 // normal geomorph. Any face compute the distance to the SplitPoint, and take min with distance to
2204 // the TileDistFar sphere.
2205 minDeltaDistToUpdate
= normalEMDeltaDist
;
2207 // We must know when we enter in TileErrorMetric zone, because the computing is different.
2208 minDeltaDistToUpdate
= min(minDeltaDistToUpdate
, distMinFace
- CLandscapeGlobals::TileDistFar
);
2210 /// TileDistNear to TileDistFar.
2211 else if( distMinFace
> CLandscapeGlobals::TileDistNear
)
2214 NL3D_PROFILE_LAND_ADD(ProfNRefineInTileTransition
, 1);
2217 // Compute distance to split/Merge in TileTransition
2218 float distTileTransSplitMerge
;
2219 float maxDeltaDist
= 8;
2220 float minDeltaDist
= 0;
2223 nearLimit
= CLandscapeGlobals::RefineThreshold
* computeNearLimit();
2224 // Since splitted, compute distance to merge.
2225 // search the distance recursively.
2226 for(uint i
=0; i
< nbRecurs
; i
++)
2228 float pivotDeltaDist
= (maxDeltaDist
-minDeltaDist
)/2;
2229 // If the em computed with this distance is still >1 (ie splitted), then we can move further.
2230 if ( computeTileEMForUpdateRefine(distSplitPoint
+pivotDeltaDist
, distMinFace
+pivotDeltaDist
, nearLimit
) > 1)
2231 minDeltaDist
= pivotDeltaDist
;
2232 // else we must move not as far
2234 maxDeltaDist
= pivotDeltaDist
;
2236 // And so take the minimum resulting delta distance
2237 distTileTransSplitMerge
= minDeltaDist
;
2239 // take the min with distance of distMinFace to the TileDistNear and TileDistFar sphere, because formula change at
2241 minDeltaDistToUpdate
= min(distTileTransSplitMerge
, CLandscapeGlobals::TileDistFar
- distMinFace
);
2242 minDeltaDistToUpdate
= min(minDeltaDistToUpdate
, distMinFace
- CLandscapeGlobals::TileDistNear
);
2244 /// 0 to TileDistNear.
2247 // because the face is not a Tile Level (ie Level<Patch->TileLimitLevel), it should be splitted,
2248 // and won't merge until reaching at least the TileDistNear sphere.
2249 // Since splitted, Must enter in TileErrorMetric area to know when to merge.
2250 minDeltaDistToUpdate
= CLandscapeGlobals::TileDistNear
- distMinFace
;
2255 // Merge Refine Threshold: because of enforced splits, we have lot of faces whit minDeltaDistToUpdate<0, because
2256 // they alwayas want to merge. To avoid this, add a delta, which delay the test for merge.
2257 // The caveat is that faces which do not need this may merge later. But 2 meters won't add too many faces.
2258 minDeltaDistToUpdate
+= NL3D_REFINE_MERGE_THRESHOLD
;
2260 // insert in the Merge priority list.
2261 // Until the RefineCenter move under minDeltaDistToUpdate, we don't need to test face.
2262 Patch
->getLandscape()->_MergePriorityList
.insert(0, minDeltaDistToUpdate
, this);
2267 // ***************************************************************************
2268 void CTessFace::unbind()
2270 // NB: since CantMergeFace has a NULL patch ptr, it is unbound too.
2274 if(!isRectangular())
2276 // Change Left/Right neighbors.
2279 // FLeft and FRight pointers are only valid in Leaves nodes.
2280 if(FLeft
&& FLeft
->Patch
!=Patch
)
2282 FLeft
->changeNeighbor(this, NULL
);
2285 if(FRight
&& FRight
->Patch
!=Patch
)
2287 FRight
->changeNeighbor(this, NULL
);
2291 // Change Base neighbors.
2292 if(FBase
&& FBase
->Patch
!=Patch
)
2294 CTessFace
*oldNeigbhorFace
= FBase
;
2296 FBase
->changeNeighbor(this, NULL
);
2300 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
2301 CTessVertex
*old
= SonLeft
->VBase
;
2302 SonLeft
->VBase
= Patch
->getLandscape()->newTessVertex();
2303 *(SonLeft
->VBase
)= *old
;
2304 SonRight
->VBase
= SonLeft
->VBase
;
2306 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
2308 SonLeft
->VBase
->MaxFaceSize
= Size
;
2309 SonLeft
->VBase
->MaxNearLimit
= computeNearLimit();
2310 // update our neigbhor, only if not a multiple patch face.
2311 if(oldNeigbhorFace
->Patch
)
2313 old
->MaxFaceSize
= oldNeigbhorFace
->Size
;
2314 old
->MaxNearLimit
= oldNeigbhorFace
->computeNearLimit();
2319 // Rectangular case.
2320 //==================
2323 // Doens't need to test FBase, since must be same patch.
2324 // In rectangular, FLeft has the behavior of FBase in square case.
2325 if(FLeft
&& FLeft
->Patch
!=Patch
)
2327 CTessFace
*oldNeigbhorFace
= FLeft
;
2329 FLeft
->changeNeighbor(this, NULL
);
2333 // Duplicate the VBase of sons, so the unbind is correct and no vertices are shared.
2334 // NB: this code is a bit different from square case.
2335 CTessVertex
*old
= SonLeft
->VBase
;
2336 SonLeft
->VBase
= Patch
->getLandscape()->newTessVertex();
2337 *(SonLeft
->VBase
)= *old
;
2338 // This is the difference: (see rectangle tesselation rules).
2339 SonRight
->VLeft
= SonLeft
->VBase
;
2340 // Yoyo_patch_himself (12/02/2001): I forgot this one!!
2341 nlassert(FBase
&& FBase
->SonLeft
);
2342 FBase
->SonLeft
->VRight
= SonLeft
->VBase
;
2345 // For geomorph (VertexProgram or soft), compute good MaxFaceSize and MaxNearLimit (change since unbinded)
2347 SonLeft
->VBase
->MaxFaceSize
= Size
;
2348 SonLeft
->VBase
->MaxNearLimit
= computeNearLimit();
2349 // update our neigbhor, only if not a multiple patch face.
2350 if(oldNeigbhorFace
->Patch
)
2352 old
->MaxFaceSize
= oldNeigbhorFace
->Size
;
2353 old
->MaxNearLimit
= oldNeigbhorFace
->computeNearLimit();
2357 // But FRight still valid in leaves nodes only.
2360 if(FRight
&& FRight
->Patch
!=Patch
)
2362 FRight
->changeNeighbor(this, NULL
);
2368 // Propagate unbind.
2369 //==================
2372 // update sons vertex pointers (since they may have been updated by me or my grandfathers).
2373 if(!isRectangular())
2375 SonLeft
->VLeft
= VBase
;
2376 SonLeft
->VRight
= VLeft
;
2377 SonRight
->VLeft
= VRight
;
2378 SonRight
->VRight
= VBase
;
2382 // Rectangular case. Update only ptrs which may have changed.
2383 SonLeft
->VLeft
= VLeft
;
2384 SonRight
->VBase
= VBase
;
2385 SonRight
->VRight
= VRight
;
2388 // Must re-create good Vertex links for Far and Near Vertices!!!
2389 SonLeft
->updateNearFarVertices();
2390 SonRight
->updateNearFarVertices();
2393 //NB: must do this for Base neighbor (see unbind() rectangular case...).
2394 nlassert(FBase
&& FBase
->SonLeft
&& FBase
->SonRight
);
2395 FBase
->SonLeft
->updateNearFarVertices();
2396 FBase
->SonRight
->updateNearFarVertices();
2405 // ***************************************************************************
2406 void CTessFace::forceMerge()
2408 if(this== &CantMergeFace
)
2413 // First, force merge of Sons and neighbor sons, to have a diamond configuration.
2414 SonLeft
->forceMerge();
2415 SonRight
->forceMerge();
2417 // forceMerge of necessary neighbors.
2418 RecursMarkForceMerge
=true;
2419 if(!isRectangular())
2421 if(FBase
&& !FBase
->RecursMarkForceMerge
)
2422 FBase
->forceMerge();
2426 // Rectangular case. May have a longer propagation...
2427 if(FBase
&& !FBase
->RecursMarkForceMerge
)
2428 FBase
->forceMerge();
2429 if(FLeft
&& !FLeft
->RecursMarkForceMerge
)
2430 FLeft
->forceMerge();
2432 RecursMarkForceMerge
=false;
2434 // If still a parent, merge.
2441 // ***************************************************************************
2442 void CTessFace::forceMergeAtTileLevel()
2444 if(this== &CantMergeFace
)
2449 SonLeft
->forceMergeAtTileLevel();
2450 SonRight
->forceMergeAtTileLevel();
2454 // If we are at tile subdivision, we must force our sons to merge.
2455 if(Level
==Patch
->TileLimitLevel
)
2461 // ***************************************************************************
2462 void CTessFace::averageTesselationVertices()
2464 // If we are not splitted, no-op.
2469 CTessFace
*neighbor
;
2470 // Normal square case.
2471 if(!isRectangular())
2475 // Special Rectangular case.
2478 // NB: here, just need to compute average of myself with FLeft, because my neighbor FBase
2479 // is on same patch (see splitRectangular()), and is average with its FLeft neighbor is done
2480 // on another branch of the recurs call.
2485 /* Try to average with neighbor.
2486 - if no neighbor, no-op :).
2487 - if neighbor is bind 1/N (CantMergeFace), no-op too, because the vertex is a BaseVertex, so don't modify.
2488 - if my patch is same than my neighbor, then we are on a same patch :), and so no need to average.
2490 if(neighbor
!=NULL
&& neighbor
!=&CantMergeFace
&& Patch
!= neighbor
->Patch
)
2492 nlassert(neighbor
->Patch
);
2493 nlassert(!neighbor
->isLeaf());
2494 // must compute average beetween me and my neighbor.
2495 // NB: this work with both rectangular and square triangles (see split*()).
2496 nlassert(SonLeft
->VBase
== neighbor
->SonLeft
->VBase
);
2498 CVector v0
= Patch
->computeVertex(SonLeft
->PVBase
.getS(), SonLeft
->PVBase
.getT());
2499 CVector v1
= neighbor
->Patch
->computeVertex(neighbor
->SonLeft
->PVBase
.getS(), neighbor
->SonLeft
->PVBase
.getT());
2501 // And so set the average.
2502 SonLeft
->VBase
->EndPos
= (v0
+v1
)/2;
2506 // Do same thing for sons. NB: see above, we are not a leaf.
2507 SonLeft
->averageTesselationVertices();
2508 SonRight
->averageTesselationVertices();
2512 // ***************************************************************************
2513 void CTessFace::refreshTesselationGeometry()
2515 // must enlarge the little tessBlock (if any), for clipping.
2516 Patch
->extendTessBlockWithEndPos(this);
2518 // If we are not splitted, no-op.
2523 /* NB: rectangular case: just need to take SonLeft->VBase, because my neighbor on FBase will compute his son
2524 on another branch of the recurs call.
2526 // re-compute this position (maybe with new noise geometry in Tile Edition).
2527 SonLeft
->VBase
->EndPos
= Patch
->computeVertex(SonLeft
->PVBase
.getS(), SonLeft
->PVBase
.getT());
2528 // overwrite cur Pos (NB: specialy hardcoded for Tile edition).
2529 SonLeft
->VBase
->Pos
= SonLeft
->VBase
->EndPos
;
2531 // Do same thing for sons. NB: see above, we are not a leaf.
2532 SonLeft
->refreshTesselationGeometry();
2533 SonRight
->refreshTesselationGeometry();
2537 // ***************************************************************************
2538 bool CTessFace::updateBindEdge(CTessFace
*&edgeFace
, bool &splitWanted
)
2540 // Return true, when the bind should be Ok, or if a split has occurred.
2541 // Return false only if pointers are updated, without splits.
2546 if(edgeFace
->isLeaf())
2550 Look at the callers, and you'll see that "this" is always a leaf.
2551 Therefore, edgeFace is a valid pointer (either if it is FLeft, FRight or FBase).
2554 // MultiPatch face case.
2555 //======================
2556 // If neighbor is a multiple face.
2557 if(edgeFace
->Patch
==NULL
&& edgeFace
->FBase
==this)
2564 // neighbor is a "Square face" case.
2565 //==================================
2566 if(!edgeFace
->isRectangular())
2568 // NB: this code works either if I AM a rectangular face or a square face.
2570 // If the neighbor is splitted on ourself, split...
2571 if(edgeFace
->FBase
==this)
2578 // Just update pointers...
2579 if(edgeFace
->FLeft
==this)
2581 CTessFace
*sonLeft
= edgeFace
->SonLeft
;
2582 sonLeft
->FBase
= this;
2585 else if(edgeFace
->FRight
==this)
2587 CTessFace
*sonRight
= edgeFace
->SonRight
;
2588 sonRight
->FBase
= this;
2593 // Look at the callers, and you'll see that "this" is always a leaf.
2594 // Therefore, we should never be here.
2599 // neighbor is a "Rectangle face" case.
2600 //=====================================
2603 // NB: this code works either if I AM a rectangular face or a square face.
2605 // If the neighbor is splitted on ourself, split...
2606 // Test FLeft because of rectangular case... :)
2607 // FBase should be tested too. If edgeFace->FBase==this, I should be myself a rectangular face.
2608 if(edgeFace
->FLeft
==this || edgeFace
->FBase
==this)
2615 if(edgeFace
->FRight
==this)
2617 // See rectangular tesselation rules, too know why we do this.
2618 CTessFace
*sonRight
= edgeFace
->SonRight
;
2619 sonRight
->FRight
= this;
2624 // Look at the callers, and you'll see that "this" is always a leaf.
2625 // Therefore, we should never be here.
2636 // ***************************************************************************
2637 void CTessFace::updateBindAndSplit()
2639 bool splitWanted
= false;
2640 CTessFace
*f0
= NULL
;
2641 CTessFace
*f1
= NULL
;
2643 Look at the callers, and you'll see that "this" is always a leaf.
2644 Therefore, FBase, FLeft and FRight are good pointers, and *FLeft and *FRight should be Ok too.
2647 while(!updateBindEdge(FBase
, splitWanted
));
2648 // FLeft and FRight pointers are only valid in Leaves nodes.
2649 while(!updateBindEdge(FLeft
, splitWanted
));
2650 while(!updateBindEdge(FRight
, splitWanted
));
2651 // In rectangular case, we MUST also update edges of FBase.
2652 // Because splitRectangular() split those two faces at the same time.
2658 nlassert(FBase
->isLeaf());
2659 // Doesn't need to update FBase->FBase, since it's me!
2660 // FLeft and FRight pointers are only valid in Leaves nodes.
2661 while(!FBase
->updateBindEdge(FBase
->FLeft
, splitWanted
));
2662 while(!FBase
->updateBindEdge(FBase
->FRight
, splitWanted
));
2667 CTessFace
*fmult
= NULL
;
2668 CTessFace
*fmult0
= NULL
;
2669 CTessFace
*fmult1
= NULL
;
2670 // If multipatch face case.
2671 //=========================
2672 if(!isRectangular())
2674 // multipatch face case are detected when face->Patch==NULL !!!
2675 if(FBase
&& FBase
->Patch
==NULL
)
2678 // First, trick: FBase is NULL, so during the split. => no ptr problem.
2686 // multipatch face case are detected when face->Patch==NULL !!!
2687 if(f0
->FLeft
&& f0
->FLeft
->Patch
==NULL
)
2690 // First, trick: neighbor is NULL, so during the split. => no ptr problem.
2693 // multipatch face case are detected when face->Patch==NULL !!!
2694 if(f1
->FLeft
&& f1
->FLeft
->Patch
==NULL
)
2697 // First, trick: neighbor is NULL, so during the split. => no ptr problem.
2702 // Then split, and propagate.
2703 //===========================
2705 if(!isRectangular())
2709 while(FBase
->isLeaf())
2710 FBase
->updateBindAndSplit();
2712 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
2713 // And problems may arise because this face hasn't yet good connectivity.
2714 nlassert(SonLeft
->isLeaf() && SonRight
->isLeaf());
2722 while(f0
->FLeft
->isLeaf())
2723 f0
->FLeft
->updateBindAndSplit();
2727 while(f1
->FLeft
->isLeaf())
2728 f1
->FLeft
->updateBindAndSplit();
2730 // There is a possible bug here (maybe easily patched). Sons may have be propagated splitted.
2731 // And problems may arise because this face hasn't yet good connectivity.
2732 nlassert(f0
->SonLeft
->isLeaf() && f0
->SonRight
->isLeaf());
2733 nlassert(f1
->SonLeft
->isLeaf() && f1
->SonRight
->isLeaf());
2737 // If multipatch face case, update neighbors.
2738 //===========================================
2739 if(!isRectangular() && fmult
)
2741 // Update good Face neighbors.
2742 //============================
2743 SonLeft
->FRight
= fmult
->SonRight
;
2744 fmult
->SonRight
->changeNeighbor(&CTessFace::MultipleBindFace
, SonLeft
);
2746 SonRight
->FLeft
= fmult
->SonLeft
;
2747 fmult
->SonLeft
->changeNeighbor(&CTessFace::MultipleBindFace
, SonRight
);
2749 // NB: this work auto with 1/2 or 1/4. See CPatch::bind(), to understand.
2750 // In 1/4 case, fmult->SonLeft and fmult->SonRight are themselves MultiPatch face. So it will recurse.
2752 // Update good vertex pointer.
2753 //============================
2754 CTessVertex
*vert
= fmult
->VBase
;
2756 // Copy the good coordinate: those splitted (because of noise).
2757 vert
->Pos
= vert
->StartPos
= vert
->EndPos
= SonLeft
->VBase
->EndPos
;
2758 // But delete the pointer.
2759 Patch
->getLandscape()->deleteTessVertex(SonLeft
->VBase
);
2760 // And update sons pointers, to good vertex.
2761 SonLeft
->VBase
= vert
;
2762 SonRight
->VBase
= vert
;
2763 // Compute correct centers.
2764 SonRight
->computeSplitPoint();
2765 SonLeft
->computeSplitPoint();
2768 // Update good Far vertex pointer.
2769 //================================
2770 // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
2772 // We do not have to propagate this vertex ptr change since sons are leaves!!
2773 nlassert(SonLeft
->isLeaf() && SonRight
->isLeaf());
2774 // update pointers on vertex.
2775 SonLeft
->updateNearFarVertices();
2776 SonRight
->updateNearFarVertices();
2779 // Bind FBase to a false face which indicate a bind 1/N.
2780 // This face prevent for "this" face to be merged...
2781 FBase
= &CantMergeFace
;
2783 // Therefore, the vertex will be never deleted (since face not merged).
2784 // The only way to do this, is to unbind the patch from all (then the vertex is cloned), then the merge will be Ok.
2786 // Else if rectangular.
2787 else if(fmult0
|| fmult1
)
2794 // Same reasoning for rectangular patchs, as above.
2798 f
= f0
, fmult
= fmult0
;
2800 f
= f1
, fmult
= fmult1
;
2803 // Update good Face neighbors (when I am a rectangle).
2804 //============================
2805 // Consider the fmult face as a square face.
2806 CTessFace
*toLeft
, *toRight
;
2807 CTessFace
*fl
=f
->SonLeft
, *fr
=f
->SonRight
;
2808 toLeft
= fmult
->SonLeft
;
2809 toRight
= fmult
->SonRight
;
2810 // Cross connection of sons.
2813 toLeft
->changeNeighbor(&CTessFace::MultipleBindFace
, fl
);
2814 toRight
->changeNeighbor(&CTessFace::MultipleBindFace
, fr
);
2816 // Update good vertex pointer.
2817 //============================
2818 CTessVertex
*vert
= fmult
->VBase
;
2820 // Copy the good coordinate: those splitted (because of noise).
2821 // NB: this work too with rectangular patch (see tesselation rules).
2822 vert
->Pos
= vert
->StartPos
= vert
->EndPos
= fl
->VBase
->EndPos
;
2823 // But delete the pointer.
2824 Patch
->getLandscape()->deleteTessVertex(fl
->VBase
);
2825 // And update sons pointers, to good vertex (rectangular case, see tesselation rules).
2828 f
->FBase
->SonLeft
->VRight
= vert
;
2830 // Point to a bind 1/N indicator.
2831 f
->FLeft
= &CantMergeFace
;
2834 // After all updates done. recompute centers of both sons 's faces, and update far vertices pointers.
2841 // Compute correct centers.
2842 f
->SonRight
->computeSplitPoint();
2843 f
->SonLeft
->computeSplitPoint();
2845 // Update good Far vertex pointer.
2846 //================================
2847 // Because *->VBase may have been merged to the multiple bind face, Near/FarVertices which pointed on it must
2849 // We do not have to propagate this vertex ptr change, since sons are leaves!!
2850 nlassert(f
->SonLeft
->isLeaf() && f
->SonRight
->isLeaf());
2851 // update pointers on vertex.
2852 f
->SonLeft
->updateNearFarVertices();
2853 f
->SonRight
->updateNearFarVertices();
2859 // ***************************************************************************
2860 void CTessFace::updateBind()
2863 Remind that updateBind() is called ONLY on the patch which is binded (not the neighbors).
2864 Since updateBind() is called on the bintree, and that precedent propagated split may have occur, we may not
2865 be a leaf here. So we are not sure that FLeft and FRight are good, and we doesn't need to update them (since we have
2867 Also, since we are splitted, and correctly linked (this may not be the case in updateBindAndSplit()), FBase IS
2868 correct. His FBase neighbor and him form a diamond. So we don't need to update him.
2870 Same remarks for rectangular patchs.
2874 bool splitWanted
= false;
2875 while(!updateBindEdge(FBase
, splitWanted
));
2876 // FLeft and FRight pointers are only valid in Leaves nodes.
2877 while(!updateBindEdge(FLeft
, splitWanted
));
2878 while(!updateBindEdge(FRight
, splitWanted
));
2880 updateBindAndSplit();
2887 // Update bind of sons.
2888 SonLeft
->updateBind();
2889 SonRight
->updateBind();
2893 // ***************************************************************************
2894 static inline bool matchEdge(const CVector2f
&uv0
, const CVector2f
&uv1
, const CVector2f
&uva
, const CVector2f
&uvb
)
2896 if(uv0
==uva
&& uv1
==uvb
)
2898 if(uv0
==uvb
&& uv1
==uva
)
2903 // ***************************************************************************
2904 CTessFace
*CTessFace::linkTessFaceWithEdge(const CVector2f
&uv0
, const CVector2f
&uv1
, CTessFace
*linkTo
)
2906 // Compute 0,1 coords of 3 patch coords.
2907 CVector2f
vb( PVBase
.getS(), PVBase
.getT() );
2908 CVector2f
vl( PVLeft
.getS(), PVLeft
.getT() );
2909 CVector2f
vr( PVRight
.getS(), PVRight
.getT() );
2911 // Search if one of the 3 edges of this triangle match the wanted edge.
2913 if(matchEdge(uv0
, uv1
, vl
, vr
))
2915 // If leaf, check if unbound (else ptr is invalid)
2916 nlassert(FBase
==NULL
|| !isLeaf());
2921 if(matchEdge(uv0
, uv1
, vb
, vl
))
2923 // If leaf, check if unbound (else ptr is invalid)
2924 nlassert(FLeft
==NULL
|| !isLeaf());
2929 if(matchEdge(uv0
, uv1
, vb
, vr
))
2931 // If leaf, check if unbound (else ptr is invalid)
2932 nlassert(FRight
==NULL
|| !isLeaf());
2938 // If not found here, recurs to children
2939 CTessFace
*ret
= NULL
;
2942 ret
= SonLeft
->linkTessFaceWithEdge(uv0
, uv1
, linkTo
);
2943 // if no found in this branch, recusr right branch.
2945 ret
= SonRight
->linkTessFaceWithEdge(uv0
, uv1
, linkTo
);
2948 // return the result from subBranchs
2953 // ***************************************************************************
2954 bool CTessFace::isRectangular() const
2956 return Level
<Patch
->SquareLimitLevel
;
2961 // ***************************************************************************
2962 // ***************************************************************************
2963 // For changePatchTexture.
2964 // ***************************************************************************
2965 // ***************************************************************************
2968 // ***************************************************************************
2969 void CTessFace::deleteTileUvs()
2971 // NB: NearVertices are removed from renderlist with deleteTileUv (called in releaseTileMaterial()).
2975 // Must delete the materials of leaves first.
2976 SonLeft
->deleteTileUvs();
2977 SonRight
->deleteTileUvs();
2978 if(SonLeft
->Level
== Patch
->TileLimitLevel
)
2980 // Square patch assumption: the sons are not of the same TileId/Patch.
2981 nlassert(!sameTile(SonLeft
, SonRight
));
2983 SonLeft
->releaseTileMaterial();
2984 SonRight
->releaseTileMaterial();
2986 else if(SonLeft
->Level
> Patch
->TileLimitLevel
)
2988 nlassert(!FBase
|| !FBase
->isLeaf());
2990 // Delete Uv, only if not already done by the neighbor (ie neighbor has yet TileFaces!!).
2991 // But Always delete if neighbor exist and has not same tile as me.
2992 // NB: this work with rectangular neigbor patch, since sameTile() will return false if different patch.
2993 if(!FBase
|| !FBase
->SonLeft
->emptyTileFaces() || !sameTile(this, FBase
))
2995 SonLeft
->deleteTileUv(IdUvBase
);
2997 // In all case, must delete the tilefaces of those face.
2998 SonLeft
->deleteTileFaces();
2999 SonRight
->deleteTileFaces();
3000 // For createTileUvs, it is important to mark those faces as NO TileMaterial.
3001 SonLeft
->TileMaterial
= NULL
;
3002 SonRight
->TileMaterial
= NULL
;
3007 // NB: this is done always BELOW tile creation (see above).
3008 // Do this only for tiles.
3010 Patch
->removeFaceFromTileRenderList(this);
3016 // ***************************************************************************
3017 void CTessFace::recreateTileUvs()
3019 // NB: NearVertices are append to renderlist with allocTileUv (called in computeTileMaterial()/heritTileMaterial()).
3023 // Must recreate the materials of parent first.
3025 // There is no problem with rectangular patch, since tiles are always squares.
3027 if(SonLeft
->Level
==Patch
->TileLimitLevel
)
3029 SonLeft
->computeTileMaterial();
3030 SonRight
->computeTileMaterial();
3033 else if(SonLeft
->Level
> Patch
->TileLimitLevel
)
3035 heritTileMaterial();
3038 SonLeft
->recreateTileUvs();
3039 SonRight
->recreateTileUvs();
3043 // NB: this is done always AFTER tile creation (see above).
3044 // Do this only for tiles.
3046 Patch
->appendFaceToTileRenderList(this);
3052 // ***************************************************************************
3053 void CTessFace::heritTileMaterial()
3055 SonLeft
->TileMaterial
= TileMaterial
;
3056 SonLeft
->TileId
= TileId
;
3057 SonLeft
->buildTileFaces();
3058 SonLeft
->copyTileUv(IdUvLeft
, this, IdUvBase
);
3059 SonLeft
->copyTileUv(IdUvRight
, this, IdUvLeft
);
3061 SonRight
->TileMaterial
= TileMaterial
;
3062 SonRight
->TileId
= TileId
;
3063 SonRight
->buildTileFaces();
3064 SonRight
->copyTileUv(IdUvLeft
, this, IdUvRight
);
3065 SonRight
->copyTileUv(IdUvRight
, this, IdUvBase
);
3067 // Create, or link to the tileUv.
3068 // Try to link to a neighbor TileUv.
3069 // Can only work iff exist, and iff FBase is same patch, and same TileId.
3070 if(FBase
!=NULL
&& !FBase
->isLeaf() && FBase
->SonLeft
->TileMaterial
!=NULL
&& sameTile(this, FBase
) )
3072 // Ok!! link to the (existing) TileUv.
3073 // FBase->SonLeft!=NULL since FBase->isLeaf()==false.
3074 SonLeft
->copyTileUv(IdUvBase
, FBase
->SonLeft
, IdUvBase
);
3075 SonRight
->copyTileUv(IdUvBase
, FBase
->SonLeft
, IdUvBase
);
3079 // Allocate a new vertex, and copy it to SonLeft and SonRight.
3080 SonLeft
->allocTileUv(IdUvBase
);
3081 SonRight
->copyTileUv(IdUvBase
, SonLeft
, IdUvBase
);
3083 // Fill the new near vertex, with middle of Left/Right father.
3084 SonLeft
->heritTileUv(this);
3086 // UVs are computed, may create and fill VB.
3087 SonLeft
->checkCreateFillTileVB(IdUvBase
);
3093 // ***************************************************************************
3094 // ***************************************************************************
3095 // For getTesselatedPos
3096 // ***************************************************************************
3097 // ***************************************************************************
3100 // ***************************************************************************
3101 void CTessFace::getTesselatedPos(const CUV
&uv
, bool verifInclusion
, CVector
&ret
)
3103 CVector
uvPos(uv
.U
, uv
.V
, 0);
3105 // may verif if uv is In this triangle. supposed true if rectangular branch.
3106 if(verifInclusion
&& !(isRectangular() && !isLeaf()) )
3109 uvs
[0].set( PVBase
.getS(), PVBase
.getT(), 0);
3110 uvs
[1].set( PVLeft
.getS(), PVLeft
.getT(), 0);
3111 uvs
[2].set( PVRight
.getS(), PVRight
.getT(), 0);
3112 for(sint i
=0; i
<3; i
++)
3114 CVector dUv
= uvs
[(i
+1)%3] - uvs
[i
];
3115 CVector
normalUv(dUv
.y
, -dUv
.x
, 0);
3116 // if out this 2D plane, uv is out this triangle
3117 if(normalUv
* (uvPos
-uvs
[i
]) <0)
3122 // compute tesselated pos in this face.
3124 // ok, no more sons, let's do it.
3125 computeTesselatedPos(uv
, ret
);
3129 // if we are rectangular (strange tesselation), must test in both leaves, else, choose only one.
3132 SonLeft
->getTesselatedPos(uv
, true, ret
);
3133 SonRight
->getTesselatedPos(uv
, true, ret
);
3137 // Compute the uv plane which separate the 2 leaves.
3138 CVector uvBase
, uvMiddle
;
3139 uvBase
.set ( PVBase
.getS(), PVBase
.getT(), 0);
3140 uvMiddle
.set( SonLeft
->PVBase
.getS(), SonLeft
->PVBase
.getT(), 0);
3141 CVector dUv
= uvMiddle
- uvBase
;
3142 CVector
normalUv(dUv
.y
, -dUv
.x
, 0);
3143 // choose what leaf to recurs.
3144 if(normalUv
* (uvPos
- uvBase
) <0)
3145 SonLeft
->getTesselatedPos(uv
, false, ret
);
3147 SonRight
->getTesselatedPos(uv
, false, ret
);
3155 // ***************************************************************************
3156 void CTessFace::computeTesselatedPos(const CUV
&uv
, CVector
&ret
)
3158 CVector
uvPos(uv
.U
, uv
.V
, 0);
3160 // compute the UV triangle of this face.
3162 uvTri
.V0
.set( PVBase
.getS(), PVBase
.getT(), 0);
3163 uvTri
.V1
.set( PVLeft
.getS(), PVLeft
.getT(), 0);
3164 uvTri
.V2
.set( PVRight
.getS(), PVRight
.getT(), 0);
3166 // must interpolate the position with given UV, so compute XYZ gradients.
3170 // If VertexProgram activated
3171 if( CLandscapeGlobals::VertexProgramEnabled
)
3173 // then Must update geomorphed position because not done !!
3174 VBase
->computeGeomPos();
3175 VLeft
->computeGeomPos();
3176 VRight
->computeGeomPos();
3178 // NB: take geomorphed position.
3179 uvTri
.computeGradient(VBase
->Pos
.x
, VLeft
->Pos
.x
, VRight
->Pos
.x
, Gx
);
3180 uvTri
.computeGradient(VBase
->Pos
.y
, VLeft
->Pos
.y
, VRight
->Pos
.y
, Gy
);
3181 uvTri
.computeGradient(VBase
->Pos
.z
, VLeft
->Pos
.z
, VRight
->Pos
.z
, Gz
);
3183 // Compute interpolated position.
3193 // ***************************************************************************
3194 void CTessFace::appendTessellationLeaves(std::vector
<const CTessFace
*> &leaves
) const
3197 leaves
.push_back(this);
3200 SonLeft
->appendTessellationLeaves(leaves
);
3201 SonRight
->appendTessellationLeaves(leaves
);