Browse Source

store egg transforms componentwise

David Rose 23 years ago
parent
commit
cc1a49c7e4

+ 18 - 6
panda/src/doc/eggSyntax.txt

@@ -1090,6 +1090,9 @@ GROUPING ENTRIES
     The transform definition may be any sequence of zero or more of
     the following.  Transformations are post multiplied in the order
     they are encountered to produce a net transformation matrix.
+    Rotations are defined as a counterclockwise angle in degrees about
+    a particular axis, either implicit (x, y, or z axis), or
+    arbitrary.
 
     <Translate> { x y z }
     <RotX> { degrees }
@@ -1097,12 +1100,7 @@ GROUPING ENTRIES
     <RotZ> { degrees }
     <Rotate> { degrees x y z }
     <Scale> { x y z }
-
-    <Matrix3> {
-      00 01 02
-      10 11 12
-      20 21 22
-    }    
+    <Scale> { s }
 
     <Matrix4> {
       00 01 02 03
@@ -1111,6 +1109,20 @@ GROUPING ENTRIES
       30 31 32 33
     }
 
+    In the context of texture coordinates, the transform is defined in
+    2-d space, and the allowable components correspondingly reflect
+    two-dimensional transforms:
+
+    <Translate> { x y }
+    <Rotate> { degrees }
+    <Scale> { x y }
+    <Scale> { s }
+
+    <Matrix3> {
+      00 01 02
+      10 11 12
+      20 21 22
+    }    
 
   <VertexRef> { indices <Ref> { pool-name } }
 

+ 3 - 0
panda/src/egg/Sources.pp

@@ -30,6 +30,7 @@
      eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h  \
      eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I  \
      eggTexture.h eggTextureCollection.I eggTextureCollection.h  \
+     eggTransform3d.I eggTransform3d.h \
      eggUtilities.I eggUtilities.h eggVertex.I eggVertex.h  \
      eggVertexPool.I eggVertexPool.h eggXfmAnimData.I  \
      eggXfmAnimData.h eggXfmSAnim.I eggXfmSAnim.h parserDefs.h  \
@@ -50,6 +51,7 @@
      eggPoolUniquifier.cxx eggPrimitive.cxx eggRenderMode.cxx  \
      eggSAnimData.cxx eggSurface.cxx eggSwitchCondition.cxx  \
      eggTable.cxx eggTexture.cxx eggTextureCollection.cxx  \
+     eggTransform3d.cxx \
      eggUtilities.cxx eggVertex.cxx eggVertexPool.cxx  \
      eggXfmAnimData.cxx eggXfmSAnim.cxx xx xx pt_EggMaterial.cxx  \
      vector_PT_EggMaterial.cxx pt_EggTexture.cxx  \
@@ -74,6 +76,7 @@
     eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h \
     eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
     eggTexture.h eggTextureCollection.I eggTextureCollection.h \
+    eggTransform3d.I eggTransform3d.h \
     eggUtilities.I eggUtilities.h eggVertex.I eggVertex.h \
     eggVertexPool.I eggVertexPool.h eggXfmAnimData.I eggXfmAnimData.h \
     eggXfmSAnim.I eggXfmSAnim.h \

+ 0 - 35
panda/src/egg/eggGroup.I

