Panda3D
eggVertexPool.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file eggVertexPool.cxx
10  * @author drose
11  * @date 1999-01-16
12  */
13 
14 #include "eggVertexPool.h"
15 #include "eggPrimitive.h"
16 #include "eggUtilities.h"
17 #include <iterator>
18 
19 #include "indent.h"
20 
21 #include <iterator>
22 
23 using std::string;
24 
25 TypeHandle EggVertexPool::_type_handle;
26 
27 /**
28  *
29  */
30 EggVertexPool::
31 EggVertexPool(const string &name) : EggNode(name) {
32  _highest_index = -1;
33 }
34 
35 /**
36  * Copying a vertex pool is of questionable value, since it will copy all of
37  * the vertices and assign new pointers to them all. There will be no
38  * polygons referring to the new vertices.
39  */
40 EggVertexPool::
41 EggVertexPool(const EggVertexPool &copy) : EggNode(copy) {
42  iterator i;
43  for (i = copy.begin(); i != copy.end(); ++i) {
44  add_vertex(new EggVertex(*(*i)), (*i)->get_index());
45  }
46 }
47 
48 
49 /**
50  *
51  */
52 EggVertexPool::
53 ~EggVertexPool() {
54  // Remove all vertices from the pool when it destructs.
55 
56  // Sanity check.
57  nassertv(_index_vertices.size() == _unique_vertices.size());
58 
59  IndexVertices::iterator ivi;
60  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
61  int index = (*ivi).first;
62  EggVertex *vertex = (*ivi).second;
63 
64  // Sanity checks on our internal data structures.
65  nassertv(vertex->_pool == this);
66  nassertv(vertex->get_index() == index);
67 
68  vertex->_pool = nullptr;
69  vertex->_index = -1;
70  }
71 
72  _index_vertices.clear();
73  _unique_vertices.clear();
74 }
75 
76 /**
77  * Returns true if any vertices in the pool are undefined forward-reference
78  * vertices, false if all vertices are defined.
79  */
80 bool EggVertexPool::
82  IndexVertices::const_iterator ivi;
83  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
84  EggVertex *vertex = (*ivi).second;
85  if (vertex->is_forward_reference()) {
86  return true;
87  }
88  }
89 
90  return false;
91 }
92 
93 /**
94  * Returns true if any vertices in the pool are fully defined vertices, false
95  * if all vertices are forward references.
96  */
97 bool EggVertexPool::
99  IndexVertices::const_iterator ivi;
100  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
101  EggVertex *vertex = (*ivi).second;
102  if (!vertex->is_forward_reference()) {
103  return true;
104  }
105  }
106 
107  return false;
108 }
109 
110 /**
111  * Returns the vertex in the pool with the indicated index number, or NULL if
112  * no vertices have that index number.
113  */
115 get_vertex(int index) const {
116  IndexVertices::const_iterator ivi = _index_vertices.find(index);
117 
118  if (ivi == _index_vertices.end()) {
119  return nullptr;
120  } else {
121  EggVertex *vertex = (*ivi).second;
122  if (vertex->is_forward_reference()) {
123  return nullptr;
124  }
125  return vertex;
126  }
127 }
128 
129 /**
130  * Returns the vertex in the pool with the indicated index number. If there
131  * is not a vertex in the pool with the indicated index number, creates a
132  * special forward-reference EggVertex that has no data, on the assumption
133  * that the vertex pool has not yet been fully read and more data will be
134  * available later.
135  */
137 get_forward_vertex(int index) {
138  nassertr(index >= 0, nullptr);
139 
140  IndexVertices::const_iterator ivi = _index_vertices.find(index);
141 
142  if (ivi == _index_vertices.end()) {
143  PT(EggVertex) forward = new EggVertex;
144  forward->_forward_reference = true;
145  return add_vertex(forward, index);
146  } else {
147  return (*ivi).second;
148  }
149 }
150 
151 /**
152  * Returns the highest index number used by any vertex in the pool (except
153  * forward references). Returns -1 if the pool is empty.
154  */
155 int EggVertexPool::
157  return _highest_index;
158 }
159 
160 /**
161  * Artificially changes the "highest index number", so that a newly created
162  * vertex will begin at this number plus 1. This can be used to default a
163  * vertex pool to start counting at 1 (or any other index number), instead of
164  * the default of 0. Use with caution.
165  */
166 void EggVertexPool::
167 set_highest_index(int highest_index) {
168  _highest_index = highest_index;
169 }
170 
171 /**
172  * Returns the maximum number of dimensions used by any vertex in the pool.
173  */
174 int EggVertexPool::
176  int num_dimensions = 0;
177 
178  IndexVertices::const_iterator ivi;
179  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
180  EggVertex *vertex = (*ivi).second;
181  num_dimensions = std::max(num_dimensions, vertex->get_num_dimensions());
182  }
183 
184  return num_dimensions;
185 }
186 
187 /**
188  * Returns true if any vertex in the pool has a normal defined, false if none
189  * of them do.
190  */
191 bool EggVertexPool::
192 has_normals() const {
193  IndexVertices::const_iterator ivi;
194  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
195  EggVertex *vertex = (*ivi).second;
196  if (vertex->has_normal()) {
197  return true;
198  }
199  }
200 
201  return false;
202 }
203 
204 /**
205  * Returns true if any vertex in the pool has a color defined, false if none
206  * of them do.
207  */
208 bool EggVertexPool::
209 has_colors() const {
210  IndexVertices::const_iterator ivi;
211  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
212  EggVertex *vertex = (*ivi).second;
213  if (vertex->has_color()) {
214  return true;
215  }
216  }
217 
218  return false;
219 }
220 
221 /**
222  * Returns true if any vertex in the pool has a color defined other than
223  * white, false if no vertices have colors, or if all colors are white.
224  */
225 bool EggVertexPool::
227  IndexVertices::const_iterator ivi;
228  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
229  EggVertex *vertex = (*ivi).second;
230  if (vertex->has_color() &&
231  (vertex->get_color() != LColor(1.0, 1.0, 1.0, 1.0) ||
232  !vertex->_drgbas.empty())) {
233  return true;
234  }
235  }
236 
237  return false;
238 }
239 
240 /**
241  * Scans the vertex pool for different colors on different vertices. If all
242  * vertices are the same color, sets has_overall_color to true and fills the
243  * color into overall_color. If no vertices have any color, set
244  * has_overall_color to true and fills white into overall_color. If at least
245  * two vertices have different colors, sets has_overall_color to false.
246  */
247 void EggVertexPool::
248 check_overall_color(bool &has_overall_color, LColor &overall_color) const {
249  if (empty()) {
250  has_overall_color = true;
251  overall_color.set(1.0f, 1.0f, 1.0f, 1.0f);
252  return;
253  }
254 
255  IndexVertices::const_iterator ivi;
256  ivi = _index_vertices.begin();
257  EggVertex *vertex = (*ivi).second;
258  overall_color = vertex->get_color();
259 
260  ++ivi;
261  while (ivi != _index_vertices.end()) {
262  vertex = (*ivi).second;
263  if (!vertex->get_color().almost_equal(overall_color)) {
264  has_overall_color = false;
265  return;
266  }
267  ++ivi;
268  }
269 
270  has_overall_color = true;
271 }
272 
273 /**
274  * Returns true if any vertex in the pool has a uv defined, false if none of
275  * them do.
276  */
277 bool EggVertexPool::
278 has_uvs() const {
279  IndexVertices::const_iterator ivi;
280  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
281  EggVertex *vertex = (*ivi).second;
282  if (vertex->has_uv()) {
283  return true;
284  }
285  }
286 
287  return false;
288 }
289 
290 /**
291  * Returns true if any vertex in the pool has auxiliary data defined, false if
292  * none of them do.
293  */
294 bool EggVertexPool::
295 has_aux() const {
296  IndexVertices::const_iterator ivi;
297  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
298  EggVertex *vertex = (*ivi).second;
299  if (vertex->has_aux()) {
300  return true;
301  }
302  }
303 
304  return false;
305 }
306 
307 /**
308  * Returns the list of UV names that are defined by any vertices in the pool,
309  * as well as the subset of UV names that actually define 3-d texture
310  * coordinates ("uvw_names"). Also returns the subset of UV/UVW names that
311  * define a tangent and binormal. It is the user's responsibility to clear
312  * both vectors before calling this method.
313  */
314 void EggVertexPool::
315 get_uv_names(vector_string &uv_names, vector_string &uvw_names,
316  vector_string &tbn_names) const {
317  pset<string> uv_names_set, uvw_names_set, tbn_names_set;
318  IndexVertices::const_iterator ivi;
319  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
320  EggVertex *vertex = (*ivi).second;
322  for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
323  EggVertexUV *uv_obj = (*uvi);
324  uv_names_set.insert(uv_obj->get_name());
325  if (uv_obj->has_w()) {
326  uvw_names_set.insert(uv_obj->get_name());
327  }
328  if (uv_obj->has_tangent() && uv_obj->has_binormal()) {
329  tbn_names_set.insert(uv_obj->get_name());
330  }
331  }
332  }
333 
335  for (si = uv_names_set.begin(); si != uv_names_set.end(); ++si) {
336  uv_names.push_back(*si);
337  }
338  for (si = uvw_names_set.begin(); si != uvw_names_set.end(); ++si) {
339  uvw_names.push_back(*si);
340  }
341  for (si = tbn_names_set.begin(); si != tbn_names_set.end(); ++si) {
342  tbn_names.push_back(*si);
343  }
344 }
345 
346 /**
347  * Returns the list of auxiliary data names that are defined by any vertices
348  * in the pool.
349  */
350 void EggVertexPool::
351 get_aux_names(vector_string &aux_names) const {
352  pset<string> aux_names_set;
353  IndexVertices::const_iterator ivi;
354  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
355  EggVertex *vertex = (*ivi).second;
357  for (uvi = vertex->aux_begin(); uvi != vertex->aux_end(); ++uvi) {
358  EggVertexAux *aux_obj = (*uvi);
359  aux_names_set.insert(aux_obj->get_name());
360  }
361  }
362 
364  for (si = aux_names_set.begin(); si != aux_names_set.end(); ++si) {
365  aux_names.push_back(*si);
366  }
367 }
368 
369 /**
370  * Returns an iterator that can be used to traverse through all the vertices
371  * in the pool.
372  */
374 begin() const {
375  nassertr(_index_vertices.size() == _unique_vertices.size(),
376  iterator(_index_vertices.begin()));
377  return iterator(_index_vertices.begin());
378 }
379 
380 /**
381  * Returns an iterator that can be used to traverse through all the vertices
382  * in the pool.
383  */
385 end() const {
386  return iterator(_index_vertices.end());
387 }
388 
389 /**
390  * Returns true if the pool is empty.
391  */
392 bool EggVertexPool::
393 empty() const {
394  return _index_vertices.empty();
395 }
396 
397 /**
398  * Returns the number of vertices in the pool.
399  */
400 EggVertexPool::size_type EggVertexPool::
401 size() const {
402  nassertr(_index_vertices.size() == _unique_vertices.size(), 0);
403  return _index_vertices.size();
404 }
405 
406 /**
407  * Adds the indicated vertex to the pool. It is an error if the vertex is
408  * already a member of this or any other pool. The vertex must have been
409  * allocated from the free store; its pointer will now be owned by the vertex
410  * pool. If the index number is supplied, tries to assign that index number;
411  * it is an error if the index number is already in use.
412  *
413  * It is possible that a forward reference to this vertex was requested in the
414  * past; if so, the data from the supplied vertex is copied onto the forward
415  * reference, which becomes the actual vertex. In this case, a different
416  * pointer is saved (and returned) than the one actually passed in. In the
417  * usual case, however, the vertex pointer passed in is the one that is saved
418  * in the vertex pool and returned from this method.
419  */
421 add_vertex(EggVertex *vertex, int index) {
422  // Save a pointer to the vertex.
423  PT(EggVertex) vertex_keep = vertex;
424 
425  // Don't try to add a vertex while it still belongs to another pool.
426  nassertr(vertex->_pool == nullptr, nullptr);
427 
428  if (index == -1) {
429  index = get_highest_index() + 1;
430  }
431  // Always supply an index number >= 0.
432  nassertr(index >= 0, nullptr);
433 
434  // Check for a forward reference.
435  IndexVertices::const_iterator ivi = _index_vertices.find(index);
436 
437  if (ivi != _index_vertices.end()) {
438  EggVertex *orig_vertex = (*ivi).second;
439  if (orig_vertex->is_forward_reference() &&
440  !vertex->is_forward_reference()) {
441  (*orig_vertex) = (*vertex);
442  orig_vertex->_forward_reference = false;
443  _highest_index = std::max(_highest_index, index);
444  return orig_vertex;
445  }
446 
447  // Oops, you duplicated a vertex index.
448  nassert_raise("duplicate vertex index");
449  return nullptr;
450  }
451 
452  _unique_vertices.insert(vertex);
453  _index_vertices[index] = vertex;
454 
455  if (!vertex->is_forward_reference()) {
456  _highest_index = std::max(_highest_index, index);
457  }
458 
459  vertex->_pool = this;
460  vertex->_index = index;
461 
462  return vertex;
463 }
464 
465 
466 /**
467  * Creates a new vertex in the pool that is a copy of the indicated one and
468  * returns it. If there is already a vertex in the pool like the indicated
469  * one, simply returns that one.
470  */
473  UniqueVertices::iterator uvi;
474  uvi = _unique_vertices.find((EggVertex *)&copy);
475 
476  if (uvi != _unique_vertices.end()) {
477  // There was already such a vertex. Return it.
478  return (*uvi);
479  }
480 
481  // Create a new vertex.
482  return add_vertex(new EggVertex(copy));
483 }
484 
485 /**
486  * If the EggVertexPool already has a vertex matching the indicated vertex,
487  * returns it; otherwise, returns NULL. This is similar to
488  * create_unique_vertex() except that a new vertex is never created.
489  */
492  UniqueVertices::iterator uvi;
493  uvi = _unique_vertices.find((EggVertex *)&copy);
494 
495  if (uvi != _unique_vertices.end()) {
496  // There was already such a vertex. Return it.
497  return (*uvi);
498  }
499 
500  // No matching vertex.
501  return nullptr;
502 }
503 
504 
505 /**
506  * Removes the vertex from the pool. It is an error if the vertex is not
507  * already a member of the pool.
508  */
509 void EggVertexPool::
511  // Make sure the vertex is already a member of this pool.
512  nassertv(vertex->_pool == this);
513 
514  // Sanity check. Is the vertex actually in the pool?
515  nassertv(get_vertex(vertex->_index) == vertex);
516 
517  // Removing the vertex from the indexed list is simple.
518  _index_vertices.erase(vertex->_index);
519 
520  if (_highest_index == vertex->_index) {
521  // Find the new highest vertex index.
522  if (_index_vertices.empty()) {
523  _highest_index = -1;
524  } else {
525  IndexVertices::reverse_iterator ivi = _index_vertices.rbegin();
526  while (ivi != _index_vertices.rend() &&
527  (*ivi).second->is_forward_reference()) {
528  ++ivi;
529  }
530  if (ivi != _index_vertices.rend()) {
531  _highest_index = (*ivi).first;
532  } else {
533  _highest_index = -1;
534  }
535  }
536  }
537 
538  // Removing the vertex from the unique list is a bit trickier--there might
539  // be several other vertices that are considered identical to this one, and
540  // so we have to walk through all the identical vertices until we find the
541  // right one.
542  UniqueVertices::iterator uvi;
543  uvi = _unique_vertices.find(vertex);
544 
545  // Sanity check. Is the vertex actually in the pool?
546  nassertv(uvi != _unique_vertices.end());
547 
548  while ((*uvi) != vertex) {
549  ++uvi;
550  // Sanity check. Is the vertex actually in the pool?
551  nassertv(uvi != _unique_vertices.end());
552  }
553 
554  _unique_vertices.erase(uvi);
555 
556  vertex->_pool = nullptr;
557 }
558 
559 /**
560  * Removes all vertices from the pool that are not referenced by at least one
561  * primitive. Also collapses together equivalent vertices, and renumbers all
562  * vertices after the operation so their indices are consecutive, beginning at
563  * zero. Returns the number of vertices removed.
564  */
565 int EggVertexPool::
567  int num_removed = 0;
568 
569  UniqueVertices new_unique_vertices;
570  IndexVertices new_index_vertices;
571 
572  IndexVertices::const_iterator ivi;
573  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
574  EggVertex *vertex = (*ivi).second;
575  if (vertex->pref_size() == 0) {
576  // This vertex is not used. Don't add it to the new lists.
577  vertex->clear_grefs();
578  vertex->_pool = nullptr;
579  num_removed++;
580 
581  } else {
582  // The vertex *is* used somewhere. Is it identical to an existing
583  // vertex?
584  UniqueVertices::iterator uvi;
585  uvi = new_unique_vertices.find(vertex);
586  if (uvi != new_unique_vertices.end()) {
587  // Yes, there's already another vertex just like this one. Redirect
588  // all the primitives currently referencing this vertex to reference
589  // the other one instead.
590  EggVertex *orig_vertex = (*uvi);
591 
592  EggVertex::PrimitiveRef pref = vertex->_pref;
593  EggVertex::PrimitiveRef::iterator pi;
594  for (pi = pref.begin(); pi != pref.end(); ++pi) {
595  EggPrimitive *prim = (*pi);
596  EggPrimitive::iterator pvi = prim->find(vertex);
597  nassertr(pvi != prim->end(), 0);
598  prim->replace(pvi, orig_vertex);
599  }
600  vertex->test_pref_integrity();
601  orig_vertex->test_pref_integrity();
602  nassertr(vertex->pref_size() == 0, 0);
603  vertex->clear_grefs();
604  vertex->_pool = nullptr;
605  num_removed++;
606 
607  } else {
608  // It's a unique vertex. Renumber it and add it to the new lists.
609  vertex->_index = new_index_vertices.size();
610  new_index_vertices.insert(IndexVertices::value_type(vertex->_index, vertex));
611  new_unique_vertices.insert(vertex);
612  }
613  }
614  }
615 
616  // All done. Lose the old lists.
617  _unique_vertices.swap(new_unique_vertices);
618  _index_vertices.swap(new_index_vertices);
619  _highest_index = (int)_index_vertices.size() - 1;
620 
621  nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed);
622 
623  return num_removed;
624 }
625 
626 /**
627  * Adds all of the unused vertices in this vertex pool to the indicated
628  * primitive, in ascending order.
629  */
630 void EggVertexPool::
632  IndexVertices::iterator ivi;
633  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
634  EggVertex *vertex = (*ivi).second;
635  if (vertex->pref_size() == 0) {
636  prim->add_vertex(vertex);
637  }
638  }
639 }
640 
641 // A function object for split_vertex(), used in transform(), below.
642 class IsLocalVertexSplitter {
643 public:
644  int operator () (const EggPrimitive *prim) const {
645  return (prim->is_local_coord() ? 1 : 0);
646  }
647 };
648 
649 /**
650  * Applies the indicated transformation matrix to all the vertices. However,
651  * vertices that are attached to primitives that believe their vertices are in
652  * a local coordinate system are transformed only by the scale and rotation
653  * component. If a vertex happens to be attached both to a local and a global
654  * primitive, and the transformation includes a translation component, the
655  * vertex will be split.
656  */
657 void EggVertexPool::
658 transform(const LMatrix4d &mat) {
659  LVector3d translation = mat.get_row3(3);
660 
661  if (translation == LVector3d(0.0, 0.0, 0.0)) {
662  // If the matrix does not have a translation component, we can treat the
663  // local and global vertices the same. This makes things much easier.
664  iterator i;
665  for (i = begin(); i != end(); ++i) {
666  EggVertex *vert = *i;
667  vert->transform(mat);
668  }
669 
670  } else {
671  // The matrix does have a translation component. That means we have to
672  // treat the global and local vertices differently. Yucky.
673 
674  // First, transform the global vertices. Get a copy of the list of
675  // vertices in this pool. We must have a copy because we might be
676  // modifying the list as we traverse it.
677 
678  typedef pvector<EggVertex *> Verts;
679  Verts verts;
680  verts.reserve(size());
681 
682  // Work around MSVC 2017 compiler bug, see GitHub issue #379
683 #ifdef _MSC_VER
684  for (const IndexVertices::value_type &v : _index_vertices) {
685  verts.push_back(v.second);
686  }
687 #else
688  std::copy(begin(), end(), std::back_inserter(verts));
689 #endif
690 
691  Verts::const_iterator vi;
692  for (vi = verts.begin(); vi != verts.end(); ++vi) {
693  EggVertex *vert = *vi;
694  int num_local_coord = vert->get_num_local_coord();
695  int num_global_coord = vert->get_num_global_coord();
696 
697  if (num_global_coord != 0) {
698  // This vertex will be transformed.
699  if (num_local_coord != 0) {
700  // It also needs to be split! Yuck.
701  split_vertex(vert, IsLocalVertexSplitter());
702  }
703 
704  vert->transform(mat);
705  }
706  }
707 
708  // Now transform the local vertices. We can walk through the list
709  // directly now, because we won't be modifying the list this time.
710  LMatrix4d local_mat = mat;
711  local_mat.set_row(3, LVector3d(0.0, 0.0, 0.0));
712 
713  iterator i;
714  for (i = begin(); i != end(); ++i) {
715  EggVertex *vert = *i;
716  if (vert->get_num_local_coord() != 0) {
717 
718  // This should be guaranteed by the vertex-splitting logic above.
719  nassertv(vert->get_num_global_coord() == 0);
720  vert->transform(local_mat);
721  }
722  }
723  }
724 }
725 
726 
727 // A function object for sort_by_external_index(), below.
728 class SortByExternalIndex {
729 public:
730  bool operator () (EggVertex *a, EggVertex *b) const {
731  int ai = a->get_external_index();
732  int bi = b->get_external_index();
733  if (ai != bi) {
734  return ai < bi;
735  }
736  return a->get_index() < b->get_index();
737  }
738 };
739 
740 /**
741  * Re-orders (and re-numbers) the vertices in this vertex pool so that they
742  * appear in increasing order by the optional external_index that has been
743  * assigned to each vertex.
744  */
745 void EggVertexPool::
747  // Copy the vertices into a vector for sorting.
748  typedef pvector<EggVertex *> SortedVertices;
749  SortedVertices sorted_vertices;
750  sorted_vertices.reserve(size());
751  iterator i;
752  for (i = begin(); i != end(); ++i) {
753  sorted_vertices.push_back(*i);
754  }
755 
756  std::sort(sorted_vertices.begin(), sorted_vertices.end(), SortByExternalIndex());
757 
758  // Now reassign the indices, and copy them into a new index map.
759  IndexVertices new_index_vertices;
760  int vi;
761  for (vi = 0; vi < (int)sorted_vertices.size(); ++vi) {
762  EggVertex *vertex = sorted_vertices[vi];
763  vertex->_index = vi;
764  new_index_vertices[vi] = vertex;
765  }
766 
767  // Finally, assign the new index map.
768  _index_vertices.swap(new_index_vertices);
769 }
770 
771 /**
772  * Writes the vertex pool to the indicated output stream in Egg format.
773  */
774 void EggVertexPool::
775 write(std::ostream &out, int indent_level) const {
776  write_header(out, indent_level, "<VertexPool>");
777 
778  iterator i;
779  for (i = begin(); i != end(); ++i) {
780  (*i)->write(out, indent_level+2);
781  }
782 
783  indent(out, indent_level)
784  << "}\n";
785 }
786 
787 
788 /**
789  * This is called from within the egg code by transform(). It applies a
790  * transformation matrix to the current node in some sensible way, then
791  * continues down the tree.
792  *
793  * The first matrix is the transformation to apply; the second is its inverse.
794  * The third parameter is the coordinate system we are changing to, or
795  * CS_default if we are not changing coordinate systems.
796  */
797 void EggVertexPool::
798 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) {
799 }
800 
801 /**
802  * This is called from within the egg code by transform_vertices_only()(). It
803  * applies a transformation matrix to the current node in some sensible way
804  * (if the current node is a vertex pool with vertices), then continues down
805  * the tree.
806  */
807 void EggVertexPool::
808 r_transform_vertices(const LMatrix4d &mat) {
809  transform(mat);
810 }
bool empty() const
Returns true if the pool is empty.
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
Definition: eggPrimitive.h:47
The set of UV's that may or may not be assigned to a vertex.
Definition: eggVertexUV.h:29
void split_vertex(EggVertex *vert, const FunctionObject &sequence)
Splits a vertex into two or more vertices, each an exact copy of the original and in the same vertex ...
Definition: eggUtilities.I:43
bool has_uvs() const
Returns true if any vertex in the pool has a uv defined, false if none of them do.
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
PrimitiveRef::size_type pref_size() const
Returns the number of elements between pref_begin() and pref_end().
Definition: eggVertex.cxx:815
void set_highest_index(int highest_index)
Artificially changes the "highest index number", so that a newly created vertex will begin at this nu...
int get_num_dimensions() const
Returns the number of dimensions the vertex uses.
Definition: eggVertex.I:99
void write_header(std::ostream &out, int indent_level, const char *egg_keyword) const
Writes the first line of the egg object, e.g.
int get_num_dimensions() const
Returns the maximum number of dimensions used by any vertex in the pool.
EggVertex * add_vertex(EggVertex *vertex, int index=-1)
Adds the indicated vertex to the pool.
bool has_aux() const
Returns true if the vertex has any auxiliary data, false otherwise.
Definition: eggVertex.I:166
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggVertex * get_vertex(int index) const
Returns the vertex in the pool with the indicated index number, or NULL if no vertices have that inde...
EggVertex * get_forward_vertex(int index)
Returns the vertex in the pool with the indicated index number.
void check_overall_color(bool &has_overall_color, LColor &overall_color) const
Scans the vertex pool for different colors on different vertices.
const_aux_iterator aux_end() const
Returns an iterator that allows walking through the complete set of auxiliary data on the vertex.
Definition: eggVertex.I:253
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear_grefs()
Removes all group references from the vertex, so that it is not assigned to any group.
Definition: eggVertex.cxx:772
LColor get_color() const
Returns the color set on this particular attribute.
Definition: eggAttributes.I:91
size_type size() const
Returns the number of vertices in the pool.
bool has_normals() const
Returns true if any vertex in the pool has a normal defined, false if none of them do.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
void write(std::ostream &out, int indent_level) const
Writes the vertex pool to the indicated output stream in Egg format.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
bool has_aux() const
Returns true if any vertex in the pool has auxiliary data defined, false if none of them do.
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:277
int get_highest_index() const
Returns the highest index number used by any vertex in the pool (except forward references).
bool has_w() const
Returns true if the texture coordinate has a third, w component, false if it is just a normal 2-d tex...
Definition: eggVertexUV.I:49
void get_uv_names(vector_string &uv_names, vector_string &uvw_names, vector_string &tbn_names) const
Returns the list of UV names that are defined by any vertices in the pool, as well as the subset of U...
bool is_local_coord() const
Returns true if this node's vertices are not in the global coordinate space.
Definition: eggNode.I:87
bool has_defined_vertices() const
Returns true if any vertices in the pool are fully defined vertices, false if all vertices are forwar...
bool has_colors() const
Returns true if any vertex in the pool has a color defined, false if none of them do.
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the vertex.
Definition: eggVertex.cxx:672
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
int remove_unused_vertices()
Removes all vertices from the pool that are not referenced by at least one primitive.
iterator find(EggVertex *vertex)
Returns the iterator pointing to the indicated vertex, or end() if the vertex is not part of the prim...
void add_unused_vertices_to_prim(EggPrimitive *prim)
Adds all of the unused vertices in this vertex pool to the indicated primitive, in ascending order.
bool has_uv() const
Returns true if the vertex has an unnamed UV coordinate pair, false otherwise.
Definition: eggVertex.I:158
The set of named auxiliary data that may or may not be assigned to a vertex.
Definition: eggVertexAux.h:30
const_aux_iterator aux_begin() const
Returns an iterator that allows walking through the complete set of auxiliary data on the vertex.
Definition: eggVertex.I:231
EggVertex * find_matching_vertex(const EggVertex &copy)
If the EggVertexPool already has a vertex matching the indicated vertex, returns it; otherwise,...
bool is_forward_reference() const
Returns true if the vertex is a forward reference to some vertex that hasn't been defined yet.
Definition: eggVertex.I:33
const_uv_iterator uv_begin() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition: eggVertex.I:220
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
void sort_by_external_index()
Re-orders (and re-numbers) the vertices in this vertex pool so that they appear in increasing order b...
int get_external_index() const
Returns the number set by set_external_index().
Definition: eggVertex.I:300
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
Definition: eggPrimitive.I:335
int get_num_global_coord() const
Returns the number of primitives that own this vertex whose vertices are interpreted in the global co...
Definition: eggVertex.cxx:654
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
int get_num_local_coord() const
Returns the number of primitives that own this vertex whose vertices are interpreted to be in a local...
Definition: eggVertex.cxx:636
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void get_aux_names(vector_string &aux_names) const
Returns the list of auxiliary data names that are defined by any vertices in the pool.
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to all the vertices.
const_uv_iterator uv_end() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition: eggVertex.I:242
bool has_forward_vertices() const
Returns true if any vertices in the pool are undefined forward-reference vertices,...
bool has_nonwhite_colors() const
Returns true if any vertex in the pool has a color defined other than white, false if no vertices hav...
void remove_vertex(EggVertex *vertex)
Removes the vertex from the pool.