Panda3D
eggPrimitive.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 eggPrimitive.cxx
10  * @author drose
11  * @date 1999-01-16
12  */
13 
14 #include "eggPrimitive.h"
15 #include "eggVertexPool.h"
16 #include "eggMiscFuncs.h"
17 #include "eggTextureCollection.h"
18 #include "lexerDefs.h"
19 #include "config_egg.h"
20 
21 #include "indent.h"
22 #include "vector_int.h"
23 
24 TypeHandle EggPrimitive::_type_handle;
25 
26 
27 /**
28  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
29  * some such object at this level or above this primitive that has an
30  * alpha_mode other than AM_unspecified. Returns a valid EggRenderMode
31  * pointer if one is found, or NULL otherwise.
32  */
35  if (get_alpha_mode() != AM_unspecified) {
36  return this;
37  }
38 
40  if (result == nullptr) {
41  int num_textures = get_num_textures();
42  for (int i = 0; i < num_textures && result == nullptr; i++) {
43  EggTexture *egg_tex = get_texture(i);
44 
45  // We only want to consider the alpha mode on those textures that can
46  // affect the transparency of the polygon. This mostly depends on the
47  // envtype flag.
48  if (egg_tex->affects_polygon_alpha()) {
49  // This texture might affect the polygon alpha, so it gets to decide
50  // the polygon transparency mode.
51  if (egg_tex->get_alpha_mode() != AM_unspecified) {
52  result = get_texture(i);
53  }
54  }
55  }
56  }
57  return result;
58 }
59 
60 /**
61  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
62  * some such object at this level or above this node that has a
63  * depth_write_mode other than DWM_unspecified. Returns a valid EggRenderMode
64  * pointer if one is found, or NULL otherwise.
65  */
68  if (get_depth_write_mode() != DWM_unspecified) {
69  return this;
70  }
71 
73  if (result == nullptr) {
74  int num_textures = get_num_textures();
75  for (int i = 0; i < num_textures && result == nullptr; i++) {
76  if (get_texture(i)->get_depth_write_mode() != DWM_unspecified) {
77  result = get_texture(i);
78  }
79  }
80  }
81  return result;
82 }
83 
84 /**
85  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
86  * some such object at this level or above this node that has a
87  * depth_test_mode other than DTM_unspecified. Returns a valid EggRenderMode
88  * pointer if one is found, or NULL otherwise.
89  */
92  if (get_depth_test_mode() != DTM_unspecified) {
93  return this;
94  }
95 
97  if (result == nullptr) {
98  int num_textures = get_num_textures();
99  for (int i = 0; i < num_textures && result == nullptr; i++) {
100  if (get_texture(i)->get_depth_test_mode() != DTM_unspecified) {
101  result = get_texture(i);
102  }
103  }
104  }
105  return result;
106 }
107 
108 /**
109  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
110  * some such object at this level or above this node that has a
111  * visibility_mode other than VM_unspecified. Returns a valid EggRenderMode
112  * pointer if one is found, or NULL otherwise.
113  */
116  if (get_visibility_mode() != VM_unspecified) {
117  return this;
118  }
119 
121  if (result == nullptr) {
122  int num_textures = get_num_textures();
123  for (int i = 0; i < num_textures && result == nullptr; i++) {
124  if (get_texture(i)->get_visibility_mode() != VM_unspecified) {
125  result = get_texture(i);
126  }
127  }
128  }
129  return result;
130 }
131 
132 /**
133  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
134  * some such object at this level or above this primitive that has a
135  * depth_offset specified. Returns a valid EggRenderMode pointer if one is
136  * found, or NULL otherwise.
137  */
140  if (has_depth_offset()) {
141  return this;
142  }
143 
145  if (result == nullptr) {
146  int num_textures = get_num_textures();
147  for (int i = 0; i < num_textures && result == nullptr; i++) {
148  if (get_texture(i)->has_depth_offset()) {
149  result = get_texture(i);
150  }
151  }
152  }
153  return result;
154 }
155 
156 /**
157  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
158  * some such object at this level or above this primitive that has a
159  * draw_order specified. Returns a valid EggRenderMode pointer if one is
160  * found, or NULL otherwise.
161  */
164  if (has_draw_order()) {
165  return this;
166  }
167 
169  if (result == nullptr) {
170  int num_textures = get_num_textures();
171  for (int i = 0; i < num_textures && result == nullptr; i++) {
172  if (get_texture(i)->has_draw_order()) {
173  result = get_texture(i);
174  }
175  }
176  }
177  return result;
178 }
179 
180 /**
181  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
182  * some such object at this level or above this primitive that has a bin
183  * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
184  * otherwise.
185  */
188  if (has_bin()) {
189  return this;
190  }
191 
193  if (result == nullptr) {
194  int num_textures = get_num_textures();
195  for (int i = 0; i < num_textures && result == nullptr; i++) {
196  if (get_texture(i)->has_bin()) {
197  result = get_texture(i);
198  }
199  }
200  }
201  return result;
202 }
203 
204 
205 /**
206  * Returns the shading properties apparent on this particular primitive. This
207  * returns S_per_vertex if the vertices have colors or normals (and they are
208  * not all the same values), or for a simple primitive, S_overall otherwise.
209  * A composite primitive may also return S_per_face if the individual
210  * component primitives have colors or normals that are not all the same
211  * values.
212  *
213  * To get the most accurate results, you should call clear_shading() on all
214  * connected primitives (or on all primitives in the egg file), followed by
215  * get_shading() on each primitive. You may find it easiest to call these
216  * methods on the EggData root node (they are defined on EggGroupNode).
217  */
218 EggPrimitive::Shading EggPrimitive::
219 get_shading() const {
220  if (empty()) {
221  return S_overall;
222  }
223 
224  if (has_vertex_normal()) {
225  // Check if the vertices all have the same normal.
226  const EggAttributes *first_vertex = get_vertex(0);
227  if (!first_vertex->has_normal()) {
228  first_vertex = this;
229  }
230  for (size_t i = 1; i < get_num_vertices(); ++i) {
231  const EggAttributes *vertex = get_vertex(i);
232  if (!vertex->has_normal()) {
233  vertex = this;
234  }
235  if (!vertex->matches_normal(*first_vertex)) {
236  return S_per_vertex;
237  }
238  }
239  }
240 
241  if (has_vertex_color()) {
242  // Check if the vertices all have the same color.
243  const EggAttributes *first_vertex = get_vertex(0);
244  if (!first_vertex->has_color()) {
245  first_vertex = this;
246  }
247  for (size_t i = 1; i < get_num_vertices(); ++i) {
248  const EggAttributes *vertex = get_vertex(i);
249  if (!vertex->has_color()) {
250  vertex = this;
251  }
252  if (!vertex->matches_color(*first_vertex)) {
253  return S_per_vertex;
254  }
255  }
256  }
257 
258  return S_overall;
259 }
260 
261 /**
262  * Copies the rendering attributes from the indicated primitive.
263  */
264 void EggPrimitive::
266  EggAttributes::operator = (other);
267 }
268 
269 /**
270  * Copies the rendering attributes from the indicated primitive.
271  */
272 void EggPrimitive::
274  EggAttributes::operator = (other);
275  _textures = other._textures;
276  set_material(other.get_material());
278 }
279 
280 /**
281  * Returns true if any vertex on the primitive has a specific normal set,
282  * false otherwise.
283  *
284  * If you call unify_attributes() first, this will also return false even if
285  * all the vertices were set to the same value (since unify_attributes()
286  * removes redundant vertex properties).
287  */
288 bool EggPrimitive::
290  Vertices::const_iterator vi;
291  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
292  if ((*vi)->has_normal()) {
293  return true;
294  }
295  }
296  return false;
297 }
298 
299 /**
300  * Returns true if any vertex on the primitive has a specific color set, false
301  * otherwise.
302  *
303  * If you call unify_attributes() first, this will also return false even if
304  * all the vertices were set to the same value (since unify_attributes()
305  * removes redundant vertex properties).
306  */
307 bool EggPrimitive::
309  Vertices::const_iterator vi;
310  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
311  if ((*vi)->has_color()) {
312  return true;
313  }
314  }
315  return false;
316 }
317 
318 /**
319  * If the shading property is S_per_vertex, ensures that all vertices have a
320  * normal and a color, and the overall primitive does not.
321  *
322  * If the shading property is S_per_face, and this is a composite primitive,
323  * ensures that all components have a normal and a color, and the vertices and
324  * overall primitive do not. (If this is a simple primitive, S_per_face works
325  * the same as S_overall, below).
326  *
327  * If the shading property is S_overall, ensures that no vertices or
328  * components have a normal or a color, and the overall primitive does (if any
329  * exists at all).
330  *
331  * After this call, either the primitive will have normals or its vertices
332  * will, but not both. Ditto for colors.
333  *
334  * This may create redundant vertices in the vertex pool.
335  */
336 void EggPrimitive::
337 unify_attributes(EggPrimitive::Shading shading) {
338  if (shading == S_unknown) {
339  shading = get_shading();
340  }
341 
342  // Does the primitive have an explicit color?
343  if (!has_color() && shading != S_overall) {
344  if (shading != S_per_vertex) {
345  // If there is no color set, first we check the vertices. If the
346  // vertices have a color, we inherit the color from there.
347  iterator pi;
348  for (pi = begin(); pi != end() && !has_color(); ++pi) {
349  EggVertex *vertex = (*pi);
350  if (vertex->has_color()) {
351  set_color(vertex->get_color());
352  }
353  }
354  }
355  if (!has_color()) {
356  // If we still don't have a color, the implicit color is white.
357  set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
358  }
359  }
360 
361  switch (shading) {
362  case S_per_vertex:
363  // Propagate everything to the vertices.
364  {
365  iterator pi;
366  for (pi = begin(); pi != end(); ++pi) {
367  EggVertex *orig_vertex = (*pi);
368  PT(EggVertex) vertex = new EggVertex(*orig_vertex);
369  if (!vertex->has_normal() && has_normal()) {
370  vertex->copy_normal(*this);
371  }
372  if (!vertex->has_color() && has_color()) {
373  vertex->copy_color(*this);
374  }
375 
376  EggVertexPool *vertex_pool = orig_vertex->get_pool();
377  nassertv(vertex_pool != nullptr);
378  vertex = vertex_pool->create_unique_vertex(*vertex);
379  vertex->copy_grefs_from(*orig_vertex);
380  replace(pi, vertex);
381  }
382  clear_normal();
383  clear_color();
384  }
385  break;
386 
387  case S_per_face:
388  case S_overall:
389  // Remove everything from the vertices.
390  {
391  iterator pi;
392  for (pi = begin(); pi != end(); ++pi) {
393  EggVertex *orig_vertex = (*pi);
394  PT(EggVertex) vertex = new EggVertex(*orig_vertex);
395  if (vertex->has_normal()) {
396  if (!has_normal()) {
397  copy_normal(*vertex);
398  }
399  vertex->clear_normal();
400  }
401  if (vertex->has_color()) {
402  if (!has_color()) {
403  copy_color(*vertex);
404  }
405  vertex->clear_color();
406  }
407 
408  EggVertexPool *vertex_pool = orig_vertex->get_pool();
409  nassertv(vertex_pool != nullptr);
410  vertex = vertex_pool->create_unique_vertex(*vertex);
411  vertex->copy_grefs_from(*orig_vertex);
412  replace(pi, vertex);
413  }
414  }
415  break;
416 
417  case S_unknown:
418  break;
419  }
420 
421  if (!has_color() && shading == S_overall) {
422  set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
423  }
424 }
425 
426 /**
427  * Sets the last vertex of the triangle (or each component) to the primitive
428  * normal and/or color, if the primitive is flat-shaded. This reflects the
429  * OpenGL convention of storing flat-shaded properties on the last vertex,
430  * although it is not usually a convention in Egg.
431  *
432  * This may introduce redundant vertices to the vertex pool.
433  */
434 void EggPrimitive::
436  if (!empty()) {
437  do_apply_flat_attribute(size() - 1, this);
438  }
439 }
440 
441 /**
442  * Sets the first vertex of the triangle (or each component) to the primitive
443  * normal and/or color, if the primitive is flat-shaded. This reflects the
444  * DirectX convention of storing flat-shaded properties on the first vertex,
445  * although it is not usually a convention in Egg.
446  *
447  * This may introduce redundant vertices to the vertex pool.
448  */
449 void EggPrimitive::
451  if (!empty()) {
452  do_apply_flat_attribute(0, this);
453  }
454 }
455 
456 /**
457  * Intended as a followup to apply_last_attribute(), this also sets an
458  * attribute on the first vertices of the primitive, if they don't already
459  * have an attribute set, just so they end up with *something*.
460  */
461 void EggPrimitive::
463  if (!empty()) {
464  for (EggVertex *vertex : _vertices) {
465  // Use set_normal() instead of copy_normal(), to avoid getting the
466  // morphs--we don't want them here, since we're just putting a bogus
467  // value on the normal anyway.
468 
469  if (has_normal() && !vertex->has_normal()) {
470  vertex->set_normal(get_normal());
471  }
472  if (has_color() && !vertex->has_color()) {
473  vertex->set_color(get_color());
474  }
475  }
476  }
477 }
478 
479 /**
480  * Reverses the ordering of the vertices in this primitive, if appropriate, in
481  * order to change the direction the polygon appears to be facing. Does not
482  * adjust the surface normal, if any.
483  */
484 void EggPrimitive::
486  // This really only makes sense for polygons. Lights don't care about
487  // vertex ordering, and NURBS surfaces have to do a bit more work in
488  // addition to this.
489  reverse(_vertices.begin(), _vertices.end());
490 }
491 
492 /**
493  * Cleans up modeling errors in whatever context this makes sense. For
494  * instance, for a polygon, this calls remove_doubled_verts(true). For a
495  * point, it calls remove_nonunique_verts(). Returns true if the primitive is
496  * valid, or false if it is degenerate.
497  */
498 bool EggPrimitive::
500  return !empty();
501 }
502 
503 /**
504  * Certain kinds of primitives, particularly polygons, don't like to have the
505  * same vertex repeated consecutively. Unfortunately, some modeling programs
506  * (like MultiGen) make this an easy mistake to make.
507  *
508  * It's handy to have a function to remove these redundant vertices. If
509  * closed is true, it also checks that the first and last vertices are not the
510  * same.
511  *
512  * This function identifies repeated vertices by position only; it does not
513  * consider any other properties, such as color or UV, significant in
514  * differentiating vertices.
515  */
516 void EggPrimitive::
517 remove_doubled_verts(bool closed) {
518  if (!_vertices.empty()) {
519  Vertices new_vertices;
520  Vertices::iterator vi, vlast;
521  vi = _vertices.begin();
522  new_vertices.push_back(*vi);
523  int num_removed = 0;
524 
525  vlast = vi;
526  ++vi;
527  while (vi != _vertices.end()) {
528  if ((*vi)->get_pos4() != (*vlast)->get_pos4()) {
529  new_vertices.push_back(*vi);
530  } else {
531  prepare_remove_vertex(*vi, vi - _vertices.begin() - num_removed,
532  _vertices.size() - num_removed);
533  num_removed++;
534  }
535  vlast = vi;
536  ++vi;
537  }
538  _vertices.swap(new_vertices);
539  }
540 
541  if (closed) {
542  // Then, if this is a polygon (which will be closed anyway), remove the
543  // vertex from the end if it's a repeat of the beginning.
544  while (_vertices.size() > 1 &&
545  _vertices.back()->get_pos4() == _vertices.front()->get_pos4()) {
546  prepare_remove_vertex(_vertices.back(), _vertices.size() - 1,
547  _vertices.size());
548  _vertices.pop_back();
549  }
550  }
551 }
552 
553 /**
554  * Removes any multiple appearances of the same vertex from the primitive.
555  * This primarily makes sense for a point primitive, which is really a
556  * collection of points and which doesn't make sense to include the same point
557  * twice, in any order.
558  */
559 void EggPrimitive::
561  Vertices::iterator vi;
562  Vertices new_vertices;
563  int num_removed = 0;
564 
565  pset<EggVertex *> unique_vertices;
566  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
567  bool inserted = unique_vertices.insert(*vi).second;
568  if (inserted) {
569  new_vertices.push_back(*vi);
570  } else {
571  prepare_remove_vertex(*vi, vi - _vertices.begin() - num_removed,
572  _vertices.size() - num_removed);
573  num_removed++;
574  }
575  }
576 
577  _vertices.swap(new_vertices);
578 }
579 
580 /**
581  * Returns true if there are any primitives (e.g. polygons) defined within
582  * this group or below, false otherwise.
583  */
584 bool EggPrimitive::
585 has_primitives() const {
586  return true;
587 }
588 
589 /**
590  * Returns true if there are any primitives (e.g. polygons) defined within
591  * this group or below, but the search does not include nested joints.
592  */
593 bool EggPrimitive::
595  return true;
596 }
597 
598 /**
599  * Returns true if any of the primitives (e.g. polygons) defined within this
600  * group or below have either face or vertex normals defined, false otherwise.
601  */
602 bool EggPrimitive::
603 has_normals() const {
604  if (has_normal()) {
605  return true;
606  }
607 
608  const_iterator vi;
609  for (vi = begin(); vi != end(); ++vi) {
610  if ((*vi)->has_normal()) {
611  return true;
612  }
613  }
614 
615  return false;
616 }
617 
618 
619 /**
620  * Part of the implementaion of the EggPrimitive as an STL container. Most of
621  * the rest of these functions are inline and declared in EggPrimitive.I.
622  */
623 EggPrimitive::iterator EggPrimitive::
624 erase(iterator first, iterator last) {
625  iterator i;
626  int num_removed = 0;
627  for (i = first; i != last; ++i) {
628  prepare_remove_vertex(*i, first - _vertices.begin(),
629  _vertices.size() - num_removed);
630  num_removed++;
631  }
632  iterator result = _vertices.erase((Vertices::iterator &)first,
633  (Vertices::iterator &)last);
634  test_vref_integrity();
635  return result;
636 }
637 
638 /**
639  * Returns the iterator pointing to the indicated vertex, or end() if the
640  * vertex is not part of the primitive.
641  */
642 EggPrimitive::iterator EggPrimitive::
643 find(EggVertex *vertex) {
644  PT_EggVertex vpt = vertex;
645  return std::find(begin(), end(), vpt);
646 }
647 
648 
649 /**
650  * Adds the indicated vertex to the end of the primitive's list of vertices,
651  * and returns it.
652  */
655  prepare_add_vertex(vertex, _vertices.size(), _vertices.size() + 1);
656  _vertices.push_back(vertex);
657 
658  vertex->test_pref_integrity();
659  test_vref_integrity();
660 
661  return vertex;
662 }
663 
664 /**
665  * Removes the indicated vertex from the primitive and returns it. If the
666  * vertex was not already in the primitive, does nothing and returns NULL.
667  */
669 remove_vertex(EggVertex *vertex) {
670  PT_EggVertex vpt = vertex;
671  iterator i = std::find(begin(), end(), vpt);
672  if (i == end()) {
673  return PT_EggVertex();
674  } else {
675  // erase() calls prepare_remove_vertex().
676  erase(i);
677 
678  vertex->test_pref_integrity();
679  test_vref_integrity();
680 
681  return vertex;
682  }
683 }
684 
685 /**
686  * Removes the indicated vertex from the primitive.
687  */
688 void EggPrimitive::
689 remove_vertex(size_t index) {
690  nassertv(index < size());
691  iterator i = begin() + index;
692 
693  // erase() calls prepare_remove_vertex().
694  erase(i);
695 
696  test_vref_integrity();
697 }
698 
699 /**
700  * Replaces the current primitive's list of vertices with a copy of the list
701  * of vertices on the other primitive.
702  */
703 void EggPrimitive::
705  clear();
706  _vertices.reserve(other.size());
707 
708  iterator vi;
709  for (vi = other.begin(); vi != other.end(); ++vi) {
710  add_vertex(*vi);
711  }
712 
713  test_vref_integrity();
714  other.test_vref_integrity();
715 }
716 
717 #ifdef _DEBUG
718 
719 /**
720  * Verifies that each vertex in the primitive exists and that it knows it is
721  * referenced by the primitive.
722  */
723 void EggPrimitive::
724 test_vref_integrity() const {
726 
727  if ((int)size() <= egg_test_vref_integrity) {
728  // First, we need to know how many times each vertex appears. Usually,
729  // this will be only one, but it's possible for a vertex to appear more
730  // than once.
731  typedef pmap<const EggVertex *, int> VertexCount;
732  VertexCount _count;
733 
734  // Now count up the vertices.
735  iterator vi;
736  for (vi = begin(); vi != end(); ++vi) {
737  const EggVertex *vert = *vi;
738  vert->test_ref_count_integrity();
739 
740  VertexCount::iterator vci = _count.find(vert);
741  if (vci == _count.end()) {
742  _count[vert] = 1;
743  } else {
744  (*vci).second++;
745  }
746  }
747 
748  // Ok, now walk through the vertices found and make sure the vertex has
749  // the proper number of entries of this primitive in its pref.
750  VertexCount::iterator vci;
751  for (vci = _count.begin(); vci != _count.end(); ++vci) {
752  const EggVertex *vert = (*vci).first;
753 
754  int count = (*vci).second;
755  int vert_count = vert->has_pref(this);
756 
757  nassertv(count == vert_count);
758  }
759  }
760 }
761 
762 #endif // _DEBUG
763 
764 /**
765  * Marks the vertex as belonging to the primitive. This is an internal
766  * function called by the STL-like functions push_back() and insert(), in
767  * preparation for actually adding the vertex.
768  *
769  * i indicates the new position of the vertex in the list; n indicates the new
770  * number of vertices after the operation has completed.
771  */
772 void EggPrimitive::
773 prepare_add_vertex(EggVertex *vertex, int i, int n) {
774  // We can't test integrity within this function, because it might be called
775  // when the primitive is in an incomplete state.
776 
777  // The vertex must have the same vertex pool as the vertices already added.
778  nassertv(empty() || vertex->get_pool() == get_pool());
779 
780  // Since a given vertex might appear more than once in a particular
781  // primitive, we can't conclude anything about data integrity by inspecting
782  // the return value of insert(). (In fact, the vertex's pref is a multiset,
783  // so the insert() will always succeed.)
784 
785  vertex->_pref.insert(this);
786 }
787 
788 
789 /**
790  * Marks the vertex as removed from the primitive. This is an internal
791  * function called by the STL-like functions pop_back() and erase(), in
792  * preparation for actually doing the removal.
793  *
794  * i indicates the former position of the vertex in the list; n indicates the
795  * current number of vertices before the operation has completed.
796  *
797  * It is an error to attempt to remove a vertex that is not already a vertex
798  * of this primitive.
799  */
800 void EggPrimitive::
801 prepare_remove_vertex(EggVertex *vertex, int i, int n) {
802  // We can't test integrity within this function, because it might be called
803  // when the primitive is in an incomplete state.
804 
805  // Now we must remove the primitive from the vertex's pref. We can't just
806  // use the simple erase() function, since that will remove all instances of
807  // this primitive from the pref; instead, we must find one instance and
808  // remove that.
809 
810  EggVertex::PrimitiveRef::iterator pri = vertex->_pref.find(this);
811 
812  // We should have found the primitive in the vertex's pref. If we did not,
813  // something's out of sync internally.
814  nassertv(pri != vertex->_pref.end());
815 
816  vertex->_pref.erase(pri);
817 }
818 
819 /**
820  * Writes the attributes and the vertices referenced by the primitive to the
821  * indicated output stream in Egg format.
822  */
823 void EggPrimitive::
824 write_body(std::ostream &out, int indent_level) const {
825  test_vref_integrity();
826 
827  EggAttributes::write(out, indent_level);
828  EggRenderMode::write(out, indent_level);
829 
830  int num_textures = get_num_textures();
831  for (int i = 0; i < num_textures; i++) {
832  EggTexture *texture = get_texture(i);
833 
834  indent(out, indent_level) << "<TRef> { ";
835  enquote_string(out, texture->get_name())
836  << " }\n";
837  }
838 
839  if (has_material()) {
840  EggMaterial *material = get_material();
841 
842  indent(out, indent_level) << "<MRef> { ";
843  enquote_string(out, material->get_name())
844  << " }\n";
845  }
846 
847  if (get_bface_flag()) {
848  indent(out, indent_level) << "<BFace> { 1 }\n";
849  }
850 
851  if (!empty()) {
852  EggVertexPool *pool = get_pool();
853 
854  // Make sure the vertices belong to some vertex pool.
855  nassertv(pool != nullptr);
856 
857  // Make sure the vertex pool is named.
858  nassertv(pool->has_name());
859 
860  if ((int)size() < 10) {
861  // A simple primitive gets all its vertex indices written on one line.
862  indent(out, indent_level) << "<VertexRef> {";
863  const_iterator i;
864  for (i = begin(); i != end(); ++i) {
865  EggVertex *vert = *i;
866  vert->test_pref_integrity();
867 
868  // Make sure each vertex belongs to the same pool.
869  nassertv(vert->get_pool() == pool);
870 
871  out << " " << vert->get_index();
872  }
873  out << " <Ref> { ";
874  enquote_string(out, pool->get_name()) << " } }\n";
875 
876  } else {
877 
878  // A larger primitive gets its vertex indices written as multiple lines.
879  vector_int indices;
880  const_iterator i;
881  for (i = begin(); i != end(); ++i) {
882  EggVertex *vert = *i;
883  vert->test_pref_integrity();
884 
885  // Make sure each vertex belongs to the same pool.
886  nassertv(vert->get_pool() == pool);
887 
888  indices.push_back(vert->get_index());
889  }
890 
891  indent(out, indent_level) << "<VertexRef> {\n";
892  write_long_list(out, indent_level+2, indices.begin(), indices.end(),
893  "", "", 72);
894  indent(out, indent_level+2) << "<Ref> { ";
895  enquote_string(out, pool->get_name()) << " }\n";
896  indent(out, indent_level) << "}\n";
897  }
898  }
899 }
900 
901 /**
902  * This function is called within parse_egg(). It should call the appropriate
903  * function on the lexer to initialize the parser into the state associated
904  * with this object. If the object cannot be parsed into directly, it should
905  * return false.
906  */
907 bool EggPrimitive::
908 egg_start_parse_body() {
909  egg_start_primitive_body();
910  return true;
911 }
912 
913 /**
914  * This is called from within the egg code by transform(). It applies a
915  * transformation matrix to the current node in some sensible way, then
916  * continues down the tree.
917  *
918  * The first matrix is the transformation to apply; the second is its inverse.
919  * The third parameter is the coordinate system we are changing to, or
920  * CS_default if we are not changing coordinate systems.
921  */
922 void EggPrimitive::
923 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) {
925 }
926 
927 /**
928  * The recursive implementation of flatten_transforms().
929  */
930 void EggPrimitive::
931 r_flatten_transforms() {
932  if (is_local_coord()) {
933  LMatrix4d mat = get_vertex_frame();
935 
936  // Transform each vertex by duplicating it in the vertex pool.
937  size_t num_vertices = size();
938  for (size_t i = 0; i < num_vertices; i++) {
939  EggVertex *vertex = get_vertex(i);
940  EggVertexPool *pool = vertex->get_pool();
941 
942  EggVertex new_vertex(*vertex);
943  new_vertex.transform(mat);
944  EggVertex *unique = pool->create_unique_vertex(new_vertex);
945  unique->copy_grefs_from(*vertex);
946 
947  set_vertex(i, unique);
948  }
949  }
950 }
951 
952 /**
953  * The recursive implementation of apply_texmats().
954  */
955 void EggPrimitive::
956 r_apply_texmats(EggTextureCollection &textures) {
957  Textures new_textures;
958  Textures::const_iterator ti;
959  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
960  EggTexture *texture = (*ti);
961 
962  if (!texture->has_transform()) {
963  new_textures.push_back(texture);
964 
965  } else if (texture->transform_is_identity()) {
966  // Now, what's the point of a texture with an identity transform?
967  texture->clear_transform();
968  new_textures.push_back(texture);
969 
970  } else {
971 
972  // We've got a texture with a matrix applied. Save the matrix, and get
973  // a new texture without the matrix.
974  LMatrix4d mat = texture->get_transform3d();
975  EggTexture new_texture(*texture);
976  new_texture.clear_transform();
977  EggTexture *unique = textures.create_unique_texture(new_texture, ~0);
978 
979  new_textures.push_back(unique);
980  std::string uv_name = unique->get_uv_name();
981 
982  // Now apply the matrix to the vertex UV's. Create new vertices as
983  // necessary.
984  size_t num_vertices = size();
985  for (size_t i = 0; i < num_vertices; i++) {
986  EggVertex *vertex = get_vertex(i);
987 
988  const EggVertexUV *uv_obj = vertex->get_uv_obj(uv_name);
989  if (uv_obj != nullptr) {
990  EggVertex new_vertex(*vertex);
991  PT(EggVertexUV) new_uv_obj = new EggVertexUV(*uv_obj);
992  LTexCoord3d uvw = uv_obj->get_uvw() * mat;
993  if (uv_obj->has_w() || texture->has_transform3d()) {
994  new_uv_obj->set_uvw(uvw);
995  } else {
996  new_uv_obj->set_uv(LTexCoordd(uvw[0], uvw[1]));
997  }
998  new_vertex.set_uv_obj(new_uv_obj);
999 
1000  EggVertexPool *pool = vertex->get_pool();
1001  EggVertex *unique = pool->create_unique_vertex(new_vertex);
1002  unique->copy_grefs_from(*vertex);
1003 
1004  set_vertex(i, unique);
1005  }
1006  }
1007  }
1008  }
1009 
1010  _textures.swap(new_textures);
1011 }
1012 
1013 /**
1014  * This is used to implement apply_first_attribute() and
1015  * apply_last_attribute(). It copies the indicated attributes to the
1016  * specified vertex.
1017  */
1018 void EggPrimitive::
1019 do_apply_flat_attribute(int vertex_index, EggAttributes *attrib) {
1020  // The significant_change flag is set if we have changed the vertex in some
1021  // important way, that will invalidate it for other primitives that might
1022  // share it. We don't consider *adding* a normal where there wasn't one
1023  // before to be significant, but we do consider it significant to change a
1024  // vertex's normal to something different. Similarly for color.
1025  bool significant_change = false;
1026 
1027  EggVertex *orig_vertex = get_vertex(vertex_index);
1028  PT(EggVertex) new_vertex = new EggVertex(*orig_vertex);
1029 
1030  if (attrib->has_normal()) {
1031  new_vertex->copy_normal(*attrib);
1032 
1033  if (orig_vertex->has_normal() &&
1034  !orig_vertex->matches_normal(*new_vertex)) {
1035  significant_change = true;
1036  }
1037  } else if (has_normal()) {
1038  new_vertex->copy_normal(*this);
1039 
1040  if (orig_vertex->has_normal() &&
1041  !orig_vertex->matches_normal(*new_vertex)) {
1042  significant_change = true;
1043  }
1044  }
1045 
1046  if (attrib->has_color()) {
1047  new_vertex->copy_color(*attrib);
1048 
1049  if (orig_vertex->has_color() &&
1050  !orig_vertex->matches_color(*new_vertex)) {
1051  significant_change = true;
1052  }
1053  } else if (has_color()) {
1054  new_vertex->copy_color(*this);
1055 
1056  if (orig_vertex->has_color() &&
1057  !orig_vertex->matches_color(*new_vertex)) {
1058  significant_change = true;
1059  }
1060  }
1061 
1062  if (significant_change) {
1063  new_vertex = get_pool()->create_unique_vertex(*new_vertex);
1064  new_vertex->copy_grefs_from(*orig_vertex);
1065  set_vertex(vertex_index, new_vertex);
1066  } else {
1067  // Just copy the new attributes back into the pool.
1068  ((EggAttributes *)orig_vertex)->operator = (*new_vertex);
1069  }
1070 }
1071 
1072 /**
1073  * Recursively updates the connected_shading member in all connected
1074  * primitives.
1075  */
1076 void EggPrimitive::
1077 set_connected_shading(EggPrimitive::Shading shading,
1078  const EggAttributes *neighbor) {
1079  ConnectedShadingNodes connected_nodes;
1080 
1081  r_set_connected_shading(0, shading, neighbor, connected_nodes);
1082 
1083  // Pick up any additional nodes we couldn't visit because of the stack depth
1084  // restrictions.
1085  while (!connected_nodes.empty()) {
1086  ConnectedShadingNodes next_nodes;
1087  next_nodes.swap(connected_nodes);
1088 
1089  ConnectedShadingNodes::iterator ni;
1090  for (ni = next_nodes.begin(); ni != next_nodes.end(); ++ni) {
1091  r_set_connected_shading(0, (*ni)._shading, (*ni)._neighbor, connected_nodes);
1092  }
1093  }
1094 }
1095 
1096 /**
1097  * Implements set_connected_shading, with some restrictions to prevent stack
1098  * overflow.
1099  */
1100 void EggPrimitive::
1101 r_set_connected_shading(int stack_depth, EggPrimitive::Shading shading,
1102  const EggAttributes *neighbor,
1103  ConnectedShadingNodes &next_nodes) {
1104  if (stack_depth > egg_recursion_limit) {
1105  // Too deep. Limit recursion.
1106  ConnectedShadingNode next;
1107  next._shading = shading;
1108  next._neighbor = neighbor;
1109  next_nodes.push_back(next);
1110  return;
1111  }
1112 
1113  bool propagate = false;
1114 
1115  if (_connected_shading == S_unknown) {
1116  // We haven't visited this node before; propagate now.
1117  _connected_shading = get_shading();
1118  propagate = true;
1119  }
1120 
1121  if (shading > _connected_shading) {
1122  // More specific information just came in. Save it, and propagate it to
1123  // all connected primitives.
1124  _connected_shading = shading;
1125  propagate = true;
1126 
1127  } else if (shading == S_overall && _connected_shading == S_overall) {
1128  // If both neighbors are overall shaded, check if the two neighbors have
1129  // different properties. If they do, elevate to per_face.
1130  bool matches_normal = this->matches_normal(*neighbor);
1131  bool matches_color = this->matches_color(*neighbor);
1132 
1133  if (!matches_color) {
1134  // Make a special case for not having an overall color: that's
1135  // implicitly white.
1136  if (!neighbor->has_color() && has_color() && _drgbas.empty() &&
1137  get_color() == LColor(1.0f, 1.0f, 1.0f, 1.0f)) {
1138  matches_color = true;
1139  } else if (!has_color() && neighbor->has_color() && neighbor->_drgbas.empty() &&
1140  neighbor->get_color() == LColor(1.0f, 1.0f, 1.0f, 1.0f)) {
1141  matches_color = true;
1142  }
1143  }
1144  if (!matches_normal || !matches_color) {
1145  _connected_shading = S_per_face;
1146  propagate = true;
1147  }
1148  }
1149 
1150  if (propagate) {
1151  Vertices::const_iterator vi;
1152  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1153  EggVertex *vertex = (*vi);
1154  EggVertex::PrimitiveRef::const_iterator pi;
1155  for (pi = vertex->pref_begin();
1156  pi != vertex->pref_end();
1157  ++pi) {
1158  (*pi)->r_set_connected_shading(stack_depth + 1, _connected_shading, this,
1159  next_nodes);
1160  }
1161  }
1162  }
1163 }
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
get_material
Returns a pointer to the applied material, or NULL if there is no material applied.
Definition: eggPrimitive.h:115
AlphaMode get_alpha_mode() const
Returns the alpha mode that was set, or AM_unspecified if nothing was set.
Definition: eggRenderMode.I:98
bool transform_is_identity() const
Returns true if the described transform is identity, false otherwise.
Definition: eggTransform.I:220
VisibilityMode get_visibility_mode() const
Returns the visibility mode that was set, or VM_unspecified if nothing was set.
Definition: eggRenderMode.I:75
virtual void unify_attributes(Shading shading)
If the shading property is S_per_vertex, ensures that all vertices have a normal and a color,...
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:212
void clear_transform()
Resets the transform to empty, identity.
Definition: eggTransform.I:114
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
virtual EggRenderMode * determine_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
const EggVertexUV * get_uv_obj(const std::string &name) const
Returns the named EggVertexUV object, which defines both the UV coordinate pair for this name and the...
Definition: eggVertex.cxx:245
EggTexture * create_unique_texture(const EggTexture &copy, int eq)
Creates a new texture if there is not already one equivalent (according to eq, see EggTexture::is_equ...
get_uv_name
Returns the texcoord name that has been specified for this texture, or the empty string if no texcoor...
Definition: eggTexture.h:337
bool has_bin() const
Returns true if a bin name has been set for this particular object.
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color,...
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:19
virtual void apply_last_attribute()
Sets the last vertex of the triangle (or each component) to the primitive normal and/or color,...
const LMatrix4d & get_vertex_frame() const
Returns the coordinate frame of the vertices referenced by primitives at or under this node.
Definition: eggNode.I:108
virtual bool cleanup()
Cleans up modeling errors in whatever context this makes sense.
const LTexCoord3d & get_uvw() const
Returns the texture coordinate triple, if get_num_dimensions() is 3.
Definition: eggVertexUV.I:68
ostream & enquote_string(ostream &out, const string &str, int indent_level, bool always_quote)
Writes the string to the indicated output stream.
void clear()
Removes all of the vertices from the primitive.
Definition: eggPrimitive.I:352
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
bool has_vertex_color() const
Returns true if any vertex on the primitive has a specific color set, false otherwise.
virtual EggRenderMode * determine_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:160
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the attributes.
void copy_vertices(const EggPrimitive &other)
Replaces the current primitive's list of vertices with a copy of the list of vertices on the other pr...
virtual EggRenderMode * determine_depth_test_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:115
void copy_normal(const EggAttributes &other)
Sets this normal to be the same as the other's, include morphs.
Definition: eggAttributes.I:69
set_bface_flag
Sets the backfacing flag of the polygon.
Definition: eggPrimitive.h:116
bool affects_polygon_alpha() const
Returns true if this texture's environment type or combine mode allows the texture to have an effect ...
Definition: eggTexture.cxx:541
void copy_attributes(const EggAttributes &other)
Copies the rendering attributes from the indicated primitive.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_shading
Returns the shading properties apparent on this particular primitive.
Definition: eggPrimitive.h:111
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
This is a collection of textures by TRef name.
virtual EggRenderMode * determine_alpha_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
set_material
Applies the indicated material to the primitive.
Definition: eggPrimitive.h:115
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
remove_vertex
Removes the indicated vertex from the primitive and returns it.
Definition: eggPrimitive.h:191
LColor get_color() const
Returns the color set on this particular attribute.
Definition: eggAttributes.I:91
bool matches_color(const EggAttributes &other) const
Returns true if this color matches that of the other EggAttributes object, include the morph list.
bool has_vertex_normal() const
Returns true if any vertex on the primitive has a specific normal set, false otherwise.
get_vertex
Returns a particular index based on its index number.
Definition: eggPrimitive.h:187
DepthWriteMode get_depth_write_mode() const
Returns the depth_write mode that was set, or DWM_unspecified if nothing was set.
Definition: eggRenderMode.I:36
bool matches_normal(const EggAttributes &other) const
Returns true if this normal matches that of the other EggAttributes object, include the morph list.
Definition: eggAttributes.I:53
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
set_vertex
Replaces a particular vertex based on its index number in the list of vertices.
Definition: eggPrimitive.h:191
This class stores miscellaneous rendering properties that is associated with geometry,...
Definition: eggRenderMode.h:31
The set of attributes that may be applied to vertices as well as polygons, such as surface normal and...
Definition: eggAttributes.h:33
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:277
virtual EggRenderMode * determine_depth_test_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
virtual bool has_primitives() const
Returns true if there are any primitives (e.g.
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
bool is_local_coord() const
Returns true if this node's vertices are not in the global coordinate space.
Definition: eggNode.I:87
virtual void reverse_vertex_ordering()
Reverses the ordering of the vertices in this primitive, if appropriate, in order to change the direc...
void copy_color(const EggAttributes &other)
Sets this color to be the same as the other's, include morphs.
virtual void post_apply_flat_attribute()
Intended as a followup to apply_last_attribute(), this also sets an attribute on the first vertices o...
virtual EggRenderMode * determine_visibility_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:130
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
void remove_nonunique_verts()
Removes any multiple appearances of the same vertex from the primitive.
virtual bool joint_has_primitives() const
Returns true if there are any primitives (e.g.
PrimitiveRef::const_iterator pref_end() const
Returns an iterator that can, in conjunction with pref_begin(), be used to traverse the entire set of...
Definition: eggVertex.cxx:805
iterator find(EggVertex *vertex)
Returns the iterator pointing to the indicated vertex, or end() if the vertex is not part of the prim...
virtual EggRenderMode * determine_depth_offset()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
virtual bool has_normals() const
Returns true if any of the primitives (e.g.
void write_long_list(std::ostream &out, int indent_level, InputIterator ifirst, InputIterator ilast, std::string first_prefix="", std::string later_prefix="", int max_col=72)
Writes a list of things to the indicated output stream, with a space separating each item.
Definition: indent.I:22
virtual EggRenderMode * determine_depth_write_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:100
virtual EggRenderMode * determine_alpha_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:85
int has_pref(const EggPrimitive *prim) const
Returns the number of times the vertex appears in the indicated primitive, or 0 if it does not appear...
Definition: eggVertex.cxx:824
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
bool has_draw_order() const
Returns true if the draw-order flag has been set for this particular object.
virtual EggRenderMode * determine_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:174
bool has_transform3d() const
Returns true if the transform is specified as a 3-d transform, e.g.
Definition: eggTransform.I:179
get_num_textures
Returns the number of textures applied to the primitive.
Definition: eggPrimitive.h:100
virtual EggRenderMode * determine_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
Definition: eggPrimitive.h:192
get_texture
Returns the first texture on the primitive, if any, or NULL if there are no textures on the primitive...
Definition: eggPrimitive.h:100
bool has_depth_offset() const
Returns true if the depth-offset flag has been set for this particular object.
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
Definition: eggPrimitive.I:335
virtual EggRenderMode * determine_visibility_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
get_bface_flag
Retrieves the backfacing flag of the polygon.
Definition: eggPrimitive.h:116
void remove_doubled_verts(bool closed)
Certain kinds of primitives, particularly polygons, don't like to have the same vertex repeated conse...
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
Definition: eggVertex.cxx:747
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:44
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PrimitiveRef::const_iterator pref_begin() const
Returns an iterator that can, in conjunction with pref_end(), be used to traverse the entire set of p...
Definition: eggVertex.cxx:793
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual EggRenderMode * determine_depth_offset()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:145
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DepthTestMode get_depth_test_mode() const
Returns the depth_test mode that was set, or DTM_unspecified if nothing was set.
Definition: eggRenderMode.I:55
virtual EggRenderMode * determine_depth_write_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
has_material
Returns true if the primitive is materiald (and get_material() will return a real pointer),...
Definition: eggPrimitive.h:115
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
Definition: eggTransform.I:143