!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / Sandbox / Plugins / LodGeneratorPlugin / Util / TopologyBuilder.cpp
blobe95c197bc3d6796223797b52eb5836e43fb2e41e
1 #include "StdAfx.h"
2 #include "TopologyBuilder.h"
4 namespace LODGenerator
6 struct FacetKey
8 FacetKey(CVertex* a1, CVertex* a2, CVertex* a3)
10 v1 = a1; v2 = a2; v3 = a3;
12 bool operator<(const FacetKey& rhs) const
14 if(v1 < rhs.v1) { return true; }
15 if(v1 > rhs.v1) { return false; }
16 if(v2 < rhs.v2) { return true; }
17 if(v2 > rhs.v2) { return false; }
18 return (v3 < rhs.v3);
20 CVertex* v1;
21 CVertex* v2;
22 CVertex* v3;
25 static std::set<FacetKey>* all_facet_keys;
26 void CTopologyBuilder::begin_surface()
28 transition(eS_Initial, eS_Surface);
30 nb_non_manifold_v_ = 0;
31 nb_duplicate_e_ = 0;
32 nb_isolated_v_ = 0;
33 all_facet_keys = new std::set<FacetKey>;
36 void CTopologyBuilder::clear()
38 vertex_.clear();
39 tex_vertex_.clear();
42 void CTopologyBuilder::end_surface(bool remove)
44 delete all_facet_keys; all_facet_keys = NULL;
45 transition(eS_Surface, eS_Final);
46 terminate_surface();
47 if(remove)
49 vertex_.clear();
50 tex_vertex_.clear();
53 if(!quiet_ && (nb_non_manifold_v_ != 0))
55 CryLog("MapBuilder Encountered non-manifold vertices (fixed)");
57 if(!quiet_ && (nb_duplicate_e_ != 0))
59 CryLog("MapBuilder Encountered duplicated edges (fixed)");
61 if(!quiet_ && (nb_isolated_v_ != 0))
63 CryLog("MapBuilder Encountered isolated vertices (removed)");
67 void CTopologyBuilder::reset()
69 transition(eS_Final, eS_Initial);
72 void CTopologyBuilder::add_vertex(unsigned int id, const Vec3d& p)
74 transition(eS_Surface, eS_Surface);
75 add_vertex_internal(id, p);
78 void CTopologyBuilder::add_vertex(const Vec3d& p)
80 transition(eS_Surface, eS_Surface);
81 add_vertex_internal(p);
84 void CTopologyBuilder::add_tex_vertex(const Vec2d& p)
86 add_tex_vertex(tex_vertex_.size(), p);
89 void CTopologyBuilder::add_tex_vertex(unsigned int id, const Vec2d& p)
91 transition(eS_Surface, eS_Surface);
92 std::shared_ptr<CTexVertex>& new_tv = std::shared_ptr<CTexVertex>(target_->new_tex_vertex());
93 new_tv-> set_tex_coord(p);
94 while(tex_vertex_.size() <= id) {
95 tex_vertex_.push_back(NULL);
97 tex_vertex_[id] = new_tv;
100 void CTopologyBuilder::add_vertex_internal(unsigned int id, const Vec3d& p)
102 CVertex* new_v = target_->new_vertex();
103 new_v-> set_point(p);
104 while(vertex_.size() <= id) {
105 vertex_.push_back(NULL);
107 vertex_[id] = new_v;
111 void CTopologyBuilder::add_vertex_internal(const Vec3d& p)
113 add_vertex_internal(vertex_.size(), p);
116 void CTopologyBuilder::begin_facet() {
117 facet_vertex_.clear();
118 facet_tex_vertex_.clear();
121 void CTopologyBuilder::end_facet()
123 assert(facet_vertex_.size() == facet_tex_vertex_.size());
124 int nb_vertices = facet_vertex_.size();
126 if(nb_vertices < 3)
128 if(!quiet_)
130 CryLog("MapBuilder Facet with less than 3 vertices");
132 return;
135 if(false && nb_vertices == 3)
137 std::vector<CVertex*> W = facet_vertex_;
138 std::sort(W.begin(), W.end());
139 FacetKey k(W[0], W[1],W[2]);
140 if(all_facet_keys->find(k) != all_facet_keys->end())
142 //std::cerr << '.' << std::flush;
143 return;
145 all_facet_keys->insert(k);
149 // Detect duplicated vertices
150 for(int i=0; i<nb_vertices; i++)
152 for(int j=i+1; j<nb_vertices; j++)
154 if(facet_vertex_[i] == facet_vertex_[j])
156 if(!quiet_)
158 CryLog("MapBuilder Duplicated vertex in facet, ignoring facet");
160 return;
165 // Detect and remove non-manifold edges by duplicating
166 // the corresponding vertices.
167 for(int from=0; from<nb_vertices; from++)
169 int to=((from+1) % nb_vertices);
170 if(find_halfedge_between(facet_vertex_[from], facet_vertex_[to]) != NULL )
172 nb_duplicate_e_++;
173 facet_vertex_[from] = copy_vertex(facet_vertex_[from]);
174 facet_vertex_[to] = copy_vertex(facet_vertex_[to]);
179 begin_facet_internal();
180 for(int i=0; i<nb_vertices; i++)
182 add_vertex_to_facet_internal(facet_vertex_[i]);
183 if(facet_tex_vertex_[i] != NULL)
185 set_corner_tex_vertex_internal(facet_tex_vertex_[i]);
188 end_facet_internal();
192 CVertex* CTopologyBuilder::copy_vertex(CVertex* from)
194 // Note: tex coords are not copied, since
195 // an halfedge does not exist in the copy to
196 // store the texvertex pointer.
198 CVertex* result = target_->new_vertex();
199 result->set_point(from->point());
200 if(is_locked_[from])
202 is_locked_[result] = true;
204 return result;
207 void CTopologyBuilder::add_vertex_to_facet(int i)
209 if(i < 0 || i >= int(vertex_.size()))
211 if(!quiet_)
213 CryLog("MapBuilder vertex index %d out of range",i);
215 return;
217 facet_vertex_.push_back(vertex_[i]);
218 facet_tex_vertex_.push_back(NULL);
221 void CTopologyBuilder::set_corner_tex_vertex(int i)
223 if(i < 0 || i >= int(tex_vertex_.size()))
225 if(!quiet_) {
226 // CryLog("MapBuilder") << "texvertex index "
227 // << i << " out of range"
228 // << std::endl;
230 return;
232 *(facet_tex_vertex_.rbegin()) = tex_vertex_[i];
235 void CTopologyBuilder::lock_vertex(int i)
237 if(i < 0 || i >= int(vertex_.size()))
239 if(!quiet_)
241 CryLog("MapBuilder vertex index %d out of range",i);
243 return;
245 is_locked_[vertex(i)] = true;
248 void CTopologyBuilder::unlock_vertex(int i)
250 if(i < 0 || i >= int(vertex_.size()))
252 if(!quiet_)
254 CryLog("MapBuilder vertex index %d out of range",i);
256 return;
258 is_locked_[vertex(i)] = false;
261 void CTopologyBuilder::begin_facet_internal()
263 transition(eS_Surface, eS_Facet);
264 current_facet_ = target_->new_facet();
265 first_vertex_in_facet_ = NULL;
266 current_vertex_ = NULL;
267 first_halfedge_in_facet_ = NULL;
268 current_halfedge_ = NULL;
269 first_tex_vertex_in_facet_ = NULL;
272 void CTopologyBuilder::end_facet_internal()
274 transition(eS_Facet, eS_Surface);
275 CHalfedge* h = new_halfedge_between(current_vertex_, first_vertex_in_facet_);
277 CTopologyGraphMutator::link(current_halfedge_, h, 1);
278 CTopologyGraphMutator::link(h, first_halfedge_in_facet_, 1);
279 if(first_tex_vertex_in_facet_ != NULL)
281 CTopologyGraphMutator::set_halfedge_tex_vertex(h, std::shared_ptr<CTexVertex>(first_tex_vertex_in_facet_));
285 void CTopologyBuilder::add_vertex_to_facet_internal(CVertex* v)
287 transition(eS_Facet, eS_Facet);
289 if(first_vertex_in_facet_ == NULL)
291 first_vertex_in_facet_ = v;
293 else
295 CHalfedge* new_halfedge = new_halfedge_between(current_vertex_, v);
297 if(first_halfedge_in_facet_ == NULL)
299 first_halfedge_in_facet_ = new_halfedge;
300 CTopologyGraphMutator::make_facet_key(first_halfedge_in_facet_);
302 else
304 CTopologyGraphMutator::link(current_halfedge_, new_halfedge, 1);
306 current_halfedge_ = new_halfedge;
308 current_vertex_ = v;
311 void CTopologyBuilder::set_corner_tex_vertex_internal(std::shared_ptr<CTexVertex>& tv)
313 transition(eS_Facet, eS_Facet);
314 if(current_halfedge_ == NULL)
316 first_tex_vertex_in_facet_ = tv;
318 else
320 CTopologyGraphMutator::set_halfedge_tex_vertex(current_halfedge_, tv);
325 CVertex* CTopologyBuilder::current_vertex()
327 return vertex_[vertex_.size() - 1];
330 CVertex* CTopologyBuilder::vertex(int i)
332 return vertex_[i];
335 std::shared_ptr<CTexVertex>& CTopologyBuilder::current_tex_vertex()
337 return tex_vertex_[tex_vertex_.size() - 1];
340 std::shared_ptr<CTexVertex>& CTopologyBuilder::tex_vertex(int i)
342 return tex_vertex_[i];
345 CFacet* CTopologyBuilder::current_facet()
347 return current_facet_;
350 CHalfedge* CTopologyBuilder::new_halfedge_between(CVertex* from, CVertex* to)
352 assert(from != to);
354 // Non-manifold edges have been removed
355 // by the higher level public functions.
356 // Let us do a sanity check anyway ...
357 assert(find_halfedge_between(from, to) == NULL);
359 CHalfedge* result = target_->new_halfedge();
360 CTopologyGraphMutator::set_halfedge_facet(result, current_facet_);
361 CTopologyGraphMutator::set_halfedge_vertex(result, to);
363 CHalfedge* opposite = find_halfedge_between(to, from);
364 if(opposite != NULL) {
365 CTopologyGraphMutator::link(result, opposite, 2);
368 star_[from].push_back(result);
369 CTopologyGraphMutator::set_vertex_halfedge(to, result);
371 return result;
374 CHalfedge* CTopologyBuilder::find_halfedge_between(CVertex* from, CVertex* to)
376 Star& star = star_[from];
377 for(Star::iterator it = star.begin(); it != star.end(); it++)
379 CHalfedge* cur = *it;
380 if(cur-> vertex() == to)
381 return cur;
383 return NULL;
386 bool CTopologyBuilder::vertex_is_manifold(CVertex* v)
388 if(v->halfedge() == NULL)
390 // Isolated vertex, removed in subsequent steps
391 return true;
394 // A vertex is manifold if the stored and the
395 // computed stars match (the number of halfedges
396 // are tested).
397 // Note: this test is valid only if the borders
398 // have been constructed.
400 return (int(star_[v].size()) == v->degree());
403 bool CTopologyBuilder::split_non_manifold_vertex(CVertex* v)
405 if(vertex_is_manifold(v))
407 return false;
410 std::set<CHalfedge*> star;
411 for(unsigned int i=0; i<star_[v].size(); i++)
413 star.insert(star_[v][i]);
416 // For the first wedge, reuse the vertex
417 disconnect_vertex(v->halfedge()->opposite(), v, star);
419 // There should be other wedges (else the vertex
420 // would have been manifold)
421 assert(!star.empty());
424 is_locked[v] = true;
425 // Create the vertices for the remaining wedges.
426 while(!star.empty())
428 CVertex* new_v = copy_vertex(v);
429 is_locked[new_v] = true;
430 CHalfedge* h = *(star.begin());
431 disconnect_vertex(h, new_v, star);
435 return true;
439 void CTopologyBuilder::disconnect_vertex(CHalfedge* start_in, CVertex* v, std::set<CHalfedge*>& star)
441 CHalfedge* start = start_in;
443 star_[v].clear();
445 // Important note: in this class, all the Stars correspond to the
446 // set of halfedges radiating FROM a vertex (i.e. h->vertex() != v
447 // if h belongs to Star(v) ).
449 assert(star.find(start) != star.end());
452 // Note: the following code needs a special handling
453 // of borders, since borders are not correctly connected
454 // in a non-manifold vertex (the standard next_around_vertex
455 // iteration does not traverse the whole star)
457 while(!start->is_border())
459 start = start->prev()->opposite();
460 if(start == start_in)
461 break;
463 CTopologyGraphMutator::set_vertex_halfedge(v,start->opposite());
465 CHalfedge* cur = start;
466 CTopologyGraphMutator::set_halfedge_vertex(cur->opposite(), v);
467 star_[v].push_back(cur);
468 std::set<CHalfedge*>::iterator it = star.find(cur);
469 assert(it != star.end());
470 star.erase(it);
472 while(!cur->opposite()->is_border())
474 cur = cur->opposite()->next();
475 if(cur == start)
476 break;
477 CTopologyGraphMutator::set_halfedge_vertex(cur->opposite(), v);
478 std::set<CHalfedge*>::iterator it = star.find(cur);
479 assert(it != star.end());
480 star.erase(it);
481 star_[v].push_back(cur);
484 if(start->is_border())
486 CTopologyGraphMutator::link(cur->opposite(),start,1);
491 void CTopologyBuilder::terminate_surface()
494 // Step 1 : create the border halfedges, and setup the 'opposite'
495 // and 'vertex' pointers.
496 std::vector<CHalfedge*> halfedgelist;
497 FOR_EACH_HALFEDGE(CTopologyGraph, target_, it)
499 halfedgelist.push_back(*it);
501 for (std::vector<CHalfedge*>::iterator it = halfedgelist.begin();it!= halfedgelist.end();it++)
503 if((*it)-> opposite() == NULL)
505 CHalfedge* h = target_->new_halfedge();
506 CTopologyGraphMutator::link(h, *it, 2);
507 CTopologyGraphMutator::set_halfedge_vertex(h, (*it)-> prev()-> vertex());
509 // Initialize texture coordinates
510 CTopologyGraphMutator::set_halfedge_tex_vertex(h, (*it)-> prev()-> tex_vertex());
512 // Used later to fix non-manifold vertices.
513 star_[ (*it)-> vertex() ].push_back(h);
517 // Step 2 : setup the 'next' and 'prev' pointers of the border.
519 FOR_EACH_HALFEDGE(CTopologyGraph, target_, it)
521 if((*it)-> facet() == NULL)
524 CHalfedge* next = (*it)-> opposite();
525 while(next-> facet() != NULL)
527 next = next-> prev()-> opposite();
529 CTopologyGraphMutator::set_halfedge_next(*it, next);
531 CHalfedge* prev = (*it)-> opposite();
532 while(prev-> facet() != NULL)
534 prev = prev-> next()-> opposite();
536 CTopologyGraphMutator::set_halfedge_prev(*it, prev);
540 // Step 3 : fix non-manifold vertices
542 for(unsigned int i=0; i<vertex_.size(); i++)
544 if(vertex_[i] == NULL) {
545 continue;
547 if(split_non_manifold_vertex(vertex_[i]))
549 nb_non_manifold_v_++;
554 // Step 4 : create TexVertices
556 FOR_EACH_HALFEDGE(CTopologyGraph, target_, it)
558 if((*it)->tex_vertex() == NULL)
560 std::shared_ptr<CTexVertex>& new_tv = std::shared_ptr<CTexVertex>(target_->new_tex_vertex());
561 CHalfedge* cur = *it;
564 CTopologyGraphMutator::set_halfedge_tex_vertex(cur, new_tv);
565 cur = cur-> next()-> opposite();
567 while(cur-> tex_vertex() == NULL);
568 cur = (*it)-> opposite()-> prev();
569 while((*it)-> tex_vertex() == NULL)
571 CTopologyGraphMutator::set_halfedge_tex_vertex(cur, new_tv);
572 cur = cur-> opposite()-> prev();
577 // Step 5 : check for isolated vertices
578 for(unsigned int i=0; i<vertex_.size(); i++)
580 if(vertex_[i] == NULL)
582 continue;
584 if(star_[vertex_[i]].size() == 0)
586 nb_isolated_v_++;
587 target_->delete_vertex(vertex_[i]);
591 target_->assert_is_valid();
594 void CTopologyBuilder::transition(EState from, EState to)
596 check_state(from);
597 state_ = to;
600 void CTopologyBuilder::check_state(EState s)
602 if(state_ != s)
604 CryLog("MapBuilder invalid state: '%s' , expected '%s'",state_to_string(state_),state_to_string(s));
605 bool ok = false;
606 assert(ok);
610 std::string CTopologyBuilder::state_to_string(EState s)
612 switch(s)
614 case eS_Initial:
615 return "initial";
616 case eS_Surface:
617 return "surface";
618 case eS_Facet:
619 return "facet";
620 case eS_Final:
621 return "final";
622 default:
623 return "unknown";
625 return "unknown";
628 void CTopologyBuilder::set_vertex(unsigned int v, const Vec3d& p)
630 vertex(v)->set_point(p);
634 void CTopologyBuilder::create_vertices(unsigned int nb_v, bool with_colors)
636 for(unsigned int i=0; i<nb_v; i++)
638 add_vertex(Vec3d(0.0, 0.0, 0.0)) ;