diff --git a/panda/src/egg/eggGroup.I b/panda/src/egg/eggGroup.I index ece99d1f8e..158984b1d6 100644 --- a/panda/src/egg/eggGroup.I +++ b/panda/src/egg/eggGroup.I @@ -27,6 +27,25 @@ get_group_type() const { return (GroupType)(_flags & F_group_type); } +//////////////////////////////////////////////////////////////////// +// Function: EggGroup::is_instance_type +// Access: Public +// Description: Returns true if this group is an instance type node; +// i.e. it begins the root of a local coordinate space. +// This is not related to instancing (multiple copies of +// a node in a scene graph). +// +// This also includes the case of the node including a +// billboard flag without an explicit center, which +// implicitly makes the node behave like an instance. +//////////////////////////////////////////////////////////////////// +INLINE bool EggGroup:: +is_instance_type() const { + return + (get_group_type() == GT_instance) || + (get_billboard_type() != BT_none && !has_billboard_center()); +} + //////////////////////////////////////////////////////////////////// // Function: EggGroup::set_billboard_type // Access: Public @@ -37,6 +56,8 @@ set_billboard_type(BillboardType type) { // Make sure the user didn't give us any stray bits. nassertv((type & ~F_billboard_type)==0); _flags = (_flags & ~F_billboard_type) | type; + // This may change the transform space of this node. + update_under(0); } //////////////////////////////////////////////////////////////////// @@ -74,6 +95,8 @@ INLINE void EggGroup:: set_billboard_center(const LPoint3d &billboard_center) { _billboard_center = billboard_center; _flags2 |= F2_billboard_center; + // This may change the transform space of this node. + update_under(0); } //////////////////////////////////////////////////////////////////// @@ -84,6 +107,8 @@ set_billboard_center(const LPoint3d &billboard_center) { INLINE void EggGroup:: clear_billboard_center() { _flags2 &= ~F2_billboard_center; + // This may change the transform space of this node. + update_under(0); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/egg/eggGroup.cxx b/panda/src/egg/eggGroup.cxx index 8877d9ad85..324934d404 100644 --- a/panda/src/egg/eggGroup.cxx +++ b/panda/src/egg/eggGroup.cxx @@ -22,9 +22,9 @@ #include "eggBin.h" #include "lexerDefs.h" -#include -#include -#include +#include "indent.h" +#include "string_utils.h" +#include "lmatrix.h" TypeHandle EggGroup::_type_handle; @@ -119,6 +119,43 @@ set_group_type(GroupType type) { } } +//////////////////////////////////////////////////////////////////// +// Function: EggGroup::has_object_type +// Access: Public +// Description: Returns true if the indicated object type has been +// added to the group, or false otherwise. +//////////////////////////////////////////////////////////////////// +bool EggGroup:: +has_object_type(const string &object_type) const { + vector_string::const_iterator oi; + for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) { + if (cmp_nocase_uh((*oi), object_type) == 0) { + return true; + } + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggGroup::remove_object_type +// Access: Public +// Description: Removes the first instance of the indicated object +// type from the group if it is present. Returns true +// if the object type was found and removed, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool EggGroup:: +remove_object_type(const string &object_type) { + vector_string::iterator oi; + for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) { + if (cmp_nocase_uh((*oi), object_type) == 0) { + _object_types.erase(oi); + return true; + } + } + return false; +} + //////////////////////////////////////////////////////////////////// // Function: EggGroup::write // Access: Public, Virtual @@ -680,10 +717,6 @@ egg_start_parse_body() { //////////////////////////////////////////////////////////////////// void EggGroup:: adjust_under() { - // Billboards without an explicit center are an implicit instance. - bool is_billboard_instance = - (get_billboard_type() != BT_none && !has_billboard_center()); - // If we have our own transform, it carries forward. // As of 4/18/01, this now also affects the local_coord flag, below. @@ -699,9 +732,11 @@ adjust_under() { new MatrixFrame(invert(get_node_frame())); _vertex_to_node = new MatrixFrame(get_vertex_frame() * get_node_frame_inv()); + _node_to_vertex = + new MatrixFrame(get_node_frame() * get_vertex_frame_inv()); } - if (get_group_type() == GT_instance || is_billboard_instance) { + if (is_instance_type()) { _under_flags |= UF_under_instance; if (_under_flags & UF_under_transform) { // If we've reached an instance node and we're under a @@ -716,6 +751,7 @@ adjust_under() { _vertex_frame = _node_frame; _vertex_frame_inv = _node_frame_inv; _vertex_to_node = NULL; + _node_to_vertex = NULL; } } @@ -753,7 +789,7 @@ r_transform(const LMatrix4d &mat, const LMatrix4d &inv, mat1.set_row(3, LVector3d(0.0, 0.0, 0.0)); inv1.set_row(3, LVector3d(0.0, 0.0, 0.0)); - set_transform(inv1 * get_transform() * mat); + internal_set_transform(inv1 * get_transform() * mat); EggGroupNode::r_transform(mat1, inv1, to_cs); } else { @@ -799,11 +835,26 @@ r_flatten_transforms() { } if (get_group_type() != GT_joint) { - clear_transform(); + internal_clear_transform(); } } +//////////////////////////////////////////////////////////////////// +// Function: EggGroup::transform_changed +// Access: Protected, Virtual +// Description: This virtual method is inherited by EggTransform3d; +// it is called whenever the transform is changed. +//////////////////////////////////////////////////////////////////// +void EggGroup:: +transform_changed() { + // Recompute all of the cached transforms at this node and below. + // We should probably make this smarter and do lazy evaluation of + // these transforms, rather than having to recompute the whole tree + // with every change to a parent node's transform. + update_under(0); +} + //////////////////////////////////////////////////////////////////// diff --git a/panda/src/egg/eggGroup.h b/panda/src/egg/eggGroup.h index be0f462f27..798c745ebb 100644 --- a/panda/src/egg/eggGroup.h +++ b/panda/src/egg/eggGroup.h @@ -100,6 +100,7 @@ public: void set_group_type(GroupType type); INLINE GroupType get_group_type() const; + INLINE bool is_instance_type() const; INLINE void set_billboard_type(BillboardType type); INLINE BillboardType get_billboard_type() const; @@ -136,6 +137,8 @@ public: INLINE void clear_object_types(); INLINE int get_num_object_types() const; INLINE string get_object_type(int index) const; + bool has_object_type(const string &object_type) const; + bool remove_object_type(const string &object_type); INLINE void set_model_flag(bool flag); INLINE bool get_model_flag() const; @@ -201,6 +204,8 @@ protected: CoordinateSystem to_cs); virtual void r_flatten_transforms(); + virtual void transform_changed(); + private: enum Flags { diff --git a/panda/src/egg/eggNode.I b/panda/src/egg/eggNode.I index d885d20f7a..44ba997935 100644 --- a/panda/src/egg/eggNode.I +++ b/panda/src/egg/eggNode.I @@ -212,6 +212,26 @@ get_vertex_to_node() const { } } +//////////////////////////////////////////////////////////////////// +// Function: EggNode::get_node_to_vertex +// Access: Public +// Description: Returns the transformation matrix suitable for +// converting vertices in the coordinate space of the +// node to the appropriate coordinate space for storing +// in the egg file. This is the same thing as: +// +// get_node_frame() * get_vertex_frame_inv() +// +//////////////////////////////////////////////////////////////////// +INLINE const LMatrix4d &EggNode:: +get_node_to_vertex() const { + if (_node_to_vertex == (LMatrix4d *)NULL) { + return LMatrix4d::ident_mat(); + } else { + return *_node_to_vertex; + } +} + //////////////////////////////////////////////////////////////////// // Function: EggNode::transform @@ -259,4 +279,5 @@ transform_vertices_only(const LMatrix4d &mat) { INLINE void EggNode:: flatten_transforms() { r_flatten_transforms(); + update_under(0); } diff --git a/panda/src/egg/eggNode.cxx b/panda/src/egg/eggNode.cxx index 67f20a5d76..038bbb0f00 100644 --- a/panda/src/egg/eggNode.cxx +++ b/panda/src/egg/eggNode.cxx @@ -244,6 +244,7 @@ update_under(int depth_offset) { _vertex_frame_inv = NULL; _node_frame_inv = NULL; _vertex_to_node = NULL; + _node_to_vertex = NULL; } else { depth = _parent->_depth + 1; _under_flags = _parent->_under_flags; @@ -252,6 +253,7 @@ update_under(int depth_offset) { _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) { diff --git a/panda/src/egg/eggNode.h b/panda/src/egg/eggNode.h index 37720c355b..85834d6e00 100644 --- a/panda/src/egg/eggNode.h +++ b/panda/src/egg/eggNode.h @@ -56,6 +56,7 @@ public: INLINE const LMatrix4d &get_vertex_frame_inv() const; INLINE const LMatrix4d &get_node_frame_inv() const; INLINE const LMatrix4d &get_vertex_to_node() const; + INLINE const LMatrix4d &get_node_to_vertex() const; INLINE void transform(const LMatrix4d &mat); INLINE void transform_vertices_only(const LMatrix4d &mat); @@ -112,6 +113,7 @@ protected: PT(MatrixFrame) _vertex_frame_inv; PT(MatrixFrame) _node_frame_inv; PT(MatrixFrame) _vertex_to_node; + PT(MatrixFrame) _node_to_vertex; public: diff --git a/panda/src/egg/eggTransform3d.I b/panda/src/egg/eggTransform3d.I index 509a282353..202bb88502 100644 --- a/panda/src/egg/eggTransform3d.I +++ b/panda/src/egg/eggTransform3d.I @@ -90,6 +90,29 @@ INLINE EggTransform3d::Component:: } } +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::clear_transform +// Access: Public +// Description: Resets the transform to empty, identity. +//////////////////////////////////////////////////////////////////// +INLINE void EggTransform3d:: +clear_transform() { + internal_clear_transform(); + transform_changed(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::add_matrix +// Access: Public +// Description: Appends an arbitrary 4x4 matrix to the current +// transform. +//////////////////////////////////////////////////////////////////// +INLINE void EggTransform3d:: +add_matrix(const LMatrix4d &mat) { + internal_add_matrix(mat); + transform_changed(); +} + //////////////////////////////////////////////////////////////////// // Function: EggTransform3d::has_transform // Access: Public @@ -111,8 +134,8 @@ has_transform() const { //////////////////////////////////////////////////////////////////// INLINE void EggTransform3d:: set_transform(const LMatrix4d &mat) { - clear_transform(); - add_matrix(mat); + internal_set_transform(mat); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -203,3 +226,15 @@ get_component_matrix(int n) const { nassertr(_components[n]._matrix != (LMatrix4d *)NULL, LMatrix4d::ident_mat()); return *_components[n]._matrix; } + +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::internal_set_transform +// Access: Protected +// Description: Sets the overall transform without calling +// transform_changed(). +//////////////////////////////////////////////////////////////////// +INLINE void EggTransform3d:: +internal_set_transform(const LMatrix4d &mat) { + internal_clear_transform(); + internal_add_matrix(mat); +} diff --git a/panda/src/egg/eggTransform3d.cxx b/panda/src/egg/eggTransform3d.cxx index abc4c1adca..35010e5765 100644 --- a/panda/src/egg/eggTransform3d.cxx +++ b/panda/src/egg/eggTransform3d.cxx @@ -63,17 +63,6 @@ EggTransform3d:: ~EggTransform3d() { } -//////////////////////////////////////////////////////////////////// -// Function: EggTransform3d::clear_transform -// Access: Public -// Description: Resets the transform to empty, identity. -//////////////////////////////////////////////////////////////////// -void EggTransform3d:: -clear_transform() { - _components.clear(); - _transform = LMatrix4d::ident_mat(); -} - //////////////////////////////////////////////////////////////////// // Function: EggTransform3d::add_translate // Access: Public @@ -85,6 +74,7 @@ add_translate(const LVector3d &translate) { _components.push_back(Component(CT_translate)); _components.back()._vector = new LVector3d(translate); _transform *= LMatrix4d::translate_mat(translate); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -98,6 +88,7 @@ void EggTransform3d:: add_rotx(double angle) { _components.push_back(Component(CT_rotx, angle)); _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(1.0, 0.0, 0.0)); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -111,6 +102,7 @@ void EggTransform3d:: add_roty(double angle) { _components.push_back(Component(CT_roty, angle)); _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 1.0, 0.0)); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -124,6 +116,7 @@ void EggTransform3d:: add_rotz(double angle) { _components.push_back(Component(CT_rotz, angle)); _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 0.0, 1.0)); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -139,6 +132,7 @@ add_rotate(double angle, const LVector3d &axis) { _components.push_back(Component(CT_rotate, angle)); _components.back()._vector = new LVector3d(normaxis); _transform *= LMatrix4d::rotate_mat(angle, normaxis); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -151,6 +145,7 @@ add_rotate(double angle, const LVector3d &axis) { void EggTransform3d:: add_rotate(const LQuaterniond &quat) { add_rotate(quat.get_angle(), quat.get_axis()); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -164,6 +159,7 @@ add_scale(const LVecBase3d &scale) { _components.push_back(Component(CT_scale)); _components.back()._vector = new LVector3d(scale); _transform *= LMatrix4d::scale_mat(scale); + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -175,19 +171,7 @@ void EggTransform3d:: add_uniform_scale(double scale) { _components.push_back(Component(CT_uniform_scale, scale)); _transform *= LMatrix4d::scale_mat(scale); -} - -//////////////////////////////////////////////////////////////////// -// Function: EggTransform3d::add_matrix -// Access: Public -// Description: Appends an arbitrary 4x4 matrix to the current -// transform. -//////////////////////////////////////////////////////////////////// -void EggTransform3d:: -add_matrix(const LMatrix4d &mat) { - _components.push_back(Component(CT_matrix)); - _components.back()._matrix = new LMatrix4d(mat); - _transform *= mat; + transform_changed(); } //////////////////////////////////////////////////////////////////// @@ -253,3 +237,41 @@ write(ostream &out, int indent_level) const { indent(out, indent_level) << "}\n"; } + +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::internal_clear_transform +// Access: Public +// Description: Resets the transform to empty without calling +// transform_changed(). +//////////////////////////////////////////////////////////////////// +void EggTransform3d:: +internal_clear_transform() { + _components.clear(); + _transform = LMatrix4d::ident_mat(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::internal_add_matrix +// Access: Public +// Description: Appends an arbitrary 4x4 matrix to the current +// transform, without calling transform_changed(). +//////////////////////////////////////////////////////////////////// +void EggTransform3d:: +internal_add_matrix(const LMatrix4d &mat) { + _components.push_back(Component(CT_matrix)); + _components.back()._matrix = new LMatrix4d(mat); + _transform *= mat; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggTransform3d::transform_changed +// Access: Protected, Virtual +// Description: This virtual method is called whenever the transform +// is changed; it is intended to provide a hook for +// derived classes (e.g. EggGroup) to update their +// internal cache appropriately. +//////////////////////////////////////////////////////////////////// +void EggTransform3d:: +transform_changed() { +} + diff --git a/panda/src/egg/eggTransform3d.h b/panda/src/egg/eggTransform3d.h index 2dd6be7b17..a52958f5b1 100644 --- a/panda/src/egg/eggTransform3d.h +++ b/panda/src/egg/eggTransform3d.h @@ -37,7 +37,7 @@ public: EggTransform3d &operator = (const EggTransform3d ©); ~EggTransform3d(); - void clear_transform(); + INLINE void clear_transform(); void add_translate(const LVector3d &translate); void add_rotx(double angle); @@ -47,7 +47,7 @@ public: void add_rotate(const LQuaterniond &quat); void add_scale(const LVecBase3d &scale); void add_uniform_scale(double scale); - void add_matrix(const LMatrix4d &mat); + INLINE void add_matrix(const LMatrix4d &mat); INLINE bool has_transform() const; INLINE void set_transform(const LMatrix4d &mat); @@ -74,6 +74,13 @@ public: void write(ostream &out, int indent_level) const; +protected: + void internal_clear_transform(); + void internal_add_matrix(const LMatrix4d &mat); + INLINE void internal_set_transform(const LMatrix4d &mat); + + virtual void transform_changed(); + private: class Component { public: