1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "../zone_lib/zone_utility.h"
19 #include "nel/misc/types_nl.h"
20 #include "nel/misc/path.h"
21 #include "nel/misc/file.h"
22 #include "nel/misc/aabbox.h"
24 #include "nel/3d/quad_grid.h"
25 #include "nel/3d/bezier_patch.h"
26 #include "nel/3d/zone.h"
37 using namespace NLMISC
;
40 // a patch vertex info, for quadtree insertion
41 struct CPatchVertexInfo
43 uint ZoneIndex
; // this zone index, 0 for the midlle zone, and from 1 to 8 for the zones around
44 uint PatchIndex
; // the Patch of this zone
45 uint PatchVertex
; // the vertex of thi patch 0..3
49 CPatchVertexInfo(uint zoneIndex
,
54 : ZoneIndex(zoneIndex
),
55 PatchIndex(patchIndex
),
56 PatchVertex(patchVertex
),
62 typedef std::vector
<CPatchVertexInfo
*> TPVVect
;
63 typedef CQuadGrid
<CPatchVertexInfo
> TPVQuadGrid
;
65 // ***************************************************************************
67 void bind_1_1 (std::vector
<CPatchInfo
> &zoneInfos
, uint patch0
, uint edge0
, uint patch1
, uint edge1
, uint zoneId
)
70 zoneInfos
[patch0
].BindEdges
[edge0
].NPatchs
= 1;
71 zoneInfos
[patch1
].BindEdges
[edge1
].NPatchs
= 1;
74 zoneInfos
[patch0
].BindEdges
[edge0
].ZoneId
= zoneId
;
75 zoneInfos
[patch1
].BindEdges
[edge1
].ZoneId
= zoneId
;
78 zoneInfos
[patch0
].BindEdges
[edge0
].Next
[0] = patch1
;
79 zoneInfos
[patch1
].BindEdges
[edge1
].Next
[0] = patch0
;
82 zoneInfos
[patch0
].BindEdges
[edge0
].Edge
[0] = edge1
;
83 zoneInfos
[patch1
].BindEdges
[edge1
].Edge
[0] = edge0
;
86 // ***************************************************************************
88 void bind_1_2 (std::vector
<CPatchInfo
> &zoneInfos
, uint patch
, uint edge
, uint patch0
, uint edge0
, uint patch1
, uint edge1
, uint zoneId
)
91 zoneInfos
[patch
].BindEdges
[edge
].NPatchs
= 2;
92 zoneInfos
[patch0
].BindEdges
[edge0
].NPatchs
= 5;
93 zoneInfos
[patch1
].BindEdges
[edge1
].NPatchs
= 5;
96 zoneInfos
[patch
].BindEdges
[edge
].ZoneId
= zoneId
;
97 zoneInfos
[patch0
].BindEdges
[edge0
].ZoneId
= zoneId
;
98 zoneInfos
[patch1
].BindEdges
[edge1
].ZoneId
= zoneId
;
101 zoneInfos
[patch
].BindEdges
[edge
].Next
[0] = patch0
;
102 zoneInfos
[patch
].BindEdges
[edge
].Next
[1] = patch1
;
103 zoneInfos
[patch0
].BindEdges
[edge0
].Next
[0] = patch
;
104 zoneInfos
[patch1
].BindEdges
[edge1
].Next
[0] = patch
;
107 zoneInfos
[patch
].BindEdges
[edge
].Edge
[0] = edge0
;
108 zoneInfos
[patch
].BindEdges
[edge
].Edge
[1] = edge1
;
109 zoneInfos
[patch0
].BindEdges
[edge0
].Edge
[0] = edge
;
110 zoneInfos
[patch1
].BindEdges
[edge1
].Edge
[0] = edge
;
113 // ***************************************************************************
115 void bind_1_4 (std::vector
<CPatchInfo
> &zoneInfos
, uint patch
, uint edge
, uint patch0
, uint edge0
, uint patch1
, uint edge1
, uint patch2
, uint edge2
, uint patch3
, uint edge3
, uint zoneId
)
118 zoneInfos
[patch
].BindEdges
[edge
].NPatchs
= 4;
119 zoneInfos
[patch0
].BindEdges
[edge0
].NPatchs
= 5;
120 zoneInfos
[patch1
].BindEdges
[edge1
].NPatchs
= 5;
121 zoneInfos
[patch2
].BindEdges
[edge2
].NPatchs
= 5;
122 zoneInfos
[patch3
].BindEdges
[edge3
].NPatchs
= 5;
125 zoneInfos
[patch
].BindEdges
[edge
].ZoneId
= zoneId
;
126 zoneInfos
[patch0
].BindEdges
[edge0
].ZoneId
= zoneId
;
127 zoneInfos
[patch1
].BindEdges
[edge1
].ZoneId
= zoneId
;
128 zoneInfos
[patch2
].BindEdges
[edge2
].ZoneId
= zoneId
;
129 zoneInfos
[patch3
].BindEdges
[edge3
].ZoneId
= zoneId
;
132 zoneInfos
[patch
].BindEdges
[edge
].Next
[0] = patch0
;
133 zoneInfos
[patch
].BindEdges
[edge
].Next
[1] = patch1
;
134 zoneInfos
[patch
].BindEdges
[edge
].Next
[2] = patch2
;
135 zoneInfos
[patch
].BindEdges
[edge
].Next
[3] = patch3
;
136 zoneInfos
[patch0
].BindEdges
[edge0
].Next
[0] = patch
;
137 zoneInfos
[patch1
].BindEdges
[edge1
].Next
[0] = patch
;
138 zoneInfos
[patch2
].BindEdges
[edge2
].Next
[0] = patch
;
139 zoneInfos
[patch3
].BindEdges
[edge3
].Next
[0] = patch
;
142 zoneInfos
[patch
].BindEdges
[edge
].Edge
[0] = edge0
;
143 zoneInfos
[patch
].BindEdges
[edge
].Edge
[1] = edge1
;
144 zoneInfos
[patch
].BindEdges
[edge
].Edge
[2] = edge2
;
145 zoneInfos
[patch
].BindEdges
[edge
].Edge
[3] = edge3
;
146 zoneInfos
[patch0
].BindEdges
[edge0
].Edge
[0] = edge
;
147 zoneInfos
[patch1
].BindEdges
[edge1
].Edge
[0] = edge
;
148 zoneInfos
[patch2
].BindEdges
[edge2
].Edge
[0] = edge
;
149 zoneInfos
[patch3
].BindEdges
[edge3
].Edge
[0] = edge
;
152 // ***************************************************************************
154 /** Test whether 2 vertices could be welded */
156 static inline bool CanWeld(const CVector
&v1
, const CVector
&v2
, float weldThreshold
)
158 return (v1
- v2
).norm() < weldThreshold
;
161 // ***************************************************************************
163 uint
getOtherCountAndPos (const std::vector
<CPatchInfo
> &zoneInfo
, uint patch
, uint edge
, uint
&otherPos
)
165 // Must be a multiple patch bind
166 if (zoneInfo
[patch
].BindEdges
[edge
].NPatchs
== 5)
169 const CPatchInfo
&otherPatchRef
= zoneInfo
[zoneInfo
[patch
].BindEdges
[edge
].Next
[0]];
170 uint otherEdge
= zoneInfo
[patch
].BindEdges
[edge
].Edge
[0];
171 for (i
=0; i
<otherPatchRef
.BindEdges
[otherEdge
].NPatchs
; i
++)
173 if ( (otherPatchRef
.BindEdges
[otherEdge
].Next
[i
] == patch
) && (otherPatchRef
.BindEdges
[otherEdge
].Edge
[i
] == edge
) )
176 return otherPatchRef
.BindEdges
[otherEdge
].NPatchs
;
183 // ***************************************************************************
185 /** Get all vertices that are near the given one */
187 static void GetCandidateVertices(const CVector
&pos
,
191 uint patchToExcludeZone
,
197 const CVector
half(weldThreshold
, weldThreshold
, weldThreshold
);
198 float weldThresholdSrt
= weldThreshold
* weldThreshold
;
199 qg
.select(pos
- half
, pos
+ half
);
200 for (TPVQuadGrid::CIterator it
= qg
.begin(); it
!= qg
.end(); ++it
)
202 if ( ::CanWeld((*it
).Pos
, pos
, weldThreshold
) )
204 if ( (!exclude
) || (! ((*it
).ZoneIndex
== patchToExcludeZone
&& (*it
).PatchIndex
== patchToExclude
) ) )
206 // Final distance test
207 if ( (pos
- (*it
).Pos
).sqrnorm () <= weldThresholdSrt
)
208 dest
.push_back(&(*it
));
214 // ***************************************************************************
216 bool isBinded (std::vector
<CPatchInfo
> &zoneInfos
, uint patch0
, uint edge0
, uint patch1
, uint edge1
)
219 if ( (zoneInfos
[patch0
].BindEdges
[edge0
].NPatchs
!= 0) && (zoneInfos
[patch1
].BindEdges
[edge1
].NPatchs
!= 0) )
222 return (zoneInfos
[patch0
].BindEdges
[edge0
].Next
[0] == patch1
) ||
223 (zoneInfos
[patch1
].BindEdges
[edge1
].Next
[0] == patch0
);
228 // ***************************************************************************
230 CVector
evalPatchEdge (CPatchInfo
&patch
, uint edge
, float lambda
)
232 // index of this border vertices
233 static const float indexToST
[][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
234 const uint vIndex
[] = { edge
, (edge
+ 1) & 0x03 };
236 return patch
.Patch
.eval((1.f
- lambda
) * indexToST
[vIndex
[0]][0] + lambda
* indexToST
[vIndex
[1]][0],
237 (1.f
- lambda
) * indexToST
[vIndex
[0]][1] + lambda
* indexToST
[vIndex
[1]][1]);
240 // ***************************************************************************
242 void getFirst (CVector
&a
, CVector
&b
, CVector
&c
, CVector
&d
)
245 CVector ab
= (a
+b
)/2.f
;
248 CVector bc
= (b
+c
)/2.f
;
251 CVector cd
= (c
+d
)/2.f
;
255 d
= ( (bc
+ cd
) / 2.f
+ c
) / 2.f
;
258 // ***************************************************************************
260 void getSecond (CVector
&a
, CVector
&b
, CVector
&c
, CVector
&d
)
263 CVector ab
= (a
+b
)/2.f
;
266 CVector bc
= (b
+c
)/2.f
;
269 CVector cd
= (c
+d
)/2.f
;
273 a
= ( (ab
+ bc
) / 2.f
+ b
) / 2.f
;
276 // ***************************************************************************
278 void CleanZone ( std::vector
<CPatchInfo
> &zoneInfos
, uint zoneId
, const CAABBoxExt
&zoneBBox
, float weldThreshold
)
280 uint l
, m
, n
, p
, q
; // some loop counters
282 ///////////////////////////////
283 // retrieve datas from zones //
284 ///////////////////////////////
286 // fill the quad grid
287 float zoneSize
= 2.f
* weldThreshold
+ std::max(zoneBBox
.getMax().x
- zoneBBox
.getMin().x
,
288 zoneBBox
.getMax().y
- zoneBBox
.getMin().y
);
291 const uint numQGElt
= 128;
292 qg
.create (numQGElt
, zoneSize
/ numQGElt
);
294 for (l
= 0; l
< zoneInfos
.size(); ++l
)
296 CPatchInfo
&patch
= zoneInfos
[l
];
297 // for each base vertex of the patch
298 for (m
= 0; m
< 4; ++m
)
300 CVector
&pos
= patch
.Patch
.Vertices
[m
];
302 // yes, insert it in the tree
303 const CVector
half(weldThreshold
, weldThreshold
, weldThreshold
);
304 qg
.insert(pos
- half
, pos
+ half
, CPatchVertexInfo(zoneId
, l
, m
, pos
));
308 /////////////////////////////////////////////////
309 // check whether each patch is correctly bound //
310 /////////////////////////////////////////////////
317 for (l
= 0; l
< zoneInfos
.size(); ++l
)
320 CPatchInfo
&patch
= zoneInfos
[l
];
322 // deals with each border
323 for (m
= 0; m
< 4; ++m
)
325 const uint vIndex
[] = { m
, (m
+ 1) & 0x03 };
327 // if this border is said to be bound, no need to test..
328 if (patch
.BindEdges
[m
].NPatchs
== 0)
330 static TPVVect verts
[2];
332 // Get vertices from other patch that could be welded with this patch boder's vertices.
333 for (q
= 0; q
< 2; ++q
)
335 ::GetCandidateVertices(patch
.Patch
.Vertices
[vIndex
[q
]], qg
, verts
[q
], l
, zoneId
, weldThreshold
, true);
339 for (bindCount
= 1; bindCount
<5; bindCount
<<=1)
342 float middle
= 1.f
/ (float)bindCount
; // 0 = 0.5; 1 = 0.25
344 // Try to find a patch that shares 2 consecutives vertices
345 static TPVVect binded4
[5];
346 binded4
[0] = verts
[0];
347 binded4
[bindCount
] = verts
[1];
349 // Compute points along the border and found list of vertex binded to it.
350 float lambda
= middle
;
351 for (n
= 1; n
<bindCount
; ++n
)
353 CVector borderPos
= evalPatchEdge (patch
, m
, lambda
);
354 ::GetCandidateVertices(borderPos
, qg
, binded4
[n
], l
, zoneId
, weldThreshold
, true);
358 // Binded patches and edges
359 uint neighborPatches
[4];
360 uint neighborEdges
[4];
363 for (q
= 0; q
< bindCount
; q
++)
365 for (n
= 0; n
< binded4
[q
].size(); n
++)
367 for (p
= 0; p
< binded4
[q
+1].size(); p
++)
369 // Ref on the two patches
370 const CPatchVertexInfo
&pv0
= *(binded4
[q
][n
]);
371 const CPatchVertexInfo
&pv1
= *(binded4
[q
+1][p
]);
373 // Direct or indirect ?
375 uint v0
= pv0
.PatchVertex
;
376 uint v1
= pv1
.PatchVertex
;
377 if ( pv0
.ZoneIndex
== pv1
.ZoneIndex
&& pv0
.PatchIndex
== pv1
.PatchIndex
)
380 if ( ( ( pv0
.PatchVertex
- pv1
.PatchVertex
) & 3 ) == 1 )
383 uint patchId2
= pv0
.PatchIndex
;
389 if (zoneInfos
[patchId2
].BindEdges
[edge
].NPatchs
== 0)
392 neighborPatches
[q
] = patchId2
;
393 neighborEdges
[q
] = edge
;
400 if (n
== binded4
[q
].size())
401 // No bind found, stop
406 // Find all binded patches ?
409 // Check The patches are binded together
410 for (q
=0; q
<bindCount
-1; q
++)
412 if (!isBinded (zoneInfos
, neighborPatches
[q
], (neighborEdges
[q
]-1)&3, neighborPatches
[q
+1], (neighborEdges
[q
+1]+1)&3))
417 if (q
== (bindCount
-1) )
422 bind_1_1 (zoneInfos
, l
, m
, neighborPatches
[0], neighborEdges
[0], zoneId
);
425 else if (bindCount
== 2)
427 bind_1_2 (zoneInfos
, l
, m
, neighborPatches
[0], neighborEdges
[0], neighborPatches
[1], neighborEdges
[1], zoneId
);
432 bind_1_4 (zoneInfos
, l
, m
, neighborPatches
[0], neighborEdges
[0], neighborPatches
[1], neighborEdges
[1],
433 neighborPatches
[2], neighborEdges
[2], neighborPatches
[3], neighborEdges
[3], zoneId
);
436 // Exit connectivity loop
446 if (bind1Count
|| bind2Count
|| bind4Count
)
448 printf ("Internal bind pass %d: ", pass
);
450 printf ("bind1-1 %d; \n", bind1Count
);
452 printf ("bind1-2 %d; \n", bind2Count
);
454 printf ("bind1-4 %d; \n", bind4Count
);
457 // No more bind, stop
464 // Insert vertex binded in the map
465 for (l
= 0; l
< zoneInfos
.size(); ++l
)
467 CPatchInfo
&patch
= zoneInfos
[l
];
471 for (edge
= 0; edge
< 4; ++edge
)
474 uint bindCount
= patch
.BindEdges
[edge
].NPatchs
;
475 if ( (bindCount
== 2) || (bindCount
== 4) )
478 float middle
= 1.f
/ (float)bindCount
; // 0 = 0.5; 1 = 0.25
479 float lambda
= middle
;
481 // For all binded vertices
483 for (vert
= 1; vert
< bindCount
; vert
++)
485 // Eval the binded position
486 CVector borderPos
= evalPatchEdge (patch
, edge
, lambda
);
488 // yes, insert it in the tree
489 const CVector
half(weldThreshold
, weldThreshold
, weldThreshold
);
490 qg
.insert (borderPos
- half
, borderPos
+ half
, CPatchVertexInfo(zoneId
, l
, 5, borderPos
));
499 // Weld all the vertices !
501 for (l
= 0; l
< zoneInfos
.size(); ++l
)
503 CPatchInfo
&patch
= zoneInfos
[l
];
507 for (vert
= 0; vert
< 4; ++vert
)
509 // Not on an opened edge ?
510 if ( (patch
.BindEdges
[vert
].NPatchs
!= 0) && (patch
.BindEdges
[(vert
-1)&3].NPatchs
!= 0) )
515 // Get the vertex to weld
516 static TPVVect toWeld
;
517 CVector pos
= patch
.Patch
.Vertices
[vert
];
518 ::GetCandidateVertices (pos
, qg
, toWeld
, l
, zoneId
, weldThreshold
, false);
521 CVector
average (0,0,0);
523 bool absolutePosition
= false;
524 for (w
= 0; w
< toWeld
.size (); w
++)
527 if (toWeld
[w
]->PatchVertex
== 5)
529 absolutePosition
= true;
530 average
= toWeld
[w
]->Pos
;
534 if (!absolutePosition
)
535 average
+= toWeld
[w
]->Pos
;
538 float dist
= (pos
- toWeld
[w
]->Pos
).norm();
539 if ( (pos
- toWeld
[w
]->Pos
).sqrnorm() > 0.0001 )
544 if (!absolutePosition
)
545 average
/= (float)toWeld
.size ();
554 for (w
= 0; w
< toWeld
.size (); w
++)
556 if (toWeld
[w
]->PatchVertex
!= 5)
558 toWeld
[w
]->Pos
= average
;
559 zoneInfos
[toWeld
[w
]->PatchIndex
].Patch
.Vertices
[toWeld
[w
]->PatchVertex
] = average
;
568 printf ("Internal vertices welded: %d\n", weldCount
);
570 // Weld all the Tangents !
572 for (l
= 0; l
< zoneInfos
.size(); ++l
)
574 CPatchInfo
&patch
= zoneInfos
[l
];
578 for (edge
= 0; edge
< 4; ++edge
)
581 uint bindCount
= patch
.BindEdges
[edge
].NPatchs
;
582 if ( /*(bindCount == 1) || */(bindCount
== 5) )
585 uint otherPatch
= patch
.BindEdges
[edge
].Next
[0];
586 uint otherEdge
= patch
.BindEdges
[edge
].Edge
[0];
587 nlassert (otherPatch
<zoneInfos
.size ());
588 nlassert (otherEdge
<4);
592 A
= zoneInfos
[otherPatch
].Patch
.Vertices
[otherEdge
];
593 B
= zoneInfos
[otherPatch
].Patch
.Tangents
[otherEdge
*2];
594 C
= zoneInfos
[otherPatch
].Patch
.Tangents
[otherEdge
*2+1];
595 D
= zoneInfos
[otherPatch
].Patch
.Vertices
[(otherEdge
+1)&3];
599 uint otherCount
= getOtherCountAndPos (zoneInfos
, l
, edge
, otherPos
);
600 nlassert ( ( (bindCount
== 1) && (otherCount
== 1) ) || ( (bindCount
== 5) && ( (otherCount
== 2) || (otherCount
== 4) ) ) );
606 getFirst (A
, B
, C
, D
);
608 getSecond (A
, B
, C
, D
);
610 else if (otherCount
== 4)
614 getFirst (A
, B
, C
, D
);
615 getFirst (A
, B
, C
, D
);
617 else if (otherPos
== 1)
619 getFirst (A
, B
, C
, D
);
620 getSecond (A
, B
, C
, D
);
622 else if (otherPos
== 2)
624 getSecond (A
, B
, C
, D
);
625 getFirst (A
, B
, C
, D
);
627 else if (otherPos
== 3)
629 getSecond (A
, B
, C
, D
);
630 getSecond (A
, B
, C
, D
);
636 for (tang
=0; tang
<2; tang
++)
638 nlassert (2*edge
+tang
< 8);
640 // Eval the binded position
641 const CVector
&tangVect
= (tang
==0) ? C
: B
;
644 float dist
= (patch
.Patch
.Tangents
[2*edge
+tang
] - tangVect
).norm();
645 if ( (patch
.Patch
.Tangents
[2*edge
+tang
] - tangVect
).sqrnorm() > 0.0001 )
651 patch
.Patch
.Tangents
[2*edge
+tang
] += tangVect
;
652 patch
.Patch
.Tangents
[2*edge
+tang
] /= 2;
655 patch
.Patch
.Tangents
[2*edge
+tang
] = tangVect
;
662 printf ("Internal tangents welded: %d\n", weldCount
);