Panda3D
Loading...
Searching...
No Matches
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"
18#include "lexerDefs.h"
19#include "config_egg.h"
20
21#include "indent.h"
22#include "vector_int.h"
23
24TypeHandle 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 */
218EggPrimitive::Shading EggPrimitive::
219get_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 */
265copy_attributes(const EggAttributes &other) {
266 EggAttributes::operator = (other);
267}
268
269/**
270 * Copies the rendering attributes from the indicated primitive.
271 */
273copy_attributes(const EggPrimitive &other) {
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 */
289has_vertex_normal() const {
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 */
308has_vertex_color() const {
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 */
337unify_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 */
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 */
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 */
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 */
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 */
499cleanup() {
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 */
517remove_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 */
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 */
585has_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 */
594joint_has_primitives() const {
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 */
603has_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 */
623EggPrimitive::iterator EggPrimitive::
624erase(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 */
642EggPrimitive::iterator EggPrimitive::
643find(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 */
654add_vertex(EggVertex *vertex) {
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 */
669remove_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 */
689remove_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 */
704copy_vertices(const EggPrimitive &other) {
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 */
723void EggPrimitive::
724test_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;
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 */
772void EggPrimitive::
773prepare_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 */
800void EggPrimitive::
801prepare_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 */
823void EggPrimitive::
824write_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 */
907bool EggPrimitive::
908egg_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 */
922void EggPrimitive::
923r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) {
925}
926
927/**
928 * The recursive implementation of flatten_transforms().
929 */
930void EggPrimitive::
931r_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 */
955void EggPrimitive::
956r_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 */
1018void EggPrimitive::
1019do_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 */
1076void EggPrimitive::
1077set_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 */
1100void EggPrimitive::
1101r_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}
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 transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the attributes.
void copy_normal(const EggAttributes &other)
Sets this normal to be the same as the other's, include morphs.
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.
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
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
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
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
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 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
bool is_local_coord() const
Returns true if this node's vertices are not in the global coordinate space.
Definition eggNode.I:87
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
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
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
set_bface_flag
Sets the backfacing flag of the polygon.
virtual void unify_attributes(Shading shading)
If the shading property is S_per_vertex, ensures that all vertices have a normal and a color,...
get_material
Returns a pointer to the applied material, or NULL if there is no material applied.
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
get_shading
Returns the shading properties apparent on this particular primitive.
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...
set_material
Applies the indicated material to the primitive.
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.
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color,...
virtual EggRenderMode * determine_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
void copy_attributes(const EggAttributes &other)
Copies the rendering attributes from the indicated primitive.
virtual bool joint_has_primitives() const
Returns true if there are any primitives (e.g.
set_vertex
Replaces a particular vertex based on its index number in the list of vertices.
virtual EggRenderMode * determine_depth_test_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
get_bface_flag
Retrieves the backfacing flag of the polygon.
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
void replace(iterator position, EggVertex *vertex)
Replaces the vertex at the indicated position with the indicated vertex.
virtual bool has_normals() const
Returns true if any of the primitives (e.g.
get_num_textures
Returns the number of textures applied to the primitive.
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...
virtual void reverse_vertex_ordering()
Reverses the ordering of the vertices in this primitive, if appropriate, in order to change the direc...
virtual EggRenderMode * determine_depth_offset()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
remove_vertex
Removes the indicated vertex from the primitive and returns it.
bool has_vertex_color() const
Returns true if any vertex on the primitive has a specific color set, false otherwise.
void remove_doubled_verts(bool closed)
Certain kinds of primitives, particularly polygons, don't like to have the same vertex repeated conse...
void clear()
Removes all of the vertices from the primitive.
void remove_nonunique_verts()
Removes any multiple appearances of the same vertex from the primitive.
virtual EggRenderMode * determine_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
iterator find(EggVertex *vertex)
Returns the iterator pointing to the indicated vertex, or end() if the vertex is not part of the prim...
get_texture
Returns the first texture on the primitive, if any, or NULL if there are no textures on the primitive...
virtual EggRenderMode * determine_depth_write_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.
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.
has_material
Returns true if the primitive is materiald (and get_material() will return a real pointer),...
virtual EggRenderMode * determine_alpha_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
This class stores miscellaneous rendering properties that is associated with geometry,...
bool has_bin() const
Returns true if a bin name has been set for this particular object.
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
DepthTestMode get_depth_test_mode() const
Returns the depth_test mode that was set, or DTM_unspecified if nothing was set.
DepthWriteMode get_depth_write_mode() const
Returns the depth_write mode that was set, or DWM_unspecified if nothing was set.
VisibilityMode get_visibility_mode() const
Returns the visibility mode that was set, or VM_unspecified if nothing was set.
bool has_draw_order() const
Returns true if the draw-order flag has been set for this particular object.
bool has_depth_offset() const
Returns true if the depth-offset flag has been set for this particular object.
AlphaMode get_alpha_mode() const
Returns the alpha mode that was set, or AM_unspecified if nothing was set.
This is a collection of textures by TRef name.
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...
Defines a texture map that may be applied to geometry.
Definition eggTexture.h:30
get_uv_name
Returns the texcoord name that has been specified for this texture, or the empty string if no texcoor...
Definition eggTexture.h:341
bool affects_polygon_alpha() const
Returns true if this texture's environment type or combine mode allows the texture to have an effect ...
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
bool has_transform3d() const
Returns true if the transform is specified as a 3-d transform, e.g.
void clear_transform()
Resets the transform to empty, identity.
bool transform_is_identity() const
Returns true if the described transform is identity, false otherwise.
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.
The set of UV's that may or may not be assigned to a vertex.
Definition eggVertexUV.h:29
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
const LTexCoord3d & get_uvw() const
Returns the texture coordinate triple, if get_num_dimensions() is 3.
Definition eggVertexUV.I:68
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
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...
int get_index() const
Returns the index number of the vertex within its pool.
Definition eggVertex.I:277
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...
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...
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition eggVertex.I:19
PrimitiveRef::const_iterator pref_end() const
Returns an iterator that can, in conjunction with pref_begin(), be used to traverse the entire set of...
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition namable.I:44
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
This is our own Panda specialization on the default STL set.
Definition pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ostream & enquote_string(ostream &out, const string &str, int indent_level, bool always_quote)
Writes the string to the indicated output stream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.