From 65458d9edd882aa410509b10211da8a91e95d174 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 21 Jul 2005 23:46:15 +0000 Subject: [PATCH] introduce 2-d TransformStates --- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 24 +- panda/src/pgraph/nodePath.I | 28 +- panda/src/pgraph/texMatrixAttrib.cxx | 19 +- panda/src/pgraph/texMatrixAttrib.h | 1 - panda/src/pgraph/transformState.I | 207 ++++++++- panda/src/pgraph/transformState.cxx | 397 +++++++++++++++--- panda/src/pgraph/transformState.h | 70 ++- panda/src/putil/bam.h | 3 +- 8 files changed, 609 insertions(+), 140 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 8b61c783e8..0bc3cd402d 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2242,21 +2242,6 @@ do_issue_texture() { TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage); bool any_point_sprite = false; - // These transforms are used in the below to invert certain - // computed component values in various modes, to emulate the - // behavior of OpenGL, so we get a consistent behavior between the - // two of them. - static CPT(TransformState) invert_z = - TransformState::make_mat(LMatrix4f(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f)); - static CPT(TransformState) invert_y = - TransformState::make_mat(LMatrix4f(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f)); - switch (mode) { case TexGenAttrib::M_off: case TexGenAttrib::M_light_vector: @@ -2352,18 +2337,19 @@ do_issue_texture() { _d3d_device->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite); if (!tex_mat->is_identity()) { - LMatrix4f m = tex_mat->get_mat(); - _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data()); - - if (!texcoords_3d) { + if (tex_mat->is_2d() && !texcoords_3d) { // For 2-d texture coordinates, we have to reorder the matrix. + LMatrix4f m = tex_mat->get_mat(); m.set(m(0, 0), m(0, 1), m(0, 3), 0.0f, m(1, 0), m(1, 1), m(1, 3), 0.0f, m(3, 0), m(3, 1), m(3, 3), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); + _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data()); _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); } else { + LMatrix4f m = tex_mat->get_mat(); + _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data()); _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3); } diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index 809be27b35..88949ea9ad 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -1314,7 +1314,7 @@ INLINE void NodePath:: set_tex_offset(TextureStage *stage, float u, float v) { nassertv_always(!is_empty()); set_tex_transform(stage, - get_tex_transform(stage)->set_pos(LVecBase3f(u, v, 0.0f))); + get_tex_transform(stage)->set_pos2d(LVecBase2f(u, v))); } //////////////////////////////////////////////////////////////////// @@ -1328,7 +1328,7 @@ INLINE void NodePath:: set_tex_rotate(TextureStage *stage, float r) { nassertv_always(!is_empty()); set_tex_transform(stage, - get_tex_transform(stage)->set_hpr(LVecBase3f(r, 0.0f, 0.0f))); + get_tex_transform(stage)->set_rotate2d(r)); } //////////////////////////////////////////////////////////////////// @@ -1352,7 +1352,7 @@ INLINE void NodePath:: set_tex_scale(TextureStage *stage, float su, float sv) { nassertv_always(!is_empty()); set_tex_transform(stage, - get_tex_transform(stage)->set_scale(LVecBase3f(su, sv, 1.0f))); + get_tex_transform(stage)->set_scale2d(LVecBase2f(su, sv))); } //////////////////////////////////////////////////////////////////// @@ -1364,8 +1364,7 @@ set_tex_scale(TextureStage *stage, float su, float sv) { INLINE LVecBase2f NodePath:: get_tex_offset(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2f::zero()); - const LVecBase3f &pos = get_tex_transform(stage)->get_pos(); - return LVecBase2f(pos[0], pos[1]); + return get_tex_transform(stage)->get_pos2d(); } //////////////////////////////////////////////////////////////////// @@ -1377,7 +1376,7 @@ get_tex_offset(TextureStage *stage) const { INLINE float NodePath:: get_tex_rotate(TextureStage *stage) const { nassertr_always(!is_empty(), 0.0f); - return get_tex_transform(stage)->get_hpr()[0]; + return get_tex_transform(stage)->get_rotate2d(); } //////////////////////////////////////////////////////////////////// @@ -1389,8 +1388,7 @@ get_tex_rotate(TextureStage *stage) const { INLINE LVecBase2f NodePath:: get_tex_scale(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f)); - const LVecBase3f &scale = get_tex_transform(stage)->get_scale(); - return LVecBase2f(scale[0], scale[1]); + return get_tex_transform(stage)->get_scale2d(); } //////////////////////////////////////////////////////////////////// @@ -1414,7 +1412,7 @@ INLINE void NodePath:: set_tex_offset(const NodePath &other, TextureStage *stage, float u, float v) { nassertv_always(!is_empty()); set_tex_transform(other, stage, - get_tex_transform(other, stage)->set_pos(LVecBase3f(u, v, 0.0f))); + get_tex_transform(other, stage)->set_pos2d(LVecBase2f(u, v))); } //////////////////////////////////////////////////////////////////// @@ -1428,7 +1426,7 @@ INLINE void NodePath:: set_tex_rotate(const NodePath &other, TextureStage *stage, float r) { nassertv_always(!is_empty()); set_tex_transform(other, stage, - get_tex_transform(other, stage)->set_hpr(LVecBase3f(r, 0.0f, 0.0f))); + get_tex_transform(other, stage)->set_rotate2d(r)); } //////////////////////////////////////////////////////////////////// @@ -1452,7 +1450,7 @@ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, float su, float sv) { nassertv_always(!is_empty()); set_tex_transform(other, stage, - get_tex_transform(stage)->set_scale(LVecBase3f(su, sv, 1.0f))); + get_tex_transform(stage)->set_scale2d(LVecBase2f(su, sv))); } //////////////////////////////////////////////////////////////////// @@ -1464,8 +1462,7 @@ set_tex_scale(const NodePath &other, TextureStage *stage, float su, float sv) { INLINE LVecBase2f NodePath:: get_tex_offset(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2f::zero()); - const LVecBase3f &pos = get_tex_transform(other, stage)->get_pos(); - return LVecBase2f(pos[0], pos[1]); + return get_tex_transform(other, stage)->get_pos2d(); } //////////////////////////////////////////////////////////////////// @@ -1477,7 +1474,7 @@ get_tex_offset(const NodePath &other, TextureStage *stage) const { INLINE float NodePath:: get_tex_rotate(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), 0.0f); - return get_tex_transform(other, stage)->get_hpr()[0]; + return get_tex_transform(other, stage)->get_rotate2d(); } //////////////////////////////////////////////////////////////////// @@ -1489,8 +1486,7 @@ get_tex_rotate(const NodePath &other, TextureStage *stage) const { INLINE LVecBase2f NodePath:: get_tex_scale(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f)); - const LVecBase3f &scale = get_tex_transform(other, stage)->get_scale(); - return LVecBase2f(scale[0], scale[1]); + return get_tex_transform(other, stage)->get_scale2d(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/texMatrixAttrib.cxx b/panda/src/pgraph/texMatrixAttrib.cxx index 23a17ba948..8889b4ab27 100644 --- a/panda/src/pgraph/texMatrixAttrib.cxx +++ b/panda/src/pgraph/texMatrixAttrib.cxx @@ -57,10 +57,13 @@ make() { // Function: TexMatrixAttrib::make // Access: Published, Static // Description: Constructs a TexMatrixAttrib that applies the -// indicated matrix to the default texture stage. +// indicated matrix to the default texture stage. This +// interface is deprecated. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(const LMatrix4f &mat) { + pgraph_cat.warning() + << "Using deprecated TexMatrixAttrib interface.\n"; if (mat == LMatrix4f::ident_mat()) { return make(); } @@ -68,20 +71,6 @@ make(const LMatrix4f &mat) { return make(TextureStage::get_default(), transform); } -//////////////////////////////////////////////////////////////////// -// Function: TexMatrixAttrib::make -// Access: Published, Static -// Description: Constructs a TexMatrixAttrib that applies the -// indicated transform to the default texture stage. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) TexMatrixAttrib:: -make(const TransformState *transform) { - if (transform->is_identity()) { - return make(); - } - return make(TextureStage::get_default(), transform); -} - //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make // Access: Published, Static diff --git a/panda/src/pgraph/texMatrixAttrib.h b/panda/src/pgraph/texMatrixAttrib.h index 858577b2ce..2fc1b4b1f0 100644 --- a/panda/src/pgraph/texMatrixAttrib.h +++ b/panda/src/pgraph/texMatrixAttrib.h @@ -45,7 +45,6 @@ public: PUBLISHED: static CPT(RenderAttrib) make(); static CPT(RenderAttrib) make(const LMatrix4f &mat); - static CPT(RenderAttrib) make(const TransformState *transform); static CPT(RenderAttrib) make(TextureStage *stage, const TransformState *transform); CPT(RenderAttrib) add_stage(TextureStage *stage, const TransformState *transform) const; diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index 8423025998..1d985950c4 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -76,9 +76,9 @@ make_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) { //////////////////////////////////////////////////////////////////// INLINE CPT(TransformState) TransformState:: make_scale(float scale) { - return make_pos_hpr_scale(LVecBase3f(0.0f, 0.0f, 0.0f), - LVecBase3f(0.0f, 0.0f, 0.0f), - LVecBase3f(scale, scale, scale)); + // We actually map this 3-d uniform make_scale() to the 2-d + // version--might as well call it a 2-d scale. + return make_scale2d(scale); } //////////////////////////////////////////////////////////////////// @@ -132,6 +132,88 @@ make_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat, return make_pos_quat_scale_shear(pos, quat, scale, LVecBase3f::zero()); } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_pos2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_pos2d(const LVecBase2f &pos) { + return make_pos_rotate_scale2d(pos, 0.0f, LVecBase2f(1.0f, 1.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_rotate2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_rotate2d(float rotate) { + return make_pos_rotate_scale2d(LVecBase2f(0.0f, 0.0f), rotate, + LVecBase2f(1.0f, 1.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_pos_rotate2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_pos_rotate2d(const LVecBase2f &pos, float rotate) { + return make_pos_rotate_scale2d(pos, rotate, + LVecBase2f(1.0, 1.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_scale2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_scale2d(float scale) { + return make_pos_rotate_scale2d(LVecBase2f(0.0f, 0.0f), 0.0f, + LVecBase2f(scale, scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_scale2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_scale2d(const LVecBase2f &scale) { + return make_pos_rotate_scale2d(LVecBase2f(0.0f, 0.0f), 0.0f, scale); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_shear2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_shear2d(float shear) { + return make_pos_rotate_scale_shear2d(LVecBase2f(0.0f, 0.0f), 0.0f, + LVecBase2f(1.0f, 1.0f), shear); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_pos_rotate_scale2d +// Access: Published, Static +// Description: Makes a new 2-d TransformState with the specified +// components. +//////////////////////////////////////////////////////////////////// +INLINE CPT(TransformState) TransformState:: +make_pos_rotate_scale2d(const LVecBase2f &pos, float rotate, + const LVecBase2f &scale) { + return make_pos_rotate_scale_shear2d(pos, rotate, scale, 0.0f); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::is_identity // Access: Published @@ -168,6 +250,19 @@ is_singular() const { return ((_flags & F_is_singular) != 0); } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::is_2d +// Access: Published +// Description: Returns true if the transform has been constructed +// entirely using the 2-d transform operations, +// e.g. make_pos2d(), and therefore operates strictly in +// two-dimensional space on X and Y only. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +is_2d() const { + return ((_flags & F_is_2d) != 0); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::has_components // Access: Published @@ -446,6 +541,89 @@ get_mat() const { return _mat; } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::get_pos2d +// Access: Published +// Description: Returns the pos component of the 2-d transform. It +// is an error to call this if has_pos() or is_2d() +// returned false. +//////////////////////////////////////////////////////////////////// +INLINE LVecBase2f TransformState:: +get_pos2d() const { + check_components(); + nassertr(has_pos() && is_2d(), LVecBase2f::zero()); + return LVecBase2f(_pos[0], _pos[1]); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::get_rotate2d +// Access: Published +// Description: Returns the rotation component of the 2-d transform +// as an angle in degrees clockwise about the origin. +// It is an error to call this if has_components() or +// is_2d() returned false. +//////////////////////////////////////////////////////////////////// +INLINE float TransformState:: +get_rotate2d() const { + check_hpr(); + nassertr(!is_invalid() && is_2d(), 0); + switch (get_default_coordinate_system()) { + default: + case CS_zup_right: + return _hpr[0]; + case CS_zup_left: + return -_hpr[0]; + case CS_yup_right: + return -_hpr[2]; + case CS_yup_left: + return _hpr[2]; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::get_scale2d +// Access: Published +// Description: Returns the scale component of the 2-d transform. It +// is an error to call this if has_components() or +// is_2d() returned false. +//////////////////////////////////////////////////////////////////// +INLINE LVecBase2f TransformState:: +get_scale2d() const { + check_components(); + nassertr(!is_invalid() && is_2d(), LVecBase2f::zero()); + return LVecBase2f(_scale[0], _scale[1]); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::get_shear2d +// Access: Published +// Description: Returns the shear component of the 2-d transform. It +// is an error to call this if has_components() or +// is_2d() returned false. +//////////////////////////////////////////////////////////////////// +INLINE float TransformState:: +get_shear2d() const { + check_components(); + nassertr(!is_invalid() && is_2d(), 0.0f); + return _shear[0]; +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::get_mat3 +// Access: Published +// Description: Returns the 3x3 matrix that describes the 2-d +// transform. It is an error to call this if is_2d() +// returned false. +//////////////////////////////////////////////////////////////////// +INLINE LMatrix3f TransformState:: +get_mat3() const { + nassertr(has_mat() && is_2d(), LMatrix3f::ident_mat()); + check_mat(); + return LMatrix3f(_mat(0, 0), _mat(0, 1), _mat(0, 3), + _mat(1, 0), _mat(1, 1), _mat(1, 3), + _mat(3, 0), _mat(3, 1), _mat(3, 3)); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::get_geom_rendering // Access: Published @@ -631,6 +809,29 @@ check_uniform_scale() { } } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::check_uniform_scale2d +// Access: Private +// Description: Should be called immediately after _scale (and +// F_has_components) is set, for a known 2-d scale, this +// checks for a identity and/or uniform scale (as well +// as a non-zero shear) and sets the bit appropriately. +//////////////////////////////////////////////////////////////////// +INLINE void TransformState:: +check_uniform_scale2d() { + if (IS_NEARLY_EQUAL(_scale[0], _scale[1])) { + _scale[2] = _scale[0]; + _flags |= F_uniform_scale; + if (IS_NEARLY_EQUAL(_scale[0], 1.0f)) { + _flags |= F_identity_scale; + } + } + + if (!_shear.almost_equal(LVecBase3f::zero())) { + _flags |= F_has_nonzero_shear; + } +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::set_destructing // Access: Private diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 611a2c7425..5041f7a86e 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -55,7 +55,7 @@ TransformState() { _states = new States; } _saved_entry = _states->end(); - _flags = F_is_identity | F_singular_known; + _flags = F_is_identity | F_singular_known | F_is_2d; _inv_mat = (LMatrix4f *)NULL; } @@ -120,7 +120,7 @@ TransformState:: bool TransformState:: operator < (const TransformState &other) const { static const int significant_flags = - (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given); + (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d); int flags = (_flags & significant_flags); int other_flags = (other._flags & significant_flags); @@ -185,7 +185,7 @@ get_hash() const { size_t hash = 0; static const int significant_flags = - (F_is_invalid | F_is_identity | F_components_given | F_hpr_given); + (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d); int flags = (_flags & significant_flags); hash = int_hash::add_hash(hash, flags); @@ -327,6 +327,74 @@ make_mat(const LMatrix4f &mat) { return return_new(state); } + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_pos_rotate_scale_shear2d +// Access: Published, Static +// Description: Makes a new two-dimensional TransformState with the +// specified components. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +make_pos_rotate_scale_shear2d(const LVecBase2f &pos, float rotate, + const LVecBase2f &scale, + float shear) { + nassertr(!(pos.is_nan() || cnan(rotate) || scale.is_nan() || cnan(shear)) , make_invalid()); + // Make a special-case check for the identity transform. + if (pos == LVecBase2f(0.0f, 0.0f) && + rotate == 0.0f && + scale == LVecBase2f(1.0f, 1.0f) && + shear == 0.0f) { + return make_identity(); + } + + TransformState *state = new TransformState; + state->_pos.set(pos[0], pos[1], 0.0f); + switch (get_default_coordinate_system()) { + default: + case CS_zup_right: + state->_hpr.set(rotate, 0.0f, 0.0f); + break; + case CS_zup_left: + state->_hpr.set(-rotate, 0.0f, 0.0f); + break; + case CS_yup_right: + state->_hpr.set(0.0f, 0.0f, -rotate); + break; + case CS_yup_left: + state->_hpr.set(0.0, 0.0f, rotate); + break; + } + state->_scale.set(scale[0], scale[1], 1.0f); + state->_shear.set(shear, 0.0f, 0.0f); + state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components | F_is_2d; + state->check_uniform_scale2d(); + return return_new(state); +} + + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::make_mat3 +// Access: Published, Static +// Description: Makes a new two-dimensional TransformState with the +// specified 3x3 transformation matrix. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +make_mat3(const LMatrix3f &mat) { + nassertr(!mat.is_nan(), make_invalid()); + // Make a special-case check for the identity matrix. + if (mat == LMatrix3f::ident_mat()) { + return make_identity(); + } + + TransformState *state = new TransformState; + state->_mat.set(mat(0, 0), mat(0, 1), 0.0f, mat(0, 2), + mat(1, 0), mat(1, 1), 0.0f, mat(1, 2), + 0.0f, 0.0f, 1.0f, 0.0f, + mat(2, 0), mat(2, 1), 0.0f, mat(2, 2)); + state->_flags = F_mat_known | F_is_2d; + return return_new(state); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::set_pos // Access: Published @@ -423,6 +491,102 @@ set_shear(const LVecBase3f &shear) const { } } +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_pos2d +// Access: Published +// Description: Returns a new TransformState object that represents the +// original 2-d TransformState with its pos component +// replaced with the indicated value. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_pos2d(const LVecBase2f &pos) const { + nassertr(!pos.is_nan(), this); + nassertr(!is_invalid(), this); + if (!is_2d()) { + return set_pos(LVecBase3f(pos[0], pos[1], 0.0f)); + } + + if (is_identity() || components_given()) { + // If we started with a componentwise transform, we keep it that + // way. + return make_pos_rotate_scale_shear2d(pos, get_rotate2d(), get_scale2d(), + get_shear2d()); + + } else { + // Otherwise, we have a matrix transform, and we keep it that way. + LMatrix3f mat = get_mat3(); + mat.set_row(2, pos); + return make_mat3(mat); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_rotate2d +// Access: Published +// Description: Returns a new TransformState object that represents the +// original 2-d TransformState with its rotation component +// replaced with the indicated value, if possible. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_rotate2d(float rotate) const { + nassertr(!cnan(rotate), this); + nassertr(!is_invalid(), this); + + if (!is_2d()) { + switch (get_default_coordinate_system()) { + default: + case CS_zup_right: + return set_hpr(LVecBase3f(rotate, 0.0f, 0.0f)); + case CS_zup_left: + return set_hpr(LVecBase3f(-rotate, 0.0f, 0.0f)); + case CS_yup_right: + return set_hpr(LVecBase3f(0.0f, 0.0f, -rotate)); + case CS_yup_left: + return set_hpr(LVecBase3f(0.0f, 0.0f, rotate)); + } + } + + return make_pos_rotate_scale_shear2d(get_pos2d(), rotate, get_scale2d(), + get_shear2d()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_scale2d +// Access: Published +// Description: Returns a new TransformState object that represents the +// original 2-d TransformState with its scale component +// replaced with the indicated value, if possible. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_scale2d(const LVecBase2f &scale) const { + nassertr(!scale.is_nan(), this); + nassertr(!is_invalid(), this); + + if (!is_2d()) { + return set_scale(LVecBase3f(scale[0], scale[1], 1.0f)); + } + return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(), + scale, get_shear2d()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::set_shear2d +// Access: Published +// Description: Returns a new TransformState object that represents the +// original 2-d TransformState with its shear component +// replaced with the indicated value, if possible. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) TransformState:: +set_shear2d(float shear) const { + nassertr(!cnan(shear), this); + nassertr(!is_invalid(), this); + if (!is_2d()) { + return set_shear(LVecBase3f(shear, 0.0f, 0.0f)); + } + return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(), + get_scale2d(), shear); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::compose // Access: Published @@ -672,26 +836,50 @@ output(ostream &out) const { } char lead = '('; - if (!get_pos().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) { - out << lead << "pos " << get_pos(); - lead = ' '; - } - if (output_hpr) { - out << lead << "hpr " << get_hpr(); - lead = ' '; - } - if (!get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) { - if (has_uniform_scale()) { - out << lead << "scale " << get_uniform_scale(); - lead = ' '; - } else { - out << lead << "scale " << get_scale(); + if (is_2d()) { + if (!get_pos2d().almost_equal(LVecBase2f(0.0f, 0.0f))) { + out << lead << "pos " << get_pos2d(); + lead = ' '; + } + if (output_hpr) { + out << lead << "rotate " << get_rotate2d(); + lead = ' '; + } + if (!get_scale2d().almost_equal(LVecBase2f(1.0f, 1.0f))) { + if (has_uniform_scale()) { + out << lead << "scale " << get_uniform_scale(); + lead = ' '; + } else { + out << lead << "scale " << get_scale2d(); + lead = ' '; + } + } + if (has_nonzero_shear()) { + out << lead << "shear " << get_shear2d(); + lead = ' '; + } + } else { + if (!get_pos().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) { + out << lead << "pos " << get_pos(); + lead = ' '; + } + if (output_hpr) { + out << lead << "hpr " << get_hpr(); + lead = ' '; + } + if (!get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) { + if (has_uniform_scale()) { + out << lead << "scale " << get_uniform_scale(); + lead = ' '; + } else { + out << lead << "scale " << get_scale(); + lead = ' '; + } + } + if (has_nonzero_shear()) { + out << lead << "shear " << get_shear(); lead = ' '; } - } - if (has_nonzero_shear()) { - out << lead << "shear " << get_shear(); - lead = ' '; } if (lead == '(') { out << "(almost identity)"; @@ -700,7 +888,11 @@ output(ostream &out) const { } } else { - out << get_mat(); + if (is_2d()) { + out << get_mat3(); + } else { + out << get_mat(); + } } } @@ -1082,18 +1274,36 @@ do_compose(const TransformState *other) const { // was given componentwise (and there is no non-uniform scale in // the way). - LVecBase3f pos = get_pos(); - LQuaternionf quat = get_quat(); - float scale = get_uniform_scale(); + CPT(TransformState) result; + if (is_2d() && other->is_2d()) { + // Do a 2-d compose. + LVecBase2f pos = get_pos2d(); + float rotate = get_rotate2d(); + LQuaternionf quat = get_quat(); + float scale = get_uniform_scale(); - pos += quat.xform(other->get_pos()) * scale; - quat = other->get_quat() * quat; - quat.normalize(); - LVecBase3f new_scale = other->get_scale() * scale; + LPoint3f op = quat.xform(other->get_pos()); + pos += LVecBase2f(op[0], op[1]) * scale; - CPT(TransformState) result = - make_pos_quat_scale(pos, quat, new_scale); + rotate += other->get_rotate2d(); + LVecBase2f new_scale = other->get_scale2d() * scale; + + result = make_pos_rotate_scale2d(pos, rotate, new_scale); + } else { + // A normal 3-d compose. + LVecBase3f pos = get_pos(); + LQuaternionf quat = get_quat(); + float scale = get_uniform_scale(); + + pos += quat.xform(other->get_pos()) * scale; + quat = other->get_quat() * quat; + quat.normalize(); + LVecBase3f new_scale = other->get_scale() * scale; + + result = make_pos_quat_scale(pos, quat, new_scale); + } + #ifndef NDEBUG if (paranoid_compose) { // Now verify against the matrix. @@ -1113,8 +1323,13 @@ do_compose(const TransformState *other) const { } // Do the operation with matrices. - LMatrix4f new_mat = other->get_mat() * get_mat(); - return make_mat(new_mat); + if (is_2d()) { + LMatrix3f new_mat = other->get_mat3() * get_mat3(); + return make_mat3(new_mat); + } else { + LMatrix4f new_mat = other->get_mat() * get_mat(); + return make_mat(new_mat); + } } //////////////////////////////////////////////////////////////////// @@ -1138,30 +1353,63 @@ do_invert_compose(const TransformState *other) const { // was given componentwise (and there is no non-uniform scale in // the way). - LVecBase3f pos = get_pos(); - LQuaternionf quat = get_quat(); - float scale = get_uniform_scale(); + CPT(TransformState) result; + if (is_2d() && other->is_2d()) { + // Do a 2-d invert compose. + LVecBase2f pos = get_pos2d(); + float rotate = get_rotate2d(); + LQuaternionf quat = get_quat(); + float scale = get_uniform_scale(); + + // First, invert our own transform. + if (scale == 0.0f) { + ((TransformState *)this)->_flags |= F_is_singular | F_singular_known; + return make_invalid(); + } + scale = 1.0f / scale; + quat.invert_in_place(); + rotate = -rotate; + LVecBase3f mp = quat.xform(-LVecBase3f(pos[0], pos[1], 0.0f)); + pos = LVecBase2f(mp[0], mp[1]) * scale; + LVecBase2f new_scale(scale, scale); + + // Now compose the inverted transform with the other transform. + if (!other->is_identity()) { + LPoint3f op = quat.xform(other->get_pos()); + pos += LVecBase2f(op[0], op[1]) * scale; - // First, invert our own transform. - if (scale == 0.0f) { - ((TransformState *)this)->_flags |= F_is_singular | F_singular_known; - return make_invalid(); + rotate += other->get_rotate2d(); + new_scale = other->get_scale2d() * scale; + } + + result = make_pos_rotate_scale2d(pos, rotate, new_scale); + + } else { + // Do a normal, 3-d invert compose. + LVecBase3f pos = get_pos(); + LQuaternionf quat = get_quat(); + float scale = get_uniform_scale(); + + // First, invert our own transform. + if (scale == 0.0f) { + ((TransformState *)this)->_flags |= F_is_singular | F_singular_known; + return make_invalid(); + } + scale = 1.0f / scale; + quat.invert_in_place(); + pos = quat.xform(-pos) * scale; + LVecBase3f new_scale(scale, scale, scale); + + // Now compose the inverted transform with the other transform. + if (!other->is_identity()) { + pos += quat.xform(other->get_pos()) * scale; + quat = other->get_quat() * quat; + quat.normalize(); + new_scale = other->get_scale() * scale; + } + + result = make_pos_quat_scale(pos, quat, new_scale); } - scale = 1.0f / scale; - quat.invert_in_place(); - pos = quat.xform(-pos) * scale; - LVecBase3f new_scale(scale, scale, scale); - - // Now compose the inverted transform with the other transform. - if (!other->is_identity()) { - pos += quat.xform(other->get_pos()) * scale; - quat = other->get_quat() * quat; - quat.normalize(); - new_scale = other->get_scale() * scale; - } - - CPT(TransformState) result = - make_pos_quat_scale(pos, quat, new_scale); #ifndef NDEBUG if (paranoid_compose) { @@ -1195,10 +1443,22 @@ do_invert_compose(const TransformState *other) const { // _inv_mat has been allocated and filled in. nassertr(_inv_mat != (LMatrix4f *)NULL, make_invalid()); - if (other->is_identity()) { - return make_mat(*_inv_mat); + if (is_2d()) { + const LMatrix4f &i = *_inv_mat; + LMatrix3f inv3(i(0, 0), i(0, 1), i(0, 3), + i(1, 0), i(1, 1), i(1, 3), + i(3, 0), i(3, 1), i(3, 3)); + if (other->is_identity()) { + return make_mat3(inv3); + } else { + return make_mat3(other->get_mat3() * inv3); + } } else { - return make_mat(other->get_mat() * (*_inv_mat)); + if (other->is_identity()) { + return make_mat(*_inv_mat); + } else { + return make_mat(other->get_mat() * (*_inv_mat)); + } } } @@ -1547,24 +1807,25 @@ write_datagram(BamWriter *manager, Datagram &dg) { if ((_flags & F_is_identity) != 0) { // Identity, nothing much to that. - int flags = F_is_identity | F_singular_known; - dg.add_uint16(flags); + int flags = F_is_identity | F_singular_known | F_is_2d; + dg.add_uint32(flags); } else if ((_flags & F_is_invalid) != 0) { // Invalid, nothing much to that either. int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known; - dg.add_uint16(flags); + dg.add_uint32(flags); } else if ((_flags & F_components_given) != 0) { // A component-based transform. int flags = F_components_given | F_components_known | F_has_components; + flags |= (_flags & F_is_2d); 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); + dg.add_uint32(flags); _pos.write_datagram(dg); if ((_flags & F_quat_given) != 0) { @@ -1579,7 +1840,8 @@ write_datagram(BamWriter *manager, Datagram &dg) { // A general matrix. nassertv((_flags & F_mat_known) != 0); int flags = F_mat_known; - dg.add_uint16(flags); + flags |= (_flags & F_is_2d); + dg.add_uint32(flags); _mat.write_datagram(dg); } } @@ -1668,7 +1930,11 @@ void TransformState:: fillin(DatagramIterator &scan, BamReader *manager) { TypedWritable::fillin(scan, manager); - _flags = scan.get_uint16(); + if (manager->get_file_minor_ver() < 2) { + _flags = scan.get_uint16(); + } else { + _flags = scan.get_uint32(); + } if ((_flags & F_components_given) != 0) { // Componentwise transform. @@ -1677,9 +1943,6 @@ fillin(DatagramIterator &scan, BamReader *manager) { _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); _shear.read_datagram(scan); diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index ce94166fd1..d8b43ddda4 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -79,7 +79,7 @@ PUBLISHED: const LVecBase3f &hpr); INLINE static CPT(TransformState) make_scale(float scale); INLINE static CPT(TransformState) make_scale(const LVecBase3f &scale); - INLINE static CPT(TransformState) make_shear(const LVecBase3f &scale); + INLINE static CPT(TransformState) make_shear(const LVecBase3f &shear); INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr, const LVecBase3f &scale); @@ -96,9 +96,29 @@ PUBLISHED: const LVecBase3f &shear); static CPT(TransformState) make_mat(const LMatrix4f &mat); + + INLINE static CPT(TransformState) make_pos2d(const LVecBase2f &pos); + INLINE static CPT(TransformState) make_rotate2d(float rotate); + INLINE static CPT(TransformState) make_pos_rotate2d(const LVecBase2f &pos, + float rotate); + INLINE static CPT(TransformState) make_scale2d(float scale); + INLINE static CPT(TransformState) make_scale2d(const LVecBase2f &scale); + INLINE static CPT(TransformState) make_shear2d(float shear); + INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2f &pos, + float rotate, + const LVecBase2f &scale); + static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2f &pos, + float rotate, + const LVecBase2f &scale, + float shear); + static CPT(TransformState) make_mat3(const LMatrix3f &mat); + + INLINE bool is_identity() const; INLINE bool is_invalid() const; INLINE bool is_singular() const; + INLINE bool is_2d() const; + INLINE bool has_components() const; INLINE bool components_given() const; INLINE bool hpr_given() const; @@ -112,6 +132,7 @@ PUBLISHED: INLINE bool has_shear() const; INLINE bool has_nonzero_shear() const; INLINE bool has_mat() const; + INLINE const LVecBase3f &get_pos() const; INLINE const LVecBase3f &get_hpr() const; INLINE const LQuaternionf &get_quat() const; @@ -120,12 +141,23 @@ PUBLISHED: INLINE const LVecBase3f &get_shear() const; INLINE const LMatrix4f &get_mat() const; + INLINE LVecBase2f get_pos2d() const; + INLINE float get_rotate2d() const; + INLINE LVecBase2f get_scale2d() const; + INLINE float get_shear2d() const; + INLINE LMatrix3f get_mat3() 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) set_shear(const LVecBase3f &shear) const; + CPT(TransformState) set_pos2d(const LVecBase2f &pos) const; + CPT(TransformState) set_rotate2d(float rotate) const; + CPT(TransformState) set_scale2d(const LVecBase2f &scale) const; + CPT(TransformState) set_shear2d(float shear) const; + CPT(TransformState) compose(const TransformState *other) const; CPT(TransformState) invert_compose(const TransformState *other) const; @@ -229,6 +261,7 @@ private: void calc_mat(); INLINE void check_uniform_scale(); + INLINE void check_uniform_scale2d(); INLINE void set_destructing(); INLINE bool is_destructing() const; @@ -237,29 +270,30 @@ private: static void update_pstats(int old_referenced_bits, int new_referenced_bits); enum Flags { - F_is_identity = 0x0001, - F_is_singular = 0x0002, - F_singular_known = 0x0004, // set if we know F_is_singular - F_components_given = 0x0008, - F_components_known = 0x0010, // set if we know F_has_components - F_has_components = 0x0020, - 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_identity_scale = 0x2000, - F_has_nonzero_shear = 0x4000, - F_is_destructing = 0x8000, + F_is_identity = 0x00000001, + F_is_singular = 0x00000002, + F_singular_known = 0x00000004, // set if we know F_is_singular + F_components_given = 0x00000008, + F_components_known = 0x00000010, // set if we know F_has_components + F_has_components = 0x00000020, + F_mat_known = 0x00000040, // set if _mat is defined + F_is_invalid = 0x00000080, + F_quat_given = 0x00000100, + F_quat_known = 0x00000200, // set if _quat is defined + F_hpr_given = 0x00000400, + F_hpr_known = 0x00000800, // set if _hpr is defined + F_uniform_scale = 0x00001000, + F_identity_scale = 0x00002000, + F_has_nonzero_shear = 0x00004000, + F_is_destructing = 0x00008000, + F_is_2d = 0x00010000, }; LVecBase3f _pos, _hpr, _scale, _shear; LQuaternionf _quat; LMatrix4f _mat; LMatrix4f *_inv_mat; - unsigned short _flags; + unsigned int _flags; public: static void register_with_read_factory(); diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index ca001c2e8e..5ad9f35ddd 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -35,8 +35,9 @@ static const unsigned short _bam_major_ver = 5; // Bumped to major version 4 on 4/10/02 to store new scene graph. // Bumped to major version 5 on 5/6/05 for new Geom implementation. -static const unsigned short _bam_minor_ver = 1; +static const unsigned short _bam_minor_ver = 2; // Bumped to minor version 1 on 7/14/05 to add TextureStage::_saved_result. +// Bumped to minor version 2 on 7/21/05 to add TransformState::is_2d. #endif