Преглед на файлове

add get_quat() and get_uniform_scale()

David Rose преди 23 години
родител
ревизия
bc946860e6
променени са 3 файла, в които са добавени 318 реда и са изтрити 33 реда
  1. 149 7
      panda/src/pgraph/transformState.I
  2. 143 23
      panda/src/pgraph/transformState.cxx
  3. 26 3
      panda/src/pgraph/transformState.h

+ 149 - 7
panda/src/pgraph/transformState.I

@@ -63,6 +63,19 @@ make_hpr(const LVecBase3f &hpr) {
                             LVecBase3f(1.0f, 1.0f, 1.0f));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::make_quat
+//       Access: Published, Static
+//  Description: Makes a new TransformState with the specified
+//               components.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(TransformState) TransformState::
+make_quat(const LQuaternionf &quat) {
+  return make_pos_quat_scale(LVecBase3f(0.0f, 0.0f, 0.0f),
+                             quat, 
+                             LVecBase3f(1.0f, 1.0f, 1.0f));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::make_pos_hpr
 //       Access: Published, Static
@@ -168,15 +181,44 @@ has_components() const {
 //  Description: Returns true if the transform was specified
 //               componentwise, or false if it was specified with a
 //               general 4x4 matrix.  If this is true, the components
-//               returned by get_pos(), get_hpr(), and get_scale()
-//               will be exactly those that were set; otherwise, these
-//               functions will return computed values.
+//               returned by get_pos() and get_scale() will be exactly
+//               those that were set; otherwise, these functions will
+//               return computed values.  If this is true, the
+//               rotation may have been set either with a hpr trio or
+//               with a quaternion; hpr_given() or quat_given() can
+//               resolve the difference.
 ////////////////////////////////////////////////////////////////////
 INLINE bool TransformState::
 components_given() const {
   return ((_flags & F_components_given) != 0);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::hpr_given
+//       Access: Published
+//  Description: Returns true if the rotation was specified via a trio
+//               of Euler angles, false otherwise.  If this is true,
+//               get_hpr() will be exactly as set; otherwise, it will
+//               return a computed value.
+////////////////////////////////////////////////////////////////////
+INLINE bool TransformState::
+hpr_given() const {
+  return ((_flags & F_hpr_given) != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::quat_given
+//       Access: Published
+//  Description: Returns true if the rotation was specified via a 
+//               quaternion, false otherwise.  If this is true,
+//               get_quat() will be exactly as set; otherwise, it will
+//               return a computed value.
+////////////////////////////////////////////////////////////////////
+INLINE bool TransformState::
+quat_given() const {
+  return ((_flags & F_quat_given) != 0);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::has_pos
 //       Access: Published
@@ -203,6 +245,19 @@ has_hpr() const {
   return has_components();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::has_quat
+//       Access: Published
+//  Description: Returns true if the transform's rotation component
+//               can be extracted out separately and described as a
+//               quaternion.  This is generally true only when
+//               has_components() is true.
+////////////////////////////////////////////////////////////////////
+INLINE bool TransformState::
+has_quat() const {
+  return has_components();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::has_scale
 //       Access: Published
@@ -215,6 +270,20 @@ has_scale() const {
   return has_components();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::has_uniform_scale
+//       Access: Published
+//  Description: Returns true if the scale is uniform across all three
+//               axes (and therefore can be expressed as a single
+//               number), or false if the transform has a different
+//               scale in different dimensions.
+////////////////////////////////////////////////////////////////////
+INLINE bool TransformState::
+has_uniform_scale() const {
+  check_components();
+  return (_flags & F_uniform_scale) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::has_mat
 //       Access: Published
@@ -243,17 +312,31 @@ get_pos() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::get_hpr
 //       Access: Published
-//  Description: Returns the hpr component of the transform.  It is an
-//               error to call this if has_components() returned
-//               false.
+//  Description: Returns the rotation component of the transform as a
+//               trio of Euler angles.  It is an error to call this if
+//               has_components() returned false.
 ////////////////////////////////////////////////////////////////////
 INLINE const LVecBase3f &TransformState::
 get_hpr() const {
-  check_components();
+  check_hpr();
   nassertr(has_hpr(), _hpr);
   return _hpr;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::get_quat
+//       Access: Published
+//  Description: Returns the rotation component of the transform as a
+//               quaternion.  It is an error to call this if
+//               has_components() returned false.
+////////////////////////////////////////////////////////////////////
+INLINE const LQuaternionf &TransformState::
+get_quat() const {
+  check_quat();
+  nassertr(has_quat(), _quat);
+  return _quat;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::get_scale
 //       Access: Published
@@ -268,6 +351,20 @@ get_scale() const {
   return _scale;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::get_uniform_scale
+//       Access: Published
+//  Description: Returns the scale component of the transform, as a
+//               single number.  It is an error to call this if
+//               has_uniform_scale() returned false.
+////////////////////////////////////////////////////////////////////
+INLINE float TransformState::
+get_uniform_scale() const {
+  check_components();
+  nassertr(has_uniform_scale(), _scale[0]);
+  return _scale[0];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::get_mat
 //       Access: Published
@@ -309,6 +406,36 @@ check_components() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::check_hpr
+//       Access: Private
+//  Description: Ensures that we know the hpr of the transform
+//               (or that we know they cannot be derived).
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+check_hpr() const {
+  // This pretends to be a const function, even though it's not,
+  // because it only updates a transparent cache value.
+  if ((_flags & F_hpr_known) == 0) {
+    ((TransformState *)this)->calc_hpr();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::check_quat
+//       Access: Private
+//  Description: Ensures that we know the quat of the transform
+//               (or that we know they cannot be derived).
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+check_quat() const {
+  // This pretends to be a const function, even though it's not,
+  // because it only updates a transparent cache value.
+  if ((_flags & F_quat_known) == 0) {
+    ((TransformState *)this)->calc_quat();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::check_mat
 //       Access: Private
@@ -323,6 +450,21 @@ check_mat() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::check_uniform_scale
+//       Access: Private
+//  Description: Should be called immediately after _scale (and
+//               F_has_components) is set, this checks for a uniform
+//               scale and sets the bit appropriately.
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+check_uniform_scale() {
+  if (IS_NEARLY_EQUAL(_scale[0], _scale[1]) && 
+      IS_NEARLY_EQUAL(_scale[0], _scale[2])) {
+    _flags |= F_uniform_scale;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::set_destructing
 //       Access: Private

+ 143 - 23
panda/src/pgraph/transformState.cxx

@@ -206,7 +206,7 @@ TransformState::
 bool TransformState::
 operator < (const TransformState &other) const {
   static const int significant_flags = 
-    (F_is_invalid | F_is_identity | F_components_given);
+    (F_is_invalid | F_is_identity | F_components_given | F_hpr_given);
 
   int flags = (_flags & significant_flags);
   int other_flags = (other._flags & significant_flags);
@@ -220,7 +220,8 @@ operator < (const TransformState &other) const {
     return 0;
   }
 
-  if ((_flags & F_components_given) != 0) {
+  if ((_flags & (F_components_given | F_hpr_given)) == 
+      (F_components_given | F_hpr_given)) {
     // If the transform was specified componentwise, compare them
     // componentwise.
     int c = _pos.compare_to(other._pos);
@@ -301,7 +302,33 @@ make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
   state->_pos = pos;
   state->_hpr = hpr;
   state->_scale = scale;
-  state->_flags = F_components_given | F_components_known | F_has_components;
+  state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components;
+  state->check_uniform_scale();
+  return return_new(state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::make_pos_quat_scale
+//       Access: Published, Static
+//  Description: Makes a new TransformState with the specified
+//               components.
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) TransformState::
+make_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat, 
+                    const LVecBase3f &scale) {
+  // Make a special-case check for the identity transform.
+  if (pos == LVecBase3f(0.0f, 0.0f, 0.0f) &&
+      quat == LQuaternionf::ident_quat() &&
+      scale == LVecBase3f(1.0f, 1.0f, 1.0f)) {
+    return make_identity();
+  }
+
+  TransformState *state = new TransformState;
+  state->_pos = pos;
+  state->_quat = quat;
+  state->_scale = scale;
+  state->_flags = F_components_given | F_quat_given | F_components_known | F_quat_known | F_has_components;
+  state->check_uniform_scale();
   return return_new(state);
 }
 
@@ -333,10 +360,14 @@ make_mat(const LMatrix4f &mat) {
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
 set_pos(const LVecBase3f &pos) const {
-  if ((_flags & F_components_given) != 0) {
+  if (components_given()) {
     // If we started with a componentwise transform, we keep it that
     // way.
-    return make_pos_hpr_scale(pos, get_hpr(), get_scale());
+    if (quat_given()) {
+      return make_pos_quat_scale(pos, get_quat(), get_scale());
+    } else {
+      return make_pos_hpr_scale(pos, get_hpr(), get_scale());
+    }
 
   } else {
     // Otherwise, we have a matrix transform, and we keep it that way.
@@ -350,7 +381,7 @@ set_pos(const LVecBase3f &pos) const {
 //     Function: TransformState::set_hpr
 //       Access: Published
 //  Description: Returns a new TransformState object that represents the
-//               original TransformState with its hpr component
+//               original TransformState with its rotation component
 //               replaced with the indicated value, if possible.
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
@@ -359,6 +390,19 @@ set_hpr(const LVecBase3f &hpr) const {
   return make_pos_hpr_scale(get_pos(), hpr, get_scale());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::set_quat
+//       Access: Published
+//  Description: Returns a new TransformState object that represents the
+//               original TransformState with its rotation component
+//               replaced with the indicated value, if possible.
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) TransformState::
+set_quat(const LQuaternionf &quat) const {
+  nassertr(has_components(), this);
+  return make_pos_quat_scale(get_pos(), quat, get_scale());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::set_scale
 //       Access: Published
@@ -369,7 +413,11 @@ set_hpr(const LVecBase3f &hpr) const {
 CPT(TransformState) TransformState::
 set_scale(const LVecBase3f &scale) const {
   nassertr(has_components(), this);
-  return make_pos_hpr_scale(get_pos(), get_hpr(), scale);
+  if (quat_given()) {
+    return make_pos_quat_scale(get_pos(), get_quat(), scale);
+  } else {
+    return make_pos_hpr_scale(get_pos(), get_hpr(), scale);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -549,13 +597,25 @@ output(ostream &out) const {
       out << lead << "pos " << get_pos();
       lead = ' ';
     }
-    if (!get_hpr().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) {
-      out << lead << "hpr " << get_hpr();
-      lead = ' ';
+    if (quat_given()) {
+      if (!get_quat().almost_equal(LQuaternionf::ident_quat())) {
+        out << lead << "quat " << get_quat();
+        lead = ' ';
+      }
+    } else {
+      if (!get_hpr().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) {
+        out << lead << "hpr " << get_hpr();
+        lead = ' ';
+      }
     }
     if (!get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
-      out << lead << "scale " << get_scale();
-      lead = ' ';
+      if (has_uniform_scale()) {
+        out << lead << "scale " << get_uniform_scale();
+        lead = ' ';
+      } else {
+        out << lead << "scale " << get_scale();
+        lead = ' ';
+      }
     }
     if (lead == '(') {
       out << "(almost identity)";
@@ -702,8 +762,9 @@ calc_components() {
   if ((_flags & F_is_identity) != 0) {
     _scale.set(1.0f, 1.0f, 1.0f);
     _hpr.set(0.0f, 0.0f, 0.0f);
+    _quat = LQuaternionf::ident_quat();
     _pos.set(0.0f, 0.0f, 0.0f);
-    _flags |= F_has_components;
+    _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale;
 
   } else {
     // If we don't have components and we're not identity, the only
@@ -712,16 +773,57 @@ calc_components() {
 
     const LMatrix4f &mat = get_mat();
     bool possible = decompose_matrix(mat, _scale, _hpr, _pos);
-    if (possible) {
-      // Some matrices can't be decomposed into scale, hpr, pos.
-      _flags |= F_has_components;
+    if (!possible) {
+      // Some matrices can't be decomposed into scale, hpr, pos.  In
+      // this case, we now know that we cannot compute the components.
+      _flags |= F_components_known | F_hpr_known | F_quat_known;
 
-      // However, we can always get at least the pos.
-      mat.get_row3(_pos, 3);
+    } else {
+      // Otherwise, we do have the components, or at least the hpr.
+      _flags |= F_has_components | F_components_known | F_hpr_known;
+      check_uniform_scale();
     }
+
+    // However, we can always get at least the pos.
+    mat.get_row3(_pos, 3);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::calc_hpr
+//       Access: Private
+//  Description: Derives the hpr, from the matrix if necessary, or
+//               from the quat.
+////////////////////////////////////////////////////////////////////
+void TransformState::
+calc_hpr() {
+  nassertv((_flags & F_is_invalid) == 0);
+  check_components();
+  if ((_flags & F_hpr_known) == 0) {
+    // If we don't know the hpr yet, we must have been given a quat.
+    // Decompose it.
+    nassertv((_flags & F_quat_known) != 0);
+    _hpr = _quat.get_hpr();
+    _flags |= F_hpr_known;
   }
+}
 
-  _flags |= F_components_known;
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::calc_quat
+//       Access: Private
+//  Description: Derives the quat from the hpr.
+////////////////////////////////////////////////////////////////////
+void TransformState::
+calc_quat() {
+  nassertv((_flags & F_is_invalid) == 0);
+  check_components();
+  if ((_flags & F_quat_known) == 0) {
+    // If we don't know the quat yet, we must have been given a hpr.
+    // Decompose it.
+    nassertv((_flags & F_hpr_known) != 0);
+    _quat.set_hpr(_hpr);
+    _flags |= F_quat_known;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -739,7 +841,7 @@ calc_mat() {
     // If we don't have a matrix and we're not identity, the only
     // other explanation is that we were constructed via components.
     nassertv((_flags & F_components_known) != 0);
-    compose_matrix(_mat, _scale, _hpr, _pos);
+    compose_matrix(_mat, _scale, get_hpr(), _pos);
   }
   _flags |= F_mat_known;
 }
@@ -778,10 +880,20 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   } else if ((_flags & F_components_given) != 0) {
     // A component-based transform.
     int flags = F_components_given | F_components_known | F_has_components;
+    if ((_flags & F_quat_given) != 0) {
+      flags |= (F_quat_given | F_quat_known);
+    } else if ((_flags & F_hpr_given) != 0) {
+      flags |= (F_hpr_given | F_hpr_known);
+    }
+
     dg.add_uint16(flags);
 
     _pos.write_datagram(dg);
-    _hpr.write_datagram(dg);
+    if ((_flags & F_quat_given) != 0) {
+      _quat.write_datagram(dg);
+    } else {
+      get_hpr().write_datagram(dg);
+    }
     _scale.write_datagram(dg);
 
   } else {
@@ -879,11 +991,19 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
   _flags = scan.get_uint16();
 
-  if ((_flags & F_components_known) != 0) {
+  if ((_flags & F_components_given) != 0) {
     // Componentwise transform.
     _pos.read_datagram(scan);
-    _hpr.read_datagram(scan);
+    if ((_flags & F_quat_given) != 0) {
+      _quat.read_datagram(scan);
+    } else {
+      _hpr.read_datagram(scan);
+      // Holdover support for bams 4.0 or older: add these bits that
+      // should have been added when the bam was written.
+      _flags |= (F_hpr_given | F_hpr_known);
+    }
     _scale.read_datagram(scan);
+    check_uniform_scale();
   }
 
   if ((_flags & F_mat_known) != 0) {

+ 26 - 3
panda/src/pgraph/transformState.h

@@ -70,6 +70,7 @@ PUBLISHED:
   static CPT(TransformState) make_invalid();
   INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos);
   INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr);
+  INLINE static CPT(TransformState) make_quat(const LQuaternionf &quat);
   INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos,
                                                  const LVecBase3f &hpr);
   INLINE static CPT(TransformState) make_scale(float scale);
@@ -77,6 +78,9 @@ PUBLISHED:
   static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos,
                                                 const LVecBase3f &hpr, 
                                                 const LVecBase3f &scale);
+  static CPT(TransformState) make_pos_quat_scale(const LVecBase3f &pos,
+                                                 const LQuaternionf &quat, 
+                                                 const LVecBase3f &scale);
   static CPT(TransformState) make_mat(const LMatrix4f &mat);
 
   INLINE bool is_identity() const;
@@ -84,17 +88,24 @@ PUBLISHED:
   INLINE bool is_singular() const;
   INLINE bool has_components() const;
   INLINE bool components_given() const;
+  INLINE bool hpr_given() const;
+  INLINE bool quat_given() const;
   INLINE bool has_pos() const;
   INLINE bool has_hpr() const;
+  INLINE bool has_quat() const;
   INLINE bool has_scale() const;
+  INLINE bool has_uniform_scale() const;
   INLINE bool has_mat() const;
   INLINE const LVecBase3f &get_pos() const;
   INLINE const LVecBase3f &get_hpr() const;
+  INLINE const LQuaternionf &get_quat() const;
   INLINE const LVecBase3f &get_scale() const;
+  INLINE float get_uniform_scale() const;
   INLINE const LMatrix4f &get_mat() const;
 
   CPT(TransformState) set_pos(const LVecBase3f &pos) const;
   CPT(TransformState) set_hpr(const LVecBase3f &hpr) const;
+  CPT(TransformState) set_quat(const LQuaternionf &quat) const;
   CPT(TransformState) set_scale(const LVecBase3f &scale) const;
 
   CPT(TransformState) compose(const TransformState *other) const;
@@ -144,26 +155,38 @@ private:
   // This is the actual data within the TransformState.
   INLINE void check_singular() const;
   INLINE void check_components() const;
+  INLINE void check_hpr() const;
+  INLINE void check_quat() const;
   INLINE void check_mat() const;
   void calc_singular();
   void calc_components();
+  void calc_hpr();
+  void calc_quat();
   void calc_mat();
 
+  INLINE void check_uniform_scale();
+
   INLINE void set_destructing();
   INLINE bool is_destructing() const;
 
   enum Flags {
     F_is_identity      = 0x0001,
     F_is_singular      = 0x0002,
-    F_singular_known   = 0x0004,
+    F_singular_known   = 0x0004,  // set if we know F_is_singular
     F_components_given = 0x0008,
-    F_components_known = 0x0010,
+    F_components_known = 0x0010,  // set if we know F_has_components
     F_has_components   = 0x0020,
-    F_mat_known        = 0x0040,
+    F_mat_known        = 0x0040,  // set if _mat is defined
     F_is_invalid       = 0x0080,
+    F_quat_given       = 0x0100,
+    F_quat_known       = 0x0200,  // set if _quat is defined
+    F_hpr_given        = 0x0400,
+    F_hpr_known        = 0x0800,  // set if _hpr is defined
+    F_uniform_scale    = 0x1000,
     F_is_destructing   = 0x8000,
   };
   LVecBase3f _pos, _hpr, _scale;
+  LQuaternionf _quat;
   LMatrix4f _mat;
   LMatrix4f *_inv_mat;