Panda3D
Loading...
Searching...
No Matches
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
15#include "eggGroupNode.h"
16#include "eggVertexPool.h"
17
18TypeHandle EggCompositePrimitive::_type_handle;
19
20
21/**
22 *
23 */
24EggCompositePrimitive::
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 */
44EggPrimitive::Shading EggCompositePrimitive::
45get_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 */
100PT(EggCompositePrimitive) EggCompositePrimitive::
101triangulate_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 */
131unify_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 */
361cleanup() {
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 */
373void EggCompositePrimitive::
374prepare_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 */
397void EggCompositePrimitive::
398prepare_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 */
420bool EggCompositePrimitive::
421do_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 */
430void EggCompositePrimitive::
431write_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}
The set of attributes that may be applied to vertices as well as polygons, such as surface normal and...
bool matches_normal(const EggAttributes &other) const
Returns true if this normal matches that of the other EggAttributes object, include the morph list.
void copy_normal(const EggAttributes &other)
Sets this normal to be the same as the other's, include morphs.
int compare_to(const EggAttributes &other) const
An ordering operator to compare two vertices for sorting order.
void copy_color(const EggAttributes &other)
Sets this color to be the same as the other's, include morphs.
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.
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
The base class for primitives such as triangle strips and triangle fans, which include several compon...
virtual void apply_last_attribute()
Sets the last 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...
get_num_components
Returns the number of individual component triangles within the composite.
get_component
Returns the attributes for the nth component triangle.
virtual void unify_attributes(Shading shading)
If the shading property is S_per_vertex, ensures that all vertices have a normal and a color,...
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color,...
virtual Shading get_shading() const
Returns the shading properties apparent on this particular primitive.
virtual bool cleanup()
Cleans up modeling errors in whatever context this makes sense.
A base class for nodes in the hierarchy that are not leaf nodes.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
get_shading
Returns the shading properties apparent on this particular primitive.
get_vertex
Returns a particular index based on its index number.
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
A collection of vertices.
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.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition eggVertex.I:19
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20