464 lines
17 KiB
C++
464 lines
17 KiB
C++
// Filename: eggNode.cxx
|
|
// Created by: drose (16Jan99)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "eggNode.h"
|
|
#include "eggGroupNode.h"
|
|
#include "config_egg.h"
|
|
#include "eggTextureCollection.h"
|
|
#include "dcast.h"
|
|
|
|
#include <algorithm>
|
|
|
|
extern int eggyyparse(void);
|
|
#include "parserDefs.h"
|
|
#include "lexerDefs.h"
|
|
|
|
TypeHandle EggNode::_type_handle;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::apply_texmats
|
|
// Access: Public
|
|
// Description: Applies the texture matrices to the UV's of the
|
|
// vertices that reference them, and then removes the
|
|
// texture matrices from the textures themselves.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
apply_texmats() {
|
|
EggTextureCollection textures;
|
|
textures.find_used_textures(this);
|
|
r_apply_texmats(textures);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::is_joint
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if this particular node represents a
|
|
// <Joint> entry or not. This is a handy thing to know
|
|
// since Joints are sorted to the end of their sibling
|
|
// list when writing an egg file. See
|
|
// EggGroupNode::write().
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
is_joint() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::is_anim_matrix
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if this node represents a table of
|
|
// animation transformation data, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
is_anim_matrix() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_alpha_mode
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has an alpha_mode other than
|
|
// AM_unspecified. Returns a valid EggRenderMode pointer
|
|
// if one is found, or NULL otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_alpha_mode() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_alpha_mode();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_depth_write_mode
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has a depth_write_mode other than
|
|
// DWM_unspecified. Returns a valid EggRenderMode pointer
|
|
// if one is found, or NULL otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_depth_write_mode() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_depth_write_mode();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_depth_test_mode
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has a depth_test_mode other than
|
|
// DTM_unspecified. Returns a valid EggRenderMode pointer
|
|
// if one is found, or NULL otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_depth_test_mode() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_depth_test_mode();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_visibility_mode
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has a visibility_mode other than
|
|
// VM_unspecified. Returns a valid EggRenderMode pointer
|
|
// if one is found, or NULL otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_visibility_mode() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_visibility_mode();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_draw_order
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has a draw_order specified.
|
|
// Returns a valid EggRenderMode pointer if one is found,
|
|
// or NULL otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_draw_order() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_draw_order();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_bin
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// or EggPrimitive or some such object at this level or
|
|
// above this node that has a bin specified. Returns a
|
|
// valid EggRenderMode pointer if one is found, or NULL
|
|
// otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
EggRenderMode *EggNode::
|
|
determine_bin() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return (EggRenderMode *)NULL;
|
|
}
|
|
return _parent->determine_bin();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_indexed
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// at this level or above that has the "indexed" scalar
|
|
// set. Returns the value of the indexed scalar if it
|
|
// is found, or false if it is not.
|
|
//
|
|
// In other words, returns true if the "indexed" flag is
|
|
// in effect for the indicated node, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
determine_indexed() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return false;
|
|
}
|
|
return _parent->determine_indexed();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::determine_decal
|
|
// Access: Public, Virtual
|
|
// Description: Walks back up the hierarchy, looking for an EggGroup
|
|
// at this level or above that has the "decal" flag
|
|
// set. Returns the value of the decal flag if it
|
|
// is found, or false if it is not.
|
|
//
|
|
// In other words, returns true if the "decal" flag is
|
|
// in effect for the indicated node, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
determine_decal() {
|
|
if (_parent == (EggGroupNode *)NULL) {
|
|
// Too bad; we're done.
|
|
return false;
|
|
}
|
|
return _parent->determine_decal();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::parse_egg
|
|
// Access: Public
|
|
// Description: Parses the egg syntax given in the indicate string as
|
|
// if it had been read from the egg file within this
|
|
// object's definition. Updates the object accordingly.
|
|
// Returns true if successful, false if there was some
|
|
// parse error or if the object does not support this
|
|
// functionality.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
parse_egg(const string &egg_syntax) {
|
|
EggGroupNode *group = get_parent();
|
|
if (is_of_type(EggGroupNode::get_class_type())) {
|
|
DCAST_INTO_R(group, this, false);
|
|
}
|
|
|
|
istringstream in(egg_syntax);
|
|
egg_init_parser(in, "", this, group);
|
|
|
|
if (!egg_start_parse_body()) {
|
|
egg_cleanup_parser();
|
|
return false;
|
|
}
|
|
|
|
eggyyparse();
|
|
egg_cleanup_parser();
|
|
|
|
return (egg_error_count() == 0);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::test_under_integrity
|
|
// Access: Public
|
|
// Description: Recursively checks the integrity of the _under_flags,
|
|
// _parent, and _depth members of this node and all of
|
|
// its ancestors.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
test_under_integrity() const {
|
|
if (_parent == NULL) {
|
|
// If we have no parent, everything should be zero.
|
|
nassertv(_depth == 0);
|
|
nassertv(_under_flags == 0);
|
|
} else {
|
|
// Otherwise, make sure we're consistent with our parent.
|
|
_parent->test_ref_count_integrity();
|
|
|
|
nassertv(_depth == _parent->_depth + 1);
|
|
|
|
// We can't perform too much checking on the under_flags, since we
|
|
// don't know which bits should have been added for this node.
|
|
// We'll verify that at least we didn't accidentally take some
|
|
// bits away.
|
|
nassertv((_under_flags & _parent->_under_flags) == _parent->_under_flags);
|
|
|
|
// Make sure we're mentioned in our parent's children list.
|
|
EggGroupNode::iterator ci;
|
|
ci = find(_parent->begin(), _parent->end(), this);
|
|
nassertv(ci != _parent->end());
|
|
|
|
// Now recurse up our parent.
|
|
_parent->test_under_integrity();
|
|
}
|
|
}
|
|
|
|
#endif // NDEBUG
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::egg_start_parse_body
|
|
// Access: Protected, Virtual
|
|
// Description: This function is called within parse_egg(). It
|
|
// should call the appropriate function on the lexer to
|
|
// initialize the parser into the state associated with
|
|
// this object. If the object cannot be parsed into
|
|
// directly, it should return false.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
egg_start_parse_body() {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::update_under
|
|
// Access: Protected, Virtual
|
|
// Description: This function is called from within EggGroupNode
|
|
// whenever the parentage of the node has changed. It
|
|
// should update the depth and under_instance flags
|
|
// accordingly.
|
|
//
|
|
// depth_offset is the difference between the old depth
|
|
// value and the new value. It should be consistent
|
|
// with the supplied depth value. If it is not, we have
|
|
// some error.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
update_under(int depth_offset) {
|
|
int depth;
|
|
if (_parent == NULL) {
|
|
depth = 0;
|
|
_under_flags = 0;
|
|
_vertex_frame = NULL;
|
|
_node_frame = NULL;
|
|
_vertex_frame_inv = NULL;
|
|
_node_frame_inv = NULL;
|
|
_vertex_to_node = NULL;
|
|
_node_to_vertex = NULL;
|
|
} else {
|
|
_parent->test_ref_count_integrity();
|
|
depth = _parent->_depth + 1;
|
|
_under_flags = _parent->_under_flags;
|
|
_vertex_frame = _parent->_vertex_frame;
|
|
_node_frame = _parent->_node_frame;
|
|
_vertex_frame_inv = _parent->_vertex_frame_inv;
|
|
_node_frame_inv = _parent->_node_frame_inv;
|
|
_vertex_to_node = _parent->_vertex_to_node;
|
|
_node_to_vertex = _parent->_node_to_vertex;
|
|
}
|
|
|
|
if (depth - _depth != depth_offset) {
|
|
egg_cat.error() << "Cycle in egg graph or invalid egg pointer!\n";
|
|
return;
|
|
}
|
|
_depth = depth;
|
|
|
|
adjust_under();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::adjust_under
|
|
// Access: Protected, Virtual
|
|
// Description: This is called within update_under() after all the
|
|
// various under settings have been inherited directly
|
|
// from the parent node. It is responsible for
|
|
// adjusting these settings to reflect states local to
|
|
// the current node; for instance, an <Instance> node
|
|
// will force the UF_under_instance bit on.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
adjust_under() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::has_primitives
|
|
// Access: Protected, Virtual
|
|
// Description: Returns true if there are any primitives
|
|
// (e.g. polygons) defined within this group or below,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
has_primitives() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::joint_has_primitives
|
|
// Access: Protected, Virtual
|
|
// Description: Returns true if there are any primitives
|
|
// (e.g. polygons) defined within this group or below,
|
|
// but the search does not include nested joints.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
joint_has_primitives() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::has_normals
|
|
// Access: Published, Virtual
|
|
// Description: Returns true if any of the primitives (e.g. polygons)
|
|
// defined within this group or below have either face
|
|
// or vertex normals defined, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool EggNode::
|
|
has_normals() const {
|
|
return false;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::r_transform
|
|
// Access: Protected, Virtual
|
|
// Description: This is called from within the egg code by
|
|
// transform(). It applies a transformation matrix
|
|
// to the current node in some sensible way, then
|
|
// continues down the tree.
|
|
//
|
|
// The first matrix is the transformation to apply; the
|
|
// second is its inverse. The third parameter is the
|
|
// coordinate system we are changing to, or CS_default
|
|
// if we are not changing coordinate systems.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
r_transform(const LMatrix4d &, const LMatrix4d &, CoordinateSystem) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::r_transform_vertices
|
|
// Access: Protected, Virtual
|
|
// Description: This is called from within the egg code by
|
|
// transform_vertices_only()(). It applies a
|
|
// transformation matrix to the current node in some
|
|
// sensible way (if the current node is a vertex pool
|
|
// with vertices), then continues down the tree.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
r_transform_vertices(const LMatrix4d &) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::r_mark_coordsys
|
|
// Access: Protected, Virtual
|
|
// Description: This is only called immediately after loading an egg
|
|
// file from disk, to propagate the value found in the
|
|
// CoordinateSystem entry (or the default Y-up
|
|
// coordinate system) to all nodes that care about what
|
|
// the coordinate system is.
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
r_mark_coordsys(CoordinateSystem) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::r_flatten_transforms
|
|
// Access: Protected, Virtual
|
|
// Description: The recursive implementation of flatten_transforms().
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
r_flatten_transforms() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: EggNode::r_apply_texmats
|
|
// Access: Protected, Virtual
|
|
// Description: The recursive implementation of apply_texmats().
|
|
////////////////////////////////////////////////////////////////////
|
|
void EggNode::
|
|
r_apply_texmats(EggTextureCollection &textures) {
|
|
}
|