Panda3D
eggCompositePrimitive.cxx
1 // Filename: eggCompositePrimitive.cxx
2 // Created by: drose (13Mar05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eggCompositePrimitive.h"
16 #include "eggGroupNode.h"
17 #include "eggVertexPool.h"
18 
19 TypeHandle EggCompositePrimitive::_type_handle;
20 
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: EggCompositePrimitive::Destructor
24 // Access: Published, Virtual
25 // Description:
26 ////////////////////////////////////////////////////////////////////
27 EggCompositePrimitive::
28 ~EggCompositePrimitive() {
29  // Every derived class of EggCompositePrimitive must call clear() in
30  // its destructor.
31  nassertv(_components.empty());
32 }
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: EggCompositePrimitive::get_shading
36 // Access: Published, Virtual
37 // Description: Returns the shading properties apparent on this
38 // particular primitive. This returns S_per_vertex if
39 // the vertices have colors or normals (and they are not
40 // all the same values), or for a simple primitive,
41 // S_overall otherwise. A composite primitive may also
42 // return S_per_face if the individual component
43 // primitives have colors or normals that are not all
44 // the same values.
45 //
46 // To get the most accurate results, you should call
47 // clear_shading() on all connected primitives (or on
48 // all primitives in the egg file), followed by
49 // get_shading() on each primitive. You may find it
50 // easiest to call these methods on the EggData root
51 // node (they are defined on EggGroupNode).
52 ////////////////////////////////////////////////////////////////////
53 EggPrimitive::Shading EggCompositePrimitive::
54 get_shading() const {
55  Shading basic_shading = EggPrimitive::get_shading();
56  if (basic_shading == S_per_vertex) {
57  return basic_shading;
58  }
59  if (_components.empty()) {
60  return S_overall;
61  }
62 
63  // Check if the components all have the same normal.
64  {
65  const EggAttributes *first_component = get_component(0);
66  if (!first_component->has_normal()) {
67  first_component = this;
68  }
69  for (int i = 1; i < get_num_components(); i++) {
70  const EggAttributes *component = get_component(i);
71  if (!component->has_normal()) {
72  component = this;
73  }
74  if (!component->matches_normal(*first_component)) {
75  return S_per_face;
76  }
77  }
78  }
79 
80  // Check if the components all have the same color.
81  {
82  const EggAttributes *first_component = get_component(0);
83  if (!first_component->has_color()) {
84  first_component = this;
85  }
86  for (int i = 1; i < get_num_components(); i++) {
87  const EggAttributes *component = get_component(i);
88  if (!component->has_color()) {
89  component = this;
90  }
91  if (!component->matches_color(*first_component)) {
92  return S_per_face;
93  }
94  }
95  }
96 
97  return S_overall;
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: EggCompositePrimitive::triangulate_in_place
102 // Access: Published
103 // Description: Subdivides the composite primitive into triangles and
104 // adds those triangles to the parent group node in
105 // place of the original primitive. Returns a pointer
106 // to the original primitive, which is likely about to
107 // be destructed.
108 //
109 // If convex_also is true, both concave and convex
110 // polygons will be subdivided into triangles;
111 // otherwise, only concave polygons will be subdivided,
112 // and convex polygons will be copied unchanged into the
113 // container.
114 ////////////////////////////////////////////////////////////////////
115 PT(EggCompositePrimitive) EggCompositePrimitive::
116 triangulate_in_place() {
117  EggGroupNode *parent = get_parent();
118  nassertr(parent != (EggGroupNode *)NULL, this);
119 
120  PT(EggCompositePrimitive) save_me = this;
121  parent->remove_child(this);
122  do_triangulate(parent);
123 
124  return save_me;
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: EggCompositePrimitive::unify_attributes
129 // Access: Published, Virtual
130 // Description: If the shading property is S_per_vertex, ensures that
131 // all vertices have a normal and a color, and the
132 // overall primitive does not.
133 //
134 // If the shading property is S_per_face, and this is a
135 // composite primitive, ensures that all components have
136 // a normal and a color, and the vertices and overall
137 // primitive do not. (If this is a simple primitive,
138 // S_per_face works the same as S_overall, below).
139 //
140 // If the shading property is S_overall, ensures that no
141 // vertices or components have a normal or a color, and
142 // the overall primitive does (if any exists at all).
143 //
144 // After this call, either the primitive will have
145 // normals or its vertices will, but not both. Ditto
146 // for colors.
147 //
148 // This may create redundant vertices in the vertex
149 // pool.
150 ////////////////////////////////////////////////////////////////////
152 unify_attributes(EggPrimitive::Shading shading) {
153  if (shading == S_unknown) {
154  shading = get_shading();
155  }
156 
157  switch (shading) {
158  case S_per_vertex:
159  // Propagate everything to the vertices.
160  {
161  Components::iterator ci;
162  for (ci = _components.begin(); ci != _components.end(); ++ci) {
163  EggAttributes *component = (*ci);
164  if (component->has_normal()) {
165  if (!has_normal()) {
166  copy_normal(*component);
167  }
168  component->clear_normal();
169  }
170  if (component->has_color()) {
171  if (!has_color()) {
172  copy_color(*component);
173  }
174  component->clear_color();
175  }
176  }
177 
178  // Not having a color is implicitly white.
179  if (!has_color()) {
180  set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
181  }
182 
183  iterator pi;
184  for (pi = begin(); pi != end(); ++pi) {
185  EggVertex *orig_vertex = (*pi);
186  PT(EggVertex) vertex = new EggVertex(*orig_vertex);
187  if (!vertex->has_normal() && has_normal()) {
188  vertex->copy_normal(*this);
189  }
190  if (!vertex->has_color() && has_color()) {
191  vertex->copy_color(*this);
192  }
193 
194  EggVertexPool *vertex_pool = orig_vertex->get_pool();
195  nassertv(vertex_pool != (EggVertexPool *)NULL);
196  vertex = vertex_pool->create_unique_vertex(*vertex);
197  vertex->copy_grefs_from(*orig_vertex);
198  replace(pi, vertex);
199  }
200  clear_normal();
201  clear_color();
202  }
203  break;
204 
205  case S_per_face:
206  // Propagate everything to the components.
207  {
208  iterator pi;
209  for (pi = begin(); pi != end(); ++pi) {
210  EggVertex *orig_vertex = (*pi);
211  if (orig_vertex->has_normal() || orig_vertex->has_color()) {
212  if (orig_vertex->has_normal() && !has_normal()) {
213  copy_normal(*orig_vertex);
214  }
215  if (orig_vertex->has_color() && !has_color()) {
216  copy_color(*orig_vertex);
217  }
218 
219  PT(EggVertex) vertex = new EggVertex(*orig_vertex);
220  vertex->clear_normal();
221  vertex->clear_color();
222 
223  EggVertexPool *vertex_pool = orig_vertex->get_pool();
224  nassertv(vertex_pool != (EggVertexPool *)NULL);
225  vertex = vertex_pool->create_unique_vertex(*vertex);
226  vertex->copy_grefs_from(*orig_vertex);
227  replace(pi, vertex);
228  }
229  }
230 
231  // Not having a color is implicitly white.
232  if (!has_color()) {
233  set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
234  }
235 
236  Components::iterator ci;
237  for (ci = _components.begin(); ci != _components.end(); ++ci) {
238  EggAttributes *component = (*ci);
239  if (!component->has_normal() && has_normal()) {
240  component->copy_normal(*this);
241  }
242  if (!component->has_color() && has_color()) {
243  component->copy_color(*this);
244  }
245  }
246  clear_normal();
247  clear_color();
248  }
249  break;
250 
251  case S_overall:
252  // Remove everything from the vertices and components.
253  {
254  iterator pi;
255  for (pi = begin(); pi != end(); ++pi) {
256  EggVertex *orig_vertex = (*pi);
257  PT(EggVertex) vertex = new EggVertex(*orig_vertex);
258  if (vertex->has_normal()) {
259  if (!has_normal()) {
260  copy_normal(*vertex);
261  }
262  vertex->clear_normal();
263  }
264  if (vertex->has_color()) {
265  if (!has_color()) {
266  copy_color(*vertex);
267  }
268  vertex->clear_color();
269  }
270 
271  EggVertexPool *vertex_pool = orig_vertex->get_pool();
272  nassertv(vertex_pool != (EggVertexPool *)NULL);
273  vertex = vertex_pool->create_unique_vertex(*vertex);
274  vertex->copy_grefs_from(*orig_vertex);
275  replace(pi, vertex);
276  }
277  Components::iterator ci;
278  for (ci = _components.begin(); ci != _components.end(); ++ci) {
279  EggAttributes *component = (*ci);
280  if (component->has_normal()) {
281  if (!has_normal()) {
282  copy_normal(*component);
283  }
284  component->clear_normal();
285  }
286  if (component->has_color()) {
287  if (!has_color()) {
288  copy_color(*component);
289  }
290  component->clear_color();
291  }
292  }
293 
294  // Not having a color is implicitly white.
295  if (!has_color()) {
296  set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f));
297  }
298  }
299  break;
300 
301  case S_unknown:
302  break;
303  }
304 }
305 
306 ////////////////////////////////////////////////////////////////////
307 // Function: EggCompositePrimitive::apply_last_attribute
308 // Access: Published, Virtual
309 // Description: Sets the last vertex of the triangle (or each
310 // component) to the primitive normal and/or color, if
311 // the primitive is flat-shaded. This reflects the
312 // OpenGL convention of storing flat-shaded properties on
313 // the last vertex, although it is not usually a
314 // convention in Egg.
315 //
316 // This may introduce redundant vertices to the vertex
317 // pool.
318 ////////////////////////////////////////////////////////////////////
321  // The first component gets applied to the third vertex, and so on
322  // from there.
323  int num_lead_vertices = get_num_lead_vertices();
324  for (int i = 0; i < get_num_components(); i++) {
325  EggAttributes *component = get_component(i);
326  do_apply_flat_attribute(i + num_lead_vertices, component);
327  }
328 }
329 
330 ////////////////////////////////////////////////////////////////////
331 // Function: EggCompositePrimitive::apply_first_attribute
332 // Access: Published, Virtual
333 // Description: Sets the first vertex of the triangle (or each
334 // component) to the primitive normal and/or color, if
335 // the primitive is flat-shaded. This reflects the
336 // DirectX convention of storing flat-shaded properties
337 // on the first vertex, although it is not usually a
338 // convention in Egg.
339 //
340 // This may introduce redundant vertices to the vertex
341 // pool.
342 ////////////////////////////////////////////////////////////////////
345  // The first component gets applied to the first vertex, and so on
346  // from there.
347  for (int i = 0; i < get_num_components(); i++) {
348  EggAttributes *component = get_component(i);
349  do_apply_flat_attribute(i, component);
350  }
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function: EggCompositePrimitive::post_apply_flat_attribute
355 // Access: Published, Virtual
356 // Description: Intended as a followup to apply_last_attribute(),
357 // this also sets an attribute on the first vertices of
358 // the primitive, if they don't already have an
359 // attribute set, just so they end up with *something*.
360 ////////////////////////////////////////////////////////////////////
363  if (!empty()) {
364  int num_lead_vertices = get_num_lead_vertices();
365  for (int i = 0; i < (int)size(); i++) {
366  EggVertex *vertex = get_vertex(i);
367  EggAttributes *component = get_component(max(i - num_lead_vertices, 0));
368 
369  // Use set_normal() instead of copy_normal(), to avoid getting
370  // the morphs--we don't want them here, since we're just putting
371  // a bogus value on the normal anyway.
372 
373  if (component->has_normal() && !vertex->has_normal()) {
374  vertex->set_normal(component->get_normal());
375  } else if (has_normal() && !vertex->has_normal()) {
376  vertex->set_normal(get_normal());
377  }
378 
379  if (component->has_color() && !vertex->has_color()) {
380  vertex->set_color(component->get_color());
381  } else if (has_color() && !vertex->has_color()) {
382  vertex->set_color(get_color());
383  }
384  }
385  }
386 }
387 
388 ////////////////////////////////////////////////////////////////////
389 // Function: EggCompositePrimitive::cleanup
390 // Access: Published, Virtual
391 // Description: Cleans up modeling errors in whatever context this
392 // makes sense. For instance, for a polygon, this calls
393 // remove_doubled_verts(true). For a point, it calls
394 // remove_nonunique_verts(). Returns true if the
395 // primitive is valid, or false if it is degenerate.
396 ////////////////////////////////////////////////////////////////////
399  return (int)size() >= get_num_lead_vertices() + 1;
400 }
401 
402 ////////////////////////////////////////////////////////////////////
403 // Function: EggCompositePrimitive::prepare_add_vertex
404 // Access: Protected, Virtual
405 // Description: Marks the vertex as belonging to the primitive. This
406 // is an internal function called by the STL-like
407 // functions push_back() and insert(), in preparation
408 // for actually adding the vertex.
409 //
410 // i indicates the new position of the vertex in the
411 // list; n indicates the new number of vertices after
412 // the operation has completed.
413 ////////////////////////////////////////////////////////////////////
414 void EggCompositePrimitive::
415 prepare_add_vertex(EggVertex *vertex, int i, int n) {
416  EggPrimitive::prepare_add_vertex(vertex, i, n);
417 
418  int num_lead_vertices = get_num_lead_vertices();
419  if (n >= num_lead_vertices + 1) {
420  i = max(i - num_lead_vertices, 0);
421  nassertv(i <= (int)_components.size());
422  _components.insert(_components.begin() + i, new EggAttributes(*this));
423  }
424 }
425 
426 
427 ////////////////////////////////////////////////////////////////////
428 // Function: EggCompositePrimitive::prepare_remove_vertex
429 // Access: Protected, Virtual
430 // Description: Marks the vertex as removed from the primitive. This
431 // is an internal function called by the STL-like
432 // functions pop_back() and erase(), in preparation for
433 // actually doing the removal.
434 //
435 // i indicates the former position of the vertex in the
436 // list; n indicates the current number of vertices
437 // before the operation has completed.
438 //
439 // It is an error to attempt to remove a vertex that is
440 // not already a vertex of this primitive.
441 ////////////////////////////////////////////////////////////////////
442 void EggCompositePrimitive::
443 prepare_remove_vertex(EggVertex *vertex, int i, int n) {
444  EggPrimitive::prepare_remove_vertex(vertex, i, n);
445 
446  int num_lead_vertices = get_num_lead_vertices();
447  if (n >= num_lead_vertices + 1) {
448  i = max(i - num_lead_vertices, 0);
449  nassertv(i < (int)_components.size());
450  delete _components[i];
451  _components.erase(_components.begin() + i);
452  }
453 }
454 
455 ////////////////////////////////////////////////////////////////////
456 // Function: EggCompositePrimitive::triangulate_poly
457 // Access: Protected, Virtual
458 // Description: Fills the container up with EggPolygons that
459 // represent the component triangles of this triangle
460 // strip.
461 //
462 // It is assumed that the EggCompositePrimitive is not
463 // already a child of any other group when this function
464 // is called.
465 //
466 // Returns true if the triangulation is successful, or
467 // false if there was some error (in which case the
468 // container may contain some partial triangulation).
469 ////////////////////////////////////////////////////////////////////
470 bool EggCompositePrimitive::
471 do_triangulate(EggGroupNode *container) const {
472  container->add_child((EggCompositePrimitive *)this);
473  return true;
474 }
475 
476 ////////////////////////////////////////////////////////////////////
477 // Function: EggCompositePrimitive::write_body
478 // Access: Protected
479 // Description: Writes the attributes and the vertices referenced by
480 // the primitive to the indicated output stream in Egg
481 // format.
482 ////////////////////////////////////////////////////////////////////
483 void EggCompositePrimitive::
484 write_body(ostream &out, int indent_level) const {
485  EggPrimitive::write_body(out, indent_level);
486 
487  for (int i = 0; i < get_num_components(); i++) {
488  const EggAttributes *attrib = get_component(i);
489  if (attrib->compare_to(*this) != 0 &&
490  (attrib->has_color() || attrib->has_normal())) {
491  indent(out, indent_level)
492  << "<Component> " << i << " {\n";
493  attrib->write(out, indent_level + 2);
494  indent(out, indent_level) << "}\n";
495  }
496  }
497 }
The base class for primitives such as triangle strips and triangle fans, which include several compon...
virtual void unify_attributes(Shading shading)
If the shading property is S_per_vertex, ensures that all vertices have a normal and a color...
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:25
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
const EggAttributes * get_component(int i) const
Returns the attributes for the nth component triangle.
void copy_normal(const EggAttributes &other)
Sets this normal to be the same as the other&#39;s, include morphs.
Definition: eggAttributes.I:84
LColor get_color() const
Returns the color set on this particular attribute.
bool matches_color(const EggAttributes &other) const
Returns true if this color matches that of the other EggAttributes object, include the morph list...
virtual Shading get_shading() const
Returns the shading properties apparent on this particular primitive.
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:65
The set of attributes that may be applied to vertices as well as polygons, such as surface normal and...
Definition: eggAttributes.h:37
void copy_color(const EggAttributes &other)
Sets this color to be the same as the other&#39;s, include morphs.
virtual void apply_last_attribute()
Sets the last vertex of the triangle (or each component) to the primitive normal and/or color...
virtual bool cleanup()
Cleans up modeling errors in whatever context this makes sense.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
int get_num_components() const
Returns the number of individual component triangles within the composite.
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void write(ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
virtual Shading get_shading() const
Returns the shading properties apparent on this particular primitive.
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
Definition: eggPrimitive.I:413
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
Definition: eggVertex.cxx:848
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color...
virtual void post_apply_flat_attribute()
Intended as a followup to apply_last_attribute(), this also sets an attribute on the first vertices o...
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:46
EggVertex * get_vertex(int index) const
Returns a particular index based on its index number.
Definition: eggPrimitive.I:466
int compare_to(const EggAttributes &other) const
An ordering operator to compare two vertices for sorting order.