501 lines
18 KiB
C++
501 lines
18 KiB
C++
// Filename: eggCompositePrimitive.cxx
|
|
// Created by: drose (13Mar05)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "eggCompositePrimitive.h"
|
|
#include "eggGroupNode.h"
|
|
|
|
TypeHandle EggCompositePrimitive::_type_handle;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::Destructor
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
EggCompositePrimitive::
|
|
~EggCompositePrimitive() {
|
|
// Every derived class of EggCompositePrimitive must call clear() in
|
|
// its destructor.
|
|
nassertv(_components.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::get_shading
|
|
// Access: Published, Virtual
|
|
// Description: Returns the shading properties apparent on this
|
|
// particular primitive. This returns S_per_vertex if
|
|
// the vertices have colors or normals (and they are not
|
|
// all the same values), or for a simple primitive,
|
|
// S_overall otherwise. A composite primitive may also
|
|
// return S_per_face if the individual component
|
|
// primitives have colors or normals that are not all
|
|
// the same values.
|
|
//
|
|
// To get the most accurate results, you should call
|
|
// clear_shading() on all connected primitives (or on
|
|
// all primitives in the egg file), followed by
|
|
// determine_shading() on each primitive. You may find
|
|
// it easiest to call these methods on the EggData root
|
|
// node (they are defined on EggGroupNode).
|
|
////////////////////////////////////////////////////////////////////
|
|
EggPrimitive::Shading EggCompositePrimitive::
|
|
get_shading() const {
|
|
Shading basic_shading = EggPrimitive::get_shading();
|
|
if (basic_shading == S_per_vertex) {
|
|
return basic_shading;
|
|
}
|
|
if (_components.empty()) {
|
|
return S_overall;
|
|
}
|
|
|
|
// Check if the components all have the same normal.
|
|
{
|
|
const EggAttributes *first_component = get_component(0);
|
|
if (!first_component->has_normal()) {
|
|
first_component = this;
|
|
}
|
|
for (int i = 1; i < get_num_components(); i++) {
|
|
const EggAttributes *component = get_component(i);
|
|
if (!component->has_normal()) {
|
|
component = this;
|
|
}
|
|
if (!component->matches_normal(*first_component)) {
|
|
return S_per_face;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if the components all have the same color.
|
|
{
|
|
const EggAttributes *first_component = get_component(0);
|
|
if (!first_component->has_color()) {
|
|
first_component = this;
|
|
}
|
|
for (int i = 1; i < get_num_components(); i++) {
|
|
const EggAttributes *component = get_component(i);
|
|
if (!component->has_color()) {
|
|
component = this;
|
|
}
|
|
if (!component->matches_color(*first_component)) {
|
|
return S_per_face;
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_overall;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::triangulate_in_place
|
|
// Access: Published
|
|
// Description: Subdivides the composite primitive into triangles and
|
|
// adds those triangles to the parent group node in
|
|
// place of the original primitive. Returns a pointer
|
|
// to the original primitive, which is likely about to
|
|
// be destructed.
|
|
//
|
|
// If convex_also is true, both concave and convex
|
|
// polygons will be subdivided into triangles;
|
|
// otherwise, only concave polygons will be subdivided,
|
|
// and convex polygons will be copied unchanged into the
|
|
// container.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(EggCompositePrimitive) EggCompositePrimitive::
|
|
triangulate_in_place() {
|
|
EggGroupNode *parent = get_parent();
|
|
nassertr(parent != (EggGroupNode *)NULL, this);
|
|
|
|
PT(EggCompositePrimitive) save_me = this;
|
|
parent->remove_child(this);
|
|
do_triangulate(parent);
|
|
|
|
return save_me;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::unify_attributes
|
|
// Access: Published, Virtual
|
|
// Description: If the shading property is S_per_vertex, ensures that
|
|
// all vertices have a normal and a color, and the
|
|
// overall primitive does not.
|
|
//
|
|
// If the shading property is S_per_face, and this is a
|
|
// composite primitive, ensures that all components have
|
|
// a normal and a color, and the vertices and overall
|
|
// primitive do not. (If this is a simple primitive,
|
|
// S_per_face works the same as S_overall, below).
|
|
//
|
|
// If the shading property is S_overall, ensures that no
|
|
// vertices or components have a normal or a color, and
|
|
// the overall primitive does (if any exists at all).
|
|
//
|
|
// After this call, either the primitive will have
|
|
// normals or its vertices will, but not both. Ditto
|
|
// for colors.
|
|
//
|
|
// This may create redundant vertices in the vertex
|
|
// pool.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
unify_attributes(EggPrimitive::Shading shading) {
|
|
if (shading == S_unknown) {
|
|
shading = get_shading();
|
|
}
|
|
|
|
switch (shading) {
|
|
case S_per_vertex:
|
|
// Propagate everything to the vertices.
|
|
{
|
|
Components::iterator ci;
|
|
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
|
EggAttributes *component = (*ci);
|
|
if (component->has_normal()) {
|
|
if (!has_normal()) {
|
|
copy_normal(*component);
|
|
}
|
|
component->clear_normal();
|
|
}
|
|
if (component->has_color()) {
|
|
if (!has_color()) {
|
|
copy_color(*component);
|
|
}
|
|
component->clear_color();
|
|
}
|
|
}
|
|
|
|
// Not having a color is implicitly white.
|
|
if (!has_color()) {
|
|
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
|
}
|
|
|
|
iterator pi;
|
|
for (pi = begin(); pi != end(); ++pi) {
|
|
EggVertex *orig_vertex = (*pi);
|
|
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
|
if (!vertex->has_normal() && has_normal()) {
|
|
vertex->copy_normal(*this);
|
|
}
|
|
if (!vertex->has_color() && has_color()) {
|
|
vertex->copy_color(*this);
|
|
}
|
|
|
|
EggVertexPool *vertex_pool = orig_vertex->get_pool();
|
|
nassertv(vertex_pool != (EggVertexPool *)NULL);
|
|
vertex = vertex_pool->create_unique_vertex(*vertex);
|
|
vertex->copy_grefs_from(*orig_vertex);
|
|
replace(pi, vertex);
|
|
}
|
|
clear_normal();
|
|
clear_color();
|
|
}
|
|
break;
|
|
|
|
case S_per_face:
|
|
// Propagate everything to the components.
|
|
{
|
|
iterator pi;
|
|
for (pi = begin(); pi != end(); ++pi) {
|
|
EggVertex *orig_vertex = (*pi);
|
|
if (orig_vertex->has_normal() || orig_vertex->has_color()) {
|
|
if (orig_vertex->has_normal() && !has_normal()) {
|
|
copy_normal(*orig_vertex);
|
|
}
|
|
if (orig_vertex->has_color() && !has_color()) {
|
|
copy_color(*orig_vertex);
|
|
}
|
|
|
|
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
|
vertex->clear_normal();
|
|
vertex->clear_color();
|
|
|
|
EggVertexPool *vertex_pool = orig_vertex->get_pool();
|
|
nassertv(vertex_pool != (EggVertexPool *)NULL);
|
|
vertex = vertex_pool->create_unique_vertex(*vertex);
|
|
vertex->copy_grefs_from(*orig_vertex);
|
|
replace(pi, vertex);
|
|
}
|
|
}
|
|
|
|
// Not having a color is implicitly white.
|
|
if (!has_color()) {
|
|
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
|
}
|
|
|
|
Components::iterator ci;
|
|
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
|
EggAttributes *component = (*ci);
|
|
if (!component->has_normal() && has_normal()) {
|
|
component->copy_normal(*this);
|
|
}
|
|
if (!component->has_color() && has_color()) {
|
|
component->copy_color(*this);
|
|
}
|
|
}
|
|
clear_normal();
|
|
clear_color();
|
|
}
|
|
break;
|
|
|
|
case S_overall:
|
|
// Remove everything from the vertices and components.
|
|
{
|
|
iterator pi;
|
|
for (pi = begin(); pi != end(); ++pi) {
|
|
EggVertex *orig_vertex = (*pi);
|
|
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
|
if (vertex->has_normal()) {
|
|
if (!has_normal()) {
|
|
copy_normal(*vertex);
|
|
}
|
|
vertex->clear_normal();
|
|
}
|
|
if (vertex->has_color()) {
|
|
if (!has_color()) {
|
|
copy_color(*vertex);
|
|
}
|
|
vertex->clear_color();
|
|
}
|
|
|
|
EggVertexPool *vertex_pool = orig_vertex->get_pool();
|
|
nassertv(vertex_pool != (EggVertexPool *)NULL);
|
|
vertex = vertex_pool->create_unique_vertex(*vertex);
|
|
vertex->copy_grefs_from(*orig_vertex);
|
|
replace(pi, vertex);
|
|
}
|
|
Components::iterator ci;
|
|
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
|
EggAttributes *component = (*ci);
|
|
if (component->has_normal()) {
|
|
if (!has_normal()) {
|
|
copy_normal(*component);
|
|
}
|
|
component->clear_normal();
|
|
}
|
|
if (component->has_color()) {
|
|
if (!has_color()) {
|
|
copy_color(*component);
|
|
}
|
|
component->clear_color();
|
|
}
|
|
}
|
|
|
|
// Not having a color is implicitly white.
|
|
if (!has_color()) {
|
|
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case S_unknown:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::apply_last_attribute
|
|
// Access: Published, Virtual
|
|
// Description: Sets the last vertex of the triangle (or each
|
|
// component) to the primitive normal and/or color, if
|
|
// the primitive is flat-shaded. This reflects the
|
|
// OpenGL convention of storing flat-shaded properties on
|
|
// the last vertex, although it is not usually a
|
|
// convention in Egg.
|
|
//
|
|
// This may introduce redundant vertices to the vertex
|
|
// pool.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
apply_last_attribute() {
|
|
// The first component gets applied to the third vertex, and so on
|
|
// from there.
|
|
int num_lead_vertices = get_num_lead_vertices();
|
|
for (int i = 0; i < get_num_components(); i++) {
|
|
EggAttributes *component = get_component(i);
|
|
do_apply_flat_attribute(i + num_lead_vertices, component);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::apply_first_attribute
|
|
// Access: Published, Virtual
|
|
// Description: Sets the first vertex of the triangle (or each
|
|
// component) to the primitive normal and/or color, if
|
|
// the primitive is flat-shaded. This reflects the
|
|
// DirectX convention of storing flat-shaded properties
|
|
// on the first vertex, although it is not usually a
|
|
// convention in Egg.
|
|
//
|
|
// This may introduce redundant vertices to the vertex
|
|
// pool.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
apply_first_attribute() {
|
|
// The first component gets applied to the first vertex, and so on
|
|
// from there.
|
|
for (int i = 0; i < get_num_components(); i++) {
|
|
EggAttributes *component = get_component(i);
|
|
do_apply_flat_attribute(i, component);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::post_apply_flat_attribute
|
|
// Access: Published, Virtual
|
|
// Description: Intended as a followup to apply_last_attribute(),
|
|
// this also sets an attribute on the first vertices of
|
|
// the primitive, if they don't already have an
|
|
// attribute set, just so they end up with *something*.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
post_apply_flat_attribute() {
|
|
if (!empty()) {
|
|
int num_lead_vertices = get_num_lead_vertices();
|
|
for (int i = 0; i < (int)size(); i++) {
|
|
EggVertex *vertex = get_vertex(i);
|
|
EggAttributes *component = get_component(max(i - num_lead_vertices, 0));
|
|
|
|
// Use set_normal() instead of copy_normal(), to avoid getting
|
|
// the morphs--we don't want them here, since we're just putting
|
|
// a bogus value on the normal anyway.
|
|
|
|
if (component->has_normal() && !vertex->has_normal()) {
|
|
vertex->set_normal(component->get_normal());
|
|
} else if (has_normal() && !vertex->has_normal()) {
|
|
vertex->set_normal(get_normal());
|
|
}
|
|
|
|
if (component->has_color() && !vertex->has_color()) {
|
|
vertex->set_color(component->get_color());
|
|
} else if (has_color() && !vertex->has_color()) {
|
|
vertex->set_color(get_color());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::cleanup
|
|
// Access: Published, Virtual
|
|
// Description: Cleans up modeling errors in whatever context this
|
|
// makes sense. For instance, for a polygon, this calls
|
|
// remove_doubled_verts(true). For a point, it calls
|
|
// remove_nonunique_verts(). Returns true if the
|
|
// primitive is valid, or false if it is degenerate.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggCompositePrimitive::
|
|
cleanup() {
|
|
return (int)size() >= get_num_lead_vertices() + 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::prepare_add_vertex
|
|
// Access: Protected, Virtual
|
|
// Description: Marks the vertex as belonging to the primitive. This
|
|
// is an internal function called by the STL-like
|
|
// functions push_back() and insert(), in preparation
|
|
// for actually adding the vertex.
|
|
//
|
|
// i indicates the new position of the vertex in the
|
|
// list; n indicates the new number of vertices after
|
|
// the operation has completed.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
prepare_add_vertex(EggVertex *vertex, int i, int n) {
|
|
EggPrimitive::prepare_add_vertex(vertex, i, n);
|
|
|
|
int num_lead_vertices = get_num_lead_vertices();
|
|
if (n >= num_lead_vertices + 1) {
|
|
i = max(i - num_lead_vertices, 0);
|
|
nassertv(i <= (int)_components.size());
|
|
_components.insert(_components.begin() + i, new EggAttributes(*this));
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::prepare_remove_vertex
|
|
// Access: Protected, Virtual
|
|
// Description: Marks the vertex as removed from the primitive. This
|
|
// is an internal function called by the STL-like
|
|
// functions pop_back() and erase(), in preparation for
|
|
// actually doing the removal.
|
|
//
|
|
// i indicates the former position of the vertex in the
|
|
// list; n indicates the current number of vertices
|
|
// before the operation has completed.
|
|
//
|
|
// It is an error to attempt to remove a vertex that is
|
|
// not already a vertex of this primitive.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
prepare_remove_vertex(EggVertex *vertex, int i, int n) {
|
|
EggPrimitive::prepare_remove_vertex(vertex, i, n);
|
|
|
|
int num_lead_vertices = get_num_lead_vertices();
|
|
if (n >= num_lead_vertices + 1) {
|
|
i = max(i - num_lead_vertices, 0);
|
|
nassertv(i < (int)_components.size());
|
|
delete _components[i];
|
|
_components.erase(_components.begin() + i);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::triangulate_poly
|
|
// Access: Protected, Virtual
|
|
// Description: Fills the container up with EggPolygons that
|
|
// represent the component triangles of this triangle
|
|
// strip.
|
|
//
|
|
// It is assumed that the EggCompositePrimitive is not
|
|
// already a child of any other group when this function
|
|
// is called.
|
|
//
|
|
// Returns true if the triangulation is successful, or
|
|
// false if there was some error (in which case the
|
|
// container may contain some partial triangulation).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggCompositePrimitive::
|
|
do_triangulate(EggGroupNode *container) const {
|
|
container->add_child((EggCompositePrimitive *)this);
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggCompositePrimitive::write_body
|
|
// Access: Protected
|
|
// Description: Writes the attributes and the vertices referenced by
|
|
// the primitive to the indicated output stream in Egg
|
|
// format.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggCompositePrimitive::
|
|
write_body(ostream &out, int indent_level) const {
|
|
EggPrimitive::write_body(out, indent_level);
|
|
|
|
for (int i = 0; i < get_num_components(); i++) {
|
|
const EggAttributes *attrib = get_component(i);
|
|
if (attrib->compare_to(*this) != 0 &&
|
|
(attrib->has_color() || attrib->has_normal())) {
|
|
indent(out, indent_level)
|
|
<< "<Component> " << i << " {\n";
|
|
attrib->write(out, indent_level + 2);
|
|
indent(out, indent_level) << "}\n";
|
|
}
|
|
}
|
|
}
|