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