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 "surface_splitter.h"
20 using namespace NLMISC
;
21 using namespace NLPACS
;
23 // -----------------------
27 CSurfaceSplitter::CSurfaceSplitter()
33 void CSurfaceSplitter::build(CLocalRetriever
&lr
)
35 nlinfo("--- Build SurfaceSplitter...");
36 nlinfo("------------------------------------------");
45 for (i
=0; i
<lr
.getChains().size(); ++i
)
48 for (i
=0; i
<lr
.getSurfaces().size(); ++i
)
51 nlinfo("converted %d chains & %d surfaces", lr
.getChains().size(), lr
.getSurfaces().size());
52 _NumSurfaces
= (uint
)lr
.getSurfaces().size();
53 _NumChains
= (uint
)lr
.getChains().size();
59 nlinfo("------------------------------------------");
63 void CSurfaceSplitter::buildChain(CLocalRetriever
&lr
, uint chain
)
65 const NLPACS::CChain
&pacsChain
= lr
.getChain(chain
);
67 CSurfaceId left
= pacsChain
.getLeft() >= 0 ? CSurfaceId(0, (uint16
)pacsChain
.getLeft()) : CSurfaceId();
68 CSurfaceId right
= pacsChain
.getRight() >= 0 ? CSurfaceId(0, (uint16
)pacsChain
.getRight()) : CSurfaceId();
69 vector
<CVector2s64
> vertices
;
72 // walk through all subchains
73 for (i
=0; i
<pacsChain
.getSubChains().size(); ++i
)
75 uint ochain
= pacsChain
.getSubChain(i
);
76 const NLPACS::COrderedChain
&pacsOChain
= lr
.getOrderedChain(ochain
);
79 // walk through subchain, forward or backward
80 if (pacsOChain
.isForward())
82 for (j
=0; j
<(sint
)pacsOChain
.getVertices().size()-1; ++j
)
83 vertices
.push_back(CVector2s64(pacsOChain
[j
]));
87 for (j
=(sint
)pacsOChain
.getVertices().size()-1; j
>0; --j
)
88 vertices
.push_back(CVector2s64(pacsOChain
[j
]));
91 // add final chain point
92 if (i
== pacsChain
.getSubChains().size()-1)
93 vertices
.push_back(CVector2s64(pacsOChain
[j
]));
96 addChain(left
,right
, vertices
);
100 void CSurfaceSplitter::buildSurface(CLocalRetriever
&lr
, uint surface
)
102 const NLPACS::CRetrievableSurface
&pacsSurface
= lr
.getSurface(surface
);
105 newSurface
.Id
= CSurfaceId(0, surface
);
108 // walk through all loops
109 for (i
=0; i
<pacsSurface
.getLoops().size(); ++i
)
111 const NLPACS::CRetrievableSurface::TLoop
&pacsLoop
= pacsSurface
.getLoop(i
);
112 newSurface
.Loops
.push_back(CSurfaceSplitter::CLoop());
113 newSurface
.Loops
.back().Surface
= newSurface
.Id
;
117 for (j
=0; j
<pacsLoop
.size(); ++j
)
119 uint chainIndex
= pacsLoop
[j
];
120 uint chain
= pacsSurface
.getChain(chainIndex
).Chain
;
122 newSurface
.Loops
.back().Chains
.push_back(CChainId(chain
));
126 _Surfaces
.insert(make_pair(newSurface
.Id
, newSurface
));
132 void CSurfaceSplitter::initEdgeGrid()
134 _Edges
.create(256, 2.0f
);
139 void CSurfaceSplitter::splitChains()
141 nlinfo("Split chains...");
146 for (i
=0; i
<_NumChains
; ++i
)
148 TChainMap::iterator it
= _Chains
.find(CChainId(i
));
149 if (it
!= _Chains
.end())
150 splitChain(it
, numInters
);
153 nlinfo("%d intersections found", numInters
);
157 void CSurfaceSplitter::splitChain(TChainMap::iterator it
, uint
&numInters
)
159 CChain
&chain
= (*it
).second
;
165 // for each edge of the chain, test for other edges collision
166 for (edge
=0; edge
<chain
.Vertices
.size()-1; ++edge
)
168 CVector p0
= chain
.Vertices
[edge
].asVector();
169 CVector p1
= chain
.Vertices
[edge
+1].asVector();
174 _Edges
.select(pmin
, pmax
);
176 CFixed64
closerDist(10.0);
177 bool collisionFound
= false;
178 CEdgeId collidingEdge
;
179 CVector2s64 collision
;
181 TEdgeGrid::CIterator it
;
182 for (it
=_Edges
.begin(); it
!=_Edges
.end(); ++it
)
187 if (chain
.Id
== iedge
.Chain
&& (edge
== iedge
.Edge
|| edge
+1 == iedge
.Edge
|| edge
-1 == iedge
.Edge
))
190 CChain
*ichain
= getChain(iedge
.Chain
);
194 nlwarning("Couldn't find referenced chain %d", iedge
.Chain
.Id
);
198 if (ichain
->DontSplit
)
204 if (intersect(chain
.Vertices
[edge
], chain
.Vertices
[edge
+1], ichain
->Vertices
[iedge
.Edge
], ichain
->Vertices
[iedge
.Edge
+1], inters
, ndist
))
206 if (inters
!= chain
.Vertices
[edge
+1] || edge
!= chain
.Vertices
.size()-2)
209 nlinfo("Intersection: %d:%d[%.3f,%.3f-%.3f,%.3f]-%d:%d[%.3f,%.3f-%.3f,%.3f] : [%.3f,%.3f]", chain
.Id
.Id
, edge
, p0
.x
, p0
.y
, p1
.x
, p1
.y
, iedge
.Chain
.Id
, iedge
.Edge
, ichain
->Vertices
[iedge
.Edge
].asVector().x
, ichain
->Vertices
[iedge
.Edge
].asVector().y
, ichain
->Vertices
[iedge
.Edge
+1].asVector().x
, ichain
->Vertices
[iedge
.Edge
+1].asVector().y
, inters
.asVector().x
, inters
.asVector().y
);
211 if (closerDist
> ndist
)
213 collisionFound
= true;
214 collidingEdge
= iedge
;
220 nlinfo("Intersection: %d:%d[%.3f,%.3f-%.3f,%.3f]-%d:%d[%.3f,%.3f-%.3f,%.3f] : [%.3f,%.3f] -- SKIPPED", chain
.Id
.Id
, edge
, p0
.x
, p0
.y
, p1
.x
, p1
.y
, iedge
.Chain
.Id
, iedge
.Edge
, ichain
->Vertices
[iedge
.Edge
].asVector().x
, ichain
->Vertices
[iedge
.Edge
].asVector().y
, ichain
->Vertices
[iedge
.Edge
+1].asVector().x
, ichain
->Vertices
[iedge
.Edge
+1].asVector().y
, inters
.asVector().x
, inters
.asVector().y
);
228 if (chain
.Id
== collidingEdge
.Chain
)
230 // self colliding chain
233 //nlassert(edge >= 0); // always true for unsigned
234 nlassert(edge
< collidingEdge
.Edge
);
235 nlassert(collidingEdge
.Edge
< chain
.Vertices
.size()-1);
237 // must split the chain in 3 parts
239 vector
<CVector2s64
> begin
;
240 vector
<CVector2s64
> middle
;
241 vector
<CVector2s64
> end
;
247 for (e
=0; e
<=edge
; ++e
)
248 begin
.push_back(chain
.Vertices
[e
]);
250 begin
.push_back(collision
);
252 if (collision
!= chain
.Vertices
[e
])
253 middle
.push_back(collision
);
255 for (; e
<=collidingEdge
.Edge
; ++e
)
256 middle
.push_back(chain
.Vertices
[e
]);
258 middle
.push_back(collision
);
260 if (collision
!= chain
.Vertices
[e
])
261 end
.push_back(collision
);
263 for (; e
<chain
.Vertices
.size(); ++e
)
264 end
.push_back(chain
.Vertices
[e
]);
266 beginId
= addChain(chain
.Left
, chain
.Right
, begin
, true);
267 middleId
= addChain(chain
.Left
, chain
.Right
, middle
);
268 endId
= addChain(chain
.Left
, chain
.Right
, end
);
270 v
.push_back(beginId
);
271 v
.push_back(middleId
);
274 replaceChain(chain
.Id
, v
);
278 //nlassert(edge >= 0); // always true for unsigned
279 nlassert(edge
< chain
.Vertices
.size()-1);
283 vector
<CVector2s64
> begin
;
284 vector
<CVector2s64
> end
;
289 // split the first chain
290 for (e
=0; e
<=edge
; ++e
)
291 begin
.push_back(chain
.Vertices
[e
]);
293 begin
.push_back(collision
);
295 if (collision
!= chain
.Vertices
[e
])
296 end
.push_back(collision
);
298 for (; e
<chain
.Vertices
.size(); ++e
)
299 end
.push_back(chain
.Vertices
[e
]);
301 beginId
= addChain(chain
.Left
, chain
.Right
, begin
, true);
302 endId
= addChain(chain
.Left
, chain
.Right
, end
);
304 v
.push_back(beginId
);
307 replaceChain(chain
.Id
, v
);
309 // reset for second chain
314 // split the second chain
315 CChain
*collide
= getChain(collidingEdge
.Chain
);
317 for (e
=0; e
<=collidingEdge
.Edge
; ++e
)
318 begin
.push_back(collide
->Vertices
[e
]);
320 begin
.push_back(collision
);
322 if (collision
!= collide
->Vertices
[e
])
323 end
.push_back(collision
);
325 for (; e
<collide
->Vertices
.size(); ++e
)
326 end
.push_back(collide
->Vertices
[e
]);
328 beginId
= addChain(collide
->Left
, collide
->Right
, begin
);
329 endId
= addChain(collide
->Left
, collide
->Right
, end
);
331 v
.push_back(beginId
);
334 replaceChain(collide
->Id
, v
);
343 bool CSurfaceSplitter::intersect(const CVector2s64
&v0
, const CVector2s64
&v1
,
344 const CVector2s64
&c0
, const CVector2s64
&c1
,
345 CVector2s64
&intersect
,
348 if (v0
== c0
|| v0
== c1
)
351 if (v1
== c0
|| v1
== c1
)
354 ndist
= CFixed64(1.0);
358 CVector2s64
nnc(c0
.y
-c1
.y
, c1
.x
-c0
.x
),
359 nnv(v0
.y
-v1
.y
, v1
.x
-v0
.x
);
361 CFixed64 dv
= (v1
-v0
)*nnc
;
363 // vectors are colinears ?
367 CFixed64 nv
= (c0
-v0
)*nnc
;
371 // intersection outside main edge ? (or at first point ?)
372 if ((sint64
)nv
<=0 || nv
>dv
)
375 CFixed64 dc
= (c1
-c0
)*(c1
-c0
);
376 // second edge null ?
385 CFixed64 nc
= (v0
-c0
+ (v1
-v0
)*lv
)*(c1
-c0
);
386 // intersection outside colliding edge ?
387 if ((sint64
)nc
<0 || nc
>dc
)
390 // treat each singular case
393 else if ((sint64
)nc
== 0)
398 // compute intersecting point
399 intersect
= v0
+ (v1
-v0
)*lv
;
409 CSurfaceSplitter::CChainId
CSurfaceSplitter::addChain(const CSurfaceId
&left
, const CSurfaceId
&right
, const vector
<CVector2s64
> &points
, bool dontSplit
)
411 pair
<TChainMap::iterator
, bool> res
= _Chains
.insert(make_pair(CChainId(_NumChains
++), CChain()));
413 CChain
&chain
= (*(res
.first
)).second
;
415 chain
.Id
= (*(res
.first
)).first
;
420 for (i
=0; i
<points
.size()-1; ++i
)
422 if (points
[i
] == points
[i
+1])
424 nlwarning("--- !! points are together !! ---");
429 chain
.Vertices
= points
;
430 chain
.DontSplit
= dontSplit
;
433 for (edge
=0; edge
<chain
.Vertices
.size()-1; ++edge
)
435 CVector p0
= chain
.Vertices
[edge
].asVector();
436 CVector p1
= chain
.Vertices
[edge
+1].asVector();
445 chain
.Iterators
.push_back(_Edges
.insert(pmin
, pmax
, CEdgeId(chain
.Id
, edge
)));
452 void CSurfaceSplitter::removeChain(CChainId chainId
)
455 TChainMap::iterator it
= _Chains
.find(chainId
);
457 if (it
== _Chains
.end())
460 CChain
&chain
= (*it
).second
;
464 if ((surf
= getSurface(chain
.Left
)))
465 surf
->removeChain(chainId
);
467 if ((surf
= getSurface(chain
.Right
)))
468 surf
->removeChain(chainId
);
472 void CSurfaceSplitter::replaceChain(CChainId chainId
, const vector
<CChainId
> &chains
)
475 TChainMap::iterator it
= _Chains
.find(chainId
);
477 if ((it
== _Chains
.end()))
480 CChain
&chain
= (*it
).second
;
484 nlinfo("-- Replace --");
488 for (c
=0; c
<chains
.size(); ++c
)
489 dumpChain(chains
[c
]);
490 nlinfo("-- End Replace --");
492 if ((surf
= getSurface(chain
.Left
)))
495 for (loop
=0; loop
<surf
->Loops
.size(); ++loop
)
497 CLoop
&ploop
= surf
->Loops
[loop
];
498 vector
<CChainId
>::iterator it
;
499 for (it
=ploop
.Chains
.begin(); it
!=ploop
.Chains
.end(); ++it
)
503 it
= ploop
.Chains
.erase(it
);
505 for (i
=(sint
)chains
.size()-1; i
>=0; --i
)
507 it
= ploop
.Chains
.insert(it
, chains
[i
]);
514 if ((surf
= getSurface(chain
.Right
)))
517 for (loop
=0; loop
<surf
->Loops
.size(); ++loop
)
519 CLoop
&ploop
= surf
->Loops
[loop
];
520 vector
<CChainId
>::iterator it
;
521 for (it
=ploop
.Chains
.begin(); it
!=ploop
.Chains
.end(); ++it
)
525 it
= ploop
.Chains
.erase(it
);
527 for (i
=0; i
<chains
.size(); ++i
)
529 it
= ploop
.Chains
.insert(it
, chains
[i
]);
537 for (i
=0; i
<chain
.Iterators
.size(); ++i
)
538 _Edges
.erase(chain
.Iterators
[i
]);