@@ -281,41 +281,6 @@ get_switch_fps() const {
   return _fps;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::has_transform
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE bool EggGroup::
-has_transform() const {
-  return (_flags & F_has_transform) != 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::get_transform
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE LMatrix4d EggGroup::
-get_transform() const {
-  nassertr(_flags & F_has_transform, _transform);
-  return _transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::transform_is_identity()
-//       Access: Public
-//  Description: Returns true if no transform matrix has been
-//               specified, or if the one specified is the identity
-//               transform.  Returns false only if a nonidentity
-//               transform has been applied.
-////////////////////////////////////////////////////////////////////
-INLINE bool EggGroup::
-transform_is_identity() const {
-  return (!has_transform() ||
-          _transform.almost_equal(LMatrix4d::ident_mat(), 0.0001));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::set_objecttype
 //       Access: Public

+ 4 - 37
panda/src/egg/eggGroup.cxx

@@ -38,7 +38,6 @@ EggGroup::
 EggGroup(const string &name) : EggGroupNode(name) {
   _flags = 0;
   _flags2 = 0;
-  _transform = LMatrix4d::ident_mat();
   _fps = 0.0;
 }
 
@@ -59,9 +58,9 @@ EggGroup(const EggGroup &copy) {
 ////////////////////////////////////////////////////////////////////
 EggGroup &EggGroup::
 operator = (const EggGroup &copy) {
+  EggTransform3d::operator = (copy);
   _flags = copy._flags;
   _flags2 = copy._flags2;
-  _transform = copy._transform;
   _objecttype = copy._objecttype;
   _collision_name = copy._collision_name;
   _fps = copy._fps;
@@ -120,38 +119,6 @@ set_group_type(GroupType type) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::set_transform
-//       Access: Public
-//  Description: Sets the indicated transformation matrix on the node.
-////////////////////////////////////////////////////////////////////
-void EggGroup::
-set_transform(const LMatrix4d &transform) {
-  _transform = transform;
-  if (!has_transform()) {
-    _flags |= F_has_transform;
-
-    // Now we have to update the under_flags.
-    update_under(0);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::clear_transform
-//       Access: Public
-//  Description: Removes any transformation matrix from the node.
-////////////////////////////////////////////////////////////////////
-void EggGroup::
-clear_transform() {
-  _transform = LMatrix4d::ident_mat();
-  if (has_transform()) {
-    _flags &= ~F_has_transform;
-
-    // Now we have to update the under_flags.
-    update_under(0);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::write
 //       Access: Public, Virtual
@@ -250,7 +217,7 @@ write(ostream &out, int indent_level) const {
   }
 
   if (has_transform()) {
-    write_transform(out, _transform, indent_level + 2);
+    EggTransform3d::write(out, indent_level + 2);
   }
 
   if (has_objecttype()) {
@@ -767,7 +734,7 @@ adjust_under() {
 void EggGroup::
 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
             CoordinateSystem to_cs) {
-  if (has_transform()) {
+  if (!transform_is_identity()) {
     // Since we want to apply this transform to all matrices,
     // including nested matrices, we can't simply premult it in and
     // leave it, because that would leave the rotational component in
@@ -785,7 +752,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));
 
-    _transform = inv1 * _transform * mat;
+    set_transform(inv1 * get_transform() * mat);
 
     EggGroupNode::r_transform(mat1, inv1, to_cs);
   } else {

+ 2 - 9
panda/src/egg/eggGroup.h

@@ -23,6 +23,7 @@
 
 #include "eggGroupNode.h"
 #include "eggRenderMode.h"
+#include "eggTransform3d.h"
 #include "eggVertex.h"
 #include "eggSwitchCondition.h"
 #include "pt_EggVertex.h"
@@ -35,7 +36,7 @@
 // Description : The main glue of the egg hierarchy, this corresponds
 //               to the <Group>, <Instance>, and <Joint> type nodes.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEGG EggGroup : public EggGroupNode, public EggRenderMode {
+class EXPCL_PANDAEGG EggGroup : public EggGroupNode, public EggRenderMode, public EggTransform3d {
 public:
   typedef pmap<PT_EggVertex, double> VertexRef;
 
@@ -130,12 +131,6 @@ public:
   INLINE void set_switch_fps(double fps);
   INLINE double get_switch_fps() const;
 
-  void set_transform(const LMatrix4d &transform);
-  void clear_transform();
-  INLINE bool has_transform() const;
-  INLINE LMatrix4d get_transform() const;
-  INLINE bool transform_is_identity() const;
-
   INLINE void set_objecttype(const string &objecttype);
   INLINE void clear_objecttype();
   INLINE bool has_objecttype() const;
@@ -213,7 +208,6 @@ private:
     F_dcs_flag               = 0x00000010,
     F_billboard_type         = 0x000000e0,
     F_switch_flag            = 0x00000100,
-    F_has_transform          = 0x00000200,
     F_model_flag             = 0x00000400,
     F_texlist_flag           = 0x00000800,
     F_nofog_flag             = 0x00001000,
@@ -231,7 +225,6 @@ private:
 
   int _flags;
   int _flags2;
-  LMatrix4d _transform;
   CollideMask _collide_mask, _from_collide_mask, _into_collide_mask;
   LPoint3d _billboard_center;
   string _objecttype;

+ 2 - 59
panda/src/egg/eggMiscFuncs.cxx

@@ -16,10 +16,9 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <pandabase.h>
+#include "pandabase.h"
 #include "eggMiscFuncs.h"
-
-#include <indent.h>
+#include "indent.h"
 
 #include <ctype.h>
 
@@ -95,59 +94,3 @@ write_transform(ostream &out, const LMatrix3d &mat, int indent_level) {
   indent(out, indent_level+2) << "}\n";
   indent(out, indent_level) << "}\n";
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: write_transform
-//  Description: A helper function to write out a 4x4 transform
-//               matrix.
-////////////////////////////////////////////////////////////////////
-void
-write_transform(ostream &out, const LMatrix4d &mat, int indent_level) {
-  indent(out, indent_level) << "<Transform> {\n";
-
-  bool written = false;
-
-  /*
-  int mat_type = mat.getMatType();
-  if ((mat_type &
-       ~(PFMAT_TRANS | PFMAT_ROT | PFMAT_SCALE | PFMAT_NONORTHO))==0) {
-    // Write out the matrix componentwise if possible.
-    pfVec3 s, r, t;
-    if (ExtractMatrix(mat, s, r, t)) {
-      if (!s.almostEqual(pfVec3(1.0, 1.0, 1.0), 0.0001)) {
-        Indent(out, indent+2) << "<Scale> { " << s << " }\n";
-      }
-      if (fabs(r[0]) > 0.0001) {
-        Indent(out, indent+2) << "<RotX> { " << r[0] << " }\n";
-      }
-      if (fabs(r[1]) > 0.0001) {
-        Indent(out, indent+2) << "<RotY> { " << r[1] << " }\n";
-      }
-      if (fabs(r[2]) > 0.0001) {
-        Indent(out, indent+2) << "<RotZ> { " << r[2] << " }\n";
-      }
-      if (!t.almostEqual(pfVec3(0.0, 0.0, 0.0), 0.0001)) {
-        Indent(out, indent+2) << "<Translate> { " << t << " }\n";
-      }
-      written = true;
-    }
-  }
-  */
-
-  if (!written) {
-    // It's some non-affine matrix, or it has a shear; write out the
-    // general 4x4.
-    indent(out, indent_level+2) << "<Matrix4> {\n";
-
-    for (int r = 0; r < 4; r++) {
-      indent(out, indent_level+3);
-      for (int c = 0; c < 4; c++) {
-        out << " " << mat(r, c);
-      }
-      out << "\n";
-    }
-    indent(out, indent_level+2) << "}\n";
-  }
-
-  indent(out, indent_level) << "}\n";
-}

+ 2 - 18
panda/src/egg/eggMiscFuncs.h

@@ -29,16 +29,8 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <pandabase.h>
-
-#include <lmatrix.h>
-#include <typedef.h>
-
-#include <string>
-
-#ifndef WIN32_VC
-class ostream;
-#endif
+#include "pandabase.h"
+#include "lmatrix.h"
 
 
 ////////////////////////////////////////////////////////////////////
@@ -64,14 +56,6 @@ void
 write_transform(ostream &out, const LMatrix3d &mat, int indent_level);
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: write_transform
-//  Description: A helper function to write out a 4x4 transform
-//               matrix.
-////////////////////////////////////////////////////////////////////
-void
-write_transform(ostream &out, const LMatrix4d &mat, int indent_level);
-
 #include "eggMiscFuncs.I"
 
 #endif

+ 2 - 5
panda/src/egg/eggRenderMode.h

@@ -19,11 +19,8 @@
 #ifndef EGGRENDERMODE_H
 #define EGGRENDERMODE_H
 
-#include <pandabase.h>
-
-#include <typedObject.h>
-
-#include <string>
+#include "pandabase.h"
+#include "typedObject.h"
 
 
 ////////////////////////////////////////////////////////////////////

+ 205 - 0
panda/src/egg/eggTransform3d.I

@@ -0,0 +1,205 @@
+// Filename: eggTransform3d.I
+// Created by:  drose (21Jun02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Component::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform3d::Component::
+Component(EggTransform3d::ComponentType type, double number) :
+  _type(type),
+  _number(number)
+{
+  _vector = (LVector3d *)NULL;
+  _matrix = (LMatrix4d *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Component::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform3d::Component::
+Component(const EggTransform3d::Component &copy) :
+  _type(copy._type),
+  _number(copy._number)
+{
+  _vector = (LVector3d *)NULL;
+  _matrix = (LMatrix4d *)NULL;
+  if (copy._vector != (LVector3d *)NULL) {
+    _vector = new LVector3d(*copy._vector);
+  }
+  if (copy._matrix != (LMatrix4d *)NULL) {
+    _matrix = new LMatrix4d(*copy._matrix);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Component::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform3d::Component::
+operator = (const EggTransform3d::Component &copy) {
+  _type = copy._type;
+  _number = copy._number;
+  if (_vector != (LVector3d *)NULL) {
+    delete _vector;
+    _vector = (LVector3d *)NULL;
+  }
+  if (_matrix != (LMatrix4d *)NULL) {
+    delete _matrix;
+    _matrix = (LMatrix4d *)NULL;
+  }
+  if (copy._vector != (LVector3d *)NULL) {
+    _vector = new LVector3d(*copy._vector);
+  }
+  if (copy._matrix != (LMatrix4d *)NULL) {
+    _matrix = new LMatrix4d(*copy._matrix);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Component::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform3d::Component::
+~Component() {
+  if (_vector != (LVector3d *)NULL) {
+    delete _vector;
+  }
+  if (_matrix != (LMatrix4d *)NULL) {
+    delete _matrix;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::has_transform
+//       Access: Public
+//  Description: Returns true if the transform is nonempty, false if
+//               it is empty (no transform components have been
+//               added).
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTransform3d::
+has_transform() const {
+  return !_components.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::set_transform
+//       Access: Public
+//  Description: Sets the overall transform as a 4x4 matrix.  This
+//               completely replaces whatever componentwise transform
+//               may have been defined.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform3d::
+set_transform(const LMatrix4d &mat) {
+  clear_transform();
+  add_matrix(mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_transform
+//       Access: Public
+//  Description: Returns the overall transform as a 4x4 matrix.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4d &EggTransform3d::
+get_transform() const {
+  return _transform;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::transform_is_identity
+//       Access: Public
+//  Description: Returns true if the described transform is identity,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTransform3d::
+transform_is_identity() const {
+  return _components.empty() ||
+    _transform.almost_equal(LMatrix4d::ident_mat(), 0.0001);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_num_components
+//       Access: Public
+//  Description: Returns the number of components that make up the
+//               transform.
+////////////////////////////////////////////////////////////////////
+INLINE int EggTransform3d::
+get_num_components() const {
+  return _components.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_component_type
+//       Access: Public
+//  Description: Returns the type of the nth component.
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform3d::ComponentType EggTransform3d::
+get_component_type(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), CT_invalid);
+  return _components[n]._type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_component_number
+//       Access: Public
+//  Description: Returns the solitary number associated with the nth
+//               component.  In the case of a rotation, this is the
+//               angle in degrees to rotate; in the case of uniform
+//               scale, this is the amount of the scale.  Other types
+//               do not use this property.
+////////////////////////////////////////////////////////////////////
+INLINE double EggTransform3d::
+get_component_number(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), 0.0);
+  return _components[n]._number;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_component_vector
+//       Access: Public
+//  Description: Returns the 3-component vector associated with the
+//               nth component.  This may be the translate vector,
+//               rotate axis, or non-uniform scale.  It is an error to
+//               call this if the component type does not use a vector
+//               property.
+////////////////////////////////////////////////////////////////////
+INLINE const LVector3d &EggTransform3d::
+get_component_vector(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LVector3d::zero());
+  nassertr(_components[n]._vector != (LVector3d *)NULL, LVector3d::zero());
+  return *_components[n]._vector;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::get_component_matrix
+//       Access: Public
+//  Description: Returns the 4x4 matrix associated with the nth
+//               component.  It is an error to call this if the
+//               component type is not CT_matrix.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4d &EggTransform3d::
+get_component_matrix(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LMatrix4d::ident_mat());
+  nassertr(_components[n]._matrix != (LMatrix4d *)NULL, LMatrix4d::ident_mat());
+  return *_components[n]._matrix;
+}

+ 242 - 0
panda/src/egg/eggTransform3d.cxx

@@ -0,0 +1,242 @@
+// Filename: eggTransform3d.cxx
+// Created by:  drose (21Jun02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eggTransform3d.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggTransform3d::
+EggTransform3d() :
+  _transform(LMatrix4d::ident_mat())
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggTransform3d::
+EggTransform3d(const EggTransform3d &copy) :
+  _components(copy._components),
+  _transform(copy._transform)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Copy assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggTransform3d &EggTransform3d::
+operator = (const EggTransform3d &copy) {
+  _components = copy._components;
+  _transform = copy._transform;
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+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
+//  Description: Appends a translation operation to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+add_translate(const LVector3d &translate) {
+  _components.push_back(Component(CT_translate));
+  _components.back()._vector = new LVector3d(translate);
+  _transform *= LMatrix4d::translate_mat(translate);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_rotx
+//       Access: Public
+//  Description: Appends a rotation about the X axis to the current
+//               transform.  The rotation angle is specified in
+//               degrees counterclockwise about the axis.
+////////////////////////////////////////////////////////////////////
+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));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_roty
+//       Access: Public
+//  Description: Appends a rotation about the Y axis to the current
+//               transform.  The rotation angle is specified in
+//               degrees counterclockwise about the axis.
+////////////////////////////////////////////////////////////////////
+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));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_rotz
+//       Access: Public
+//  Description: Appends a rotation about the Z axis to the current
+//               transform.  The rotation angle is specified in
+//               degrees counterclockwise about the axis.
+////////////////////////////////////////////////////////////////////
+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));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_rotate
+//       Access: Public
+//  Description: Appends a rotation about an arbitrary axis to the
+//               current transform.  The rotation angle is specified
+//               in degrees counterclockwise about the axis.
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+add_rotate(double angle, const LVector3d &axis) {
+  _components.push_back(Component(CT_rotate, angle));
+  _components.back()._vector = new LVector3d(axis);
+  _transform *= LMatrix4d::rotate_mat(angle, axis);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_scale
+//       Access: Public
+//  Description: Appends a possibly non-uniform scale to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+add_scale(const LVecBase3d &scale) {
+  _components.push_back(Component(CT_scale));
+  _components.back()._vector = new LVector3d(scale);
+  _transform *= LMatrix4d::scale_mat(scale);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_uniform_scale
+//       Access: Public
+//  Description: Appends a uniform scale to the current transform.
+////////////////////////////////////////////////////////////////////
+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;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::write
+//       Access: Public
+//  Description: Writes the transform to the indicated stream in Egg
+//               format.
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << "<Transform> {\n";
+
+  int num_components = get_num_components();
+  for (int i = 0; i < num_components; i++) {
+    switch (get_component_type(i)) {
+    case CT_translate:
+      indent(out, indent_level + 2)
+        << "<Translate> { " << get_component_vector(i) << " }\n";
+      break;
+
+    case CT_rotx:
+      indent(out, indent_level + 2)
+        << "<RotX> { " << get_component_number(i) << " }\n";
+      break;
+
+    case CT_roty:
+      indent(out, indent_level + 2)
+        << "<RotY> { " << get_component_number(i) << " }\n";
+      break;
+
+    case CT_rotz:
+      indent(out, indent_level + 2)
+        << "<RotZ> { " << get_component_number(i) << " }\n";
+      break;
+
+    case CT_rotate:
+      indent(out, indent_level + 2)
+        << "<Rotate> { " << get_component_number(i) << " " 
+        << get_component_vector(i) << " }\n";
+      break;
+
+    case CT_scale:
+      indent(out, indent_level + 2)
+        << "<Scale> { " << get_component_vector(i) << " }\n";
+      break;
+
+    case CT_uniform_scale:
+      indent(out, indent_level + 2)
+        << "<Scale> { " << get_component_number(i) << " }\n";
+      break;
+
+    case CT_matrix:
+      indent(out, indent_level + 2) << "<Matrix4> {\n";
+      get_component_matrix(i).write(out, indent_level + 4);
+      indent(out, indent_level + 2) << "}\n";
+      break;
+
+    case CT_invalid:
+      nassertv(false);
+      break;
+    }
+  }
+
+  indent(out, indent_level) << "}\n";
+}

+ 97 - 0
panda/src/egg/eggTransform3d.h

@@ -0,0 +1,97 @@
+// Filename: eggTransform3d.h
+// Created by:  drose (21Jun02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EGGTRANSFORM3D_H
+#define EGGTRANSFORM3D_H
+
+#include "pandabase.h"
+#include "luse.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : EggTransform3d
+// Description : This represents the <Transform> entry of a group
+//               node: a list of component transform operations,
+//               applied in order, that describe a net transform
+//               matrix.  This is a 3-d transform, and therefore
+//               computes a 4x4 matrix.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEGG EggTransform3d {
+public:
+  EggTransform3d();
+  EggTransform3d(const EggTransform3d &copy);
+  EggTransform3d &operator = (const EggTransform3d &copy);
+  ~EggTransform3d();
+
+  void clear_transform();
+
+  void add_translate(const LVector3d &translate);
+  void add_rotx(double angle); 
+  void add_roty(double angle); 
+  void add_rotz(double angle); 
+  void add_rotate(double angle, const LVector3d &axis);
+  void add_scale(const LVecBase3d &scale);
+  void add_uniform_scale(double scale);
+  void add_matrix(const LMatrix4d &mat);
+
+  INLINE bool has_transform() const;
+  INLINE void set_transform(const LMatrix4d &mat);
+  INLINE const LMatrix4d &get_transform() const;
+  INLINE bool transform_is_identity() const;
+
+  enum ComponentType {
+    CT_invalid,
+    CT_translate,
+    CT_rotx,
+    CT_roty,
+    CT_rotz,
+    CT_rotate,
+    CT_scale,
+    CT_uniform_scale,
+    CT_matrix
+  };
+
+  INLINE int get_num_components() const;
+  INLINE ComponentType get_component_type(int n) const;
+  INLINE double get_component_number(int n) const;
+  INLINE const LVector3d &get_component_vector(int n) const;
+  INLINE const LMatrix4d &get_component_matrix(int n) const;
+
+  void write(ostream &out, int indent_level) const;
+
+private:
+  class Component {
+  public:
+    INLINE Component(ComponentType type, double number = 0.0);
+    INLINE Component(const Component &copy);
+    INLINE void operator = (const Component &copy);
+    INLINE ~Component();
+
+    ComponentType _type;
+    double _number;
+    LVector3d *_vector;
+    LMatrix4d *_matrix;
+  };
+
+  typedef pvector<Component> Components;
+  Components _components;
+  LMatrix4d _transform;
+};
+
+#include "eggTransform3d.I"
+
+#endif

+ 1 - 0
panda/src/egg/egg_composite2.cxx

@@ -13,6 +13,7 @@
 #include "eggTable.cxx"
 #include "eggTexture.cxx"
 #include "eggTextureCollection.cxx"
+#include "eggTransform3d.cxx"
 #include "eggUtilities.cxx"
 #include "eggVertex.cxx"
 #include "eggVertexPool.cxx"

+ 17 - 32
panda/src/egg/parser.yxx

@@ -77,7 +77,6 @@ static int vertex_index;
 
 // We need to hold a matrix for a little bit while parsing the
 // <Transform> entries.
-static LMatrix4d matrix_3d;
 static LMatrix3d matrix_2d;
 
 
@@ -1049,12 +1048,9 @@ collide_flags:
 transform_3d:
         TRANSFORM
 {
-  matrix_3d = LMatrix4d::ident_mat();
+  DCAST(EggGroup, egg_stack.back())->clear_transform();
 }
         '{' transform_3d_body '}'
-{
-  DCAST(EggGroup, egg_stack.back())->set_transform(matrix_3d);
-}
         ;
 
 
@@ -1067,49 +1063,52 @@ transform_3d:
  */
 transform_3d_body:
           empty
-        | transform_3d_body matrix3_3d
-        | transform_3d_body matrix4_3d
         | transform_3d_body translate_3d
         | transform_3d_body rotx_3d
         | transform_3d_body roty_3d
         | transform_3d_body rotz_3d
         | transform_3d_body rotate_3d
         | transform_3d_body scale_3d
+        | transform_3d_body matrix4_3d
         ;
 
 translate_3d: TRANSLATE '{' real real real '}'
 {
-  matrix_3d *= LMatrix4d::translate_mat($3, $4, $5);
+  DCAST(EggGroup, egg_stack.back())->add_translate(LVector3d($3, $4, $5));
 }
         ;
 
 rotx_3d: ROTX '{' real '}'
 {
-  matrix_3d *= LMatrix4d::rotate_mat_normaxis($3, LVector3d(1.0, 0.0, 0.0));
+  DCAST(EggGroup, egg_stack.back())->add_rotx($3);
 }
         ;
 
 roty_3d: ROTY '{' real '}'
 {
-  matrix_3d *= LMatrix4d::rotate_mat_normaxis($3, LVector3d(0.0, 1.0, 0.0));
+  DCAST(EggGroup, egg_stack.back())->add_roty($3);
 }
         ;
 
 rotz_3d: ROTZ '{' real '}'
 {
-  matrix_3d *= LMatrix4d::rotate_mat_normaxis($3, LVector3d(0.0, 0.0, 1.0));
+  DCAST(EggGroup, egg_stack.back())->add_rotz($3);
 }
         ;
 
 rotate_3d: ROTATE '{' real real real real '}'
 {
-  matrix_3d *= LMatrix4d::rotate_mat($3, LVector3d($4, $5, $6));
+  DCAST(EggGroup, egg_stack.back())->add_rotate($3, LVector3d($4, $5, $6));
 }
         ;
 
 scale_3d: SCALE '{' real real real '}'
 {
-  matrix_3d *= LMatrix4d::scale_mat($3, $4, $5);
+  DCAST(EggGroup, egg_stack.back())->add_scale(LVecBase3d($3, $4, $5));
+}
+	| SCALE '{' real '}'
+{
+  DCAST(EggGroup, egg_stack.back())->add_uniform_scale($3);
 }
         ;
 
@@ -1124,25 +1123,11 @@ matrix4_3d_body:
           real real real real 
           real real real real 
 {
-  matrix_3d *= LMatrix4d($1, $2, $3, $4,
-                         $5, $6, $7, $8,
-                         $9, $10, $11, $12,
-                         $13, $14, $15, $16);
-}
-        ;
-
-matrix3_3d: MATRIX3 '{' matrix3_3d_body '}'
-        ;
-
-matrix3_3d_body: 
-          empty
-        | real real real
-          real real real
-          real real real
-{
-  matrix_3d *= LMatrix4d(LMatrix3d($1, $2, $3,
-                                   $4, $5, $6,
-                                   $7, $8, $9));
+  DCAST(EggGroup, egg_stack.back())->add_matrix
+    (LMatrix4d($1, $2, $3, $4,
+               $5, $6, $7, $8,
+               $9, $10, $11, $12,
+               $13, $14, $15, $16));
 }
         ;
 

+ 86 - 2
panda/src/egg2pg/eggLoader.cxx

@@ -1431,8 +1431,7 @@ create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) {
 
   // If the group had a transform, apply it to the arc.
   if (egg_group->has_transform()) {
-    LMatrix4f matf = LCAST(float, egg_group->get_transform());
-    node->set_transform(TransformState::make_mat(matf));
+    node->set_transform(make_transform(egg_group));
   }
 
   // If the group has a billboard flag, apply that.
@@ -1924,3 +1923,88 @@ apply_deferred_nodes(PandaNode *node, const DeferredNodeProperty &prop) {
     apply_deferred_nodes(node->get_child(i), next_prop);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLoader::make_transform
+//       Access: Private
+//  Description: Walks back over the tree and applies the
+//               DeferredNodeProperties that were saved up along the
+//               way.
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) EggLoader::
+make_transform(const EggTransform3d *egg_transform) {
+  // We'll build up the transform componentwise, so we preserve any
+  // componentwise properties of the egg transform.
+
+  CPT(TransformState) ts = TransformState::make_identity();
+  int num_components = egg_transform->get_num_components();
+  for (int i = 0; i < num_components; i++) {
+    switch (egg_transform->get_component_type(i)) {
+    case EggTransform3d::CT_translate:
+      {
+        LVector3f trans(LCAST(float, egg_transform->get_component_vector(i)));
+        ts = TransformState::make_pos(trans)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_rotx:
+      {
+        LRotationf rot(LVector3f(1.0f, 0.0f, 0.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_roty:
+      {
+        LRotationf rot(LVector3f(0.0f, 1.0f, 0.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_rotz:
+      {
+        LRotationf rot(LVector3f(0.0f, 0.0f, 1.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_rotate:
+      {
+        LRotationf rot(LCAST(float, egg_transform->get_component_vector(i)),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_scale:
+      {
+        LVecBase3f scale(LCAST(float, egg_transform->get_component_vector(i)));
+        ts = TransformState::make_scale(scale)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_uniform_scale:
+      {
+        float scale = (float)egg_transform->get_component_number(i);
+        ts = TransformState::make_scale(scale)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_matrix:
+      {
+        LMatrix4f mat(LCAST(float, egg_transform->get_component_matrix(i)));
+        ts = TransformState::make_mat(mat)->compose(ts);
+      }
+      break;
+
+    case EggTransform3d::CT_invalid:
+      nassertr(false, ts);
+      break;
+    }
+  }
+
+  return ts;
+}

+ 3 - 0
panda/src/egg2pg/eggLoader.h

@@ -35,6 +35,7 @@
 #include "lmatrix.h"
 #include "indirectCompareTo.h"
 #include "textureAttrib.h"
+#include "eggTransform3d.h"
 
 class EggNode;
 class EggBin;
@@ -122,6 +123,8 @@ private:
 
   void apply_deferred_nodes(PandaNode *node, const DeferredNodeProperty &prop);
 
+  CPT(TransformState) make_transform(const EggTransform3d *egg_transform);
+
   Builder _builder;
 
   typedef pmap<PT_EggTexture, TextureDef> Textures;