Panda3D
 All Classes Functions Variables Enumerations
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 ////////////////////////////////////////////////////////////////////
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 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
bool matches_color(const EggAttributes &other) const
Returns true if this color matches that of the other EggAttributes object, include the morph list...
The base class for primitives such as triangle strips and triangle fans, which include several compon...
LColor get_color() const
Returns the color set on this particular attribute.
virtual Shading get_shading() const
Returns the shading properties apparent on this particular primitive.
void write(ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
void copy_normal(const EggAttributes &other)
Sets this normal to be the same as the other&#39;s, include morphs.
Definition: eggAttributes.I:84
int compare_to(const EggAttributes &other) const
An ordering operator to compare two vertices for sorting order.
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...
const EggAttributes * get_component(int i) const
Returns the attributes for the nth component triangle.
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
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
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
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:25
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color...
EggVertex * get_vertex(int index) const
Returns a particular index based on its index number.
Definition: eggPrimitive.I:466
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
int get_num_components() const
Returns the number of individual component triangles within the composite.