introduce 2-d TransformStates

This commit is contained in:
David Rose 2005-07-21 23:46:15 +00:00
parent d4faa62ea5
commit 65458d9edd
8 changed files with 609 additions and 140 deletions

View File

@ -2242,21 +2242,6 @@ do_issue_texture() {
TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage); TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
bool any_point_sprite = false; 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) { switch (mode) {
case TexGenAttrib::M_off: case TexGenAttrib::M_off:
case TexGenAttrib::M_light_vector: case TexGenAttrib::M_light_vector:
@ -2352,18 +2337,19 @@ do_issue_texture() {
_d3d_device->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite); _d3d_device->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite);
if (!tex_mat->is_identity()) { if (!tex_mat->is_identity()) {
LMatrix4f m = tex_mat->get_mat(); if (tex_mat->is_2d() && !texcoords_3d) {
_d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data());
if (!texcoords_3d) {
// For 2-d texture coordinates, we have to reorder the matrix. // 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.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
m(1, 0), m(1, 1), m(1, 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, m(3, 0), m(3, 1), m(3, 3), 0.0f,
0.0f, 0.0f, 0.0f, 1.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, _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
D3DTTFF_COUNT2); D3DTTFF_COUNT2);
} else { } 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, _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
D3DTTFF_COUNT3); D3DTTFF_COUNT3);
} }

View File

@ -1314,7 +1314,7 @@ INLINE void NodePath::
set_tex_offset(TextureStage *stage, float u, float v) { set_tex_offset(TextureStage *stage, float u, float v) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(stage, 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) { set_tex_rotate(TextureStage *stage, float r) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(stage, 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) { set_tex_scale(TextureStage *stage, float su, float sv) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(stage, 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:: INLINE LVecBase2f NodePath::
get_tex_offset(TextureStage *stage) const { get_tex_offset(TextureStage *stage) const {
nassertr_always(!is_empty(), LVecBase2f::zero()); nassertr_always(!is_empty(), LVecBase2f::zero());
const LVecBase3f &pos = get_tex_transform(stage)->get_pos(); return get_tex_transform(stage)->get_pos2d();
return LVecBase2f(pos[0], pos[1]);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1377,7 +1376,7 @@ get_tex_offset(TextureStage *stage) const {
INLINE float NodePath:: INLINE float NodePath::
get_tex_rotate(TextureStage *stage) const { get_tex_rotate(TextureStage *stage) const {
nassertr_always(!is_empty(), 0.0f); 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:: INLINE LVecBase2f NodePath::
get_tex_scale(TextureStage *stage) const { get_tex_scale(TextureStage *stage) const {
nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f)); nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f));
const LVecBase3f &scale = get_tex_transform(stage)->get_scale(); return get_tex_transform(stage)->get_scale2d();
return LVecBase2f(scale[0], scale[1]);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1414,7 +1412,7 @@ INLINE void NodePath::
set_tex_offset(const NodePath &other, TextureStage *stage, float u, float v) { set_tex_offset(const NodePath &other, TextureStage *stage, float u, float v) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(other, stage, 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) { set_tex_rotate(const NodePath &other, TextureStage *stage, float r) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(other, stage, 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) { set_tex_scale(const NodePath &other, TextureStage *stage, float su, float sv) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
set_tex_transform(other, stage, 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:: INLINE LVecBase2f NodePath::
get_tex_offset(const NodePath &other, TextureStage *stage) const { get_tex_offset(const NodePath &other, TextureStage *stage) const {
nassertr_always(!is_empty(), LVecBase2f::zero()); nassertr_always(!is_empty(), LVecBase2f::zero());
const LVecBase3f &pos = get_tex_transform(other, stage)->get_pos(); return get_tex_transform(other, stage)->get_pos2d();
return LVecBase2f(pos[0], pos[1]);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1477,7 +1474,7 @@ get_tex_offset(const NodePath &other, TextureStage *stage) const {
INLINE float NodePath:: INLINE float NodePath::
get_tex_rotate(const NodePath &other, TextureStage *stage) const { get_tex_rotate(const NodePath &other, TextureStage *stage) const {
nassertr_always(!is_empty(), 0.0f); 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:: INLINE LVecBase2f NodePath::
get_tex_scale(const NodePath &other, TextureStage *stage) const { get_tex_scale(const NodePath &other, TextureStage *stage) const {
nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f)); nassertr_always(!is_empty(), LVecBase2f(1.0f, 1.0f));
const LVecBase3f &scale = get_tex_transform(other, stage)->get_scale(); return get_tex_transform(other, stage)->get_scale2d();
return LVecBase2f(scale[0], scale[1]);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -57,10 +57,13 @@ make() {
// Function: TexMatrixAttrib::make // Function: TexMatrixAttrib::make
// Access: Published, Static // Access: Published, Static
// Description: Constructs a TexMatrixAttrib that applies the // 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:: CPT(RenderAttrib) TexMatrixAttrib::
make(const LMatrix4f &mat) { make(const LMatrix4f &mat) {
pgraph_cat.warning()
<< "Using deprecated TexMatrixAttrib interface.\n";
if (mat == LMatrix4f::ident_mat()) { if (mat == LMatrix4f::ident_mat()) {
return make(); return make();
} }
@ -68,20 +71,6 @@ make(const LMatrix4f &mat) {
return make(TextureStage::get_default(), transform); 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 // Function: TexMatrixAttrib::make
// Access: Published, Static // Access: Published, Static

View File

@ -45,7 +45,6 @@ public:
PUBLISHED: PUBLISHED:
static CPT(RenderAttrib) make(); static CPT(RenderAttrib) make();
static CPT(RenderAttrib) make(const LMatrix4f &mat); static CPT(RenderAttrib) make(const LMatrix4f &mat);
static CPT(RenderAttrib) make(const TransformState *transform);
static CPT(RenderAttrib) make(TextureStage *stage, const TransformState *transform); static CPT(RenderAttrib) make(TextureStage *stage, const TransformState *transform);
CPT(RenderAttrib) add_stage(TextureStage *stage, const TransformState *transform) const; CPT(RenderAttrib) add_stage(TextureStage *stage, const TransformState *transform) const;

View File

@ -76,9 +76,9 @@ make_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE CPT(TransformState) TransformState:: INLINE CPT(TransformState) TransformState::
make_scale(float scale) { make_scale(float scale) {
return make_pos_hpr_scale(LVecBase3f(0.0f, 0.0f, 0.0f), // We actually map this 3-d uniform make_scale() to the 2-d
LVecBase3f(0.0f, 0.0f, 0.0f), // version--might as well call it a 2-d scale.
LVecBase3f(scale, scale, 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()); 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 // Function: TransformState::is_identity
// Access: Published // Access: Published
@ -168,6 +250,19 @@ is_singular() const {
return ((_flags & F_is_singular) != 0); 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 // Function: TransformState::has_components
// Access: Published // Access: Published
@ -446,6 +541,89 @@ get_mat() const {
return _mat; 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 // Function: TransformState::get_geom_rendering
// Access: Published // 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 // Function: TransformState::set_destructing
// Access: Private // Access: Private

View File

@ -55,7 +55,7 @@ TransformState() {
_states = new States; _states = new States;
} }
_saved_entry = _states->end(); _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; _inv_mat = (LMatrix4f *)NULL;
} }
@ -120,7 +120,7 @@ TransformState::
bool TransformState:: bool TransformState::
operator < (const TransformState &other) const { operator < (const TransformState &other) const {
static const int significant_flags = 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 flags = (_flags & significant_flags);
int other_flags = (other._flags & significant_flags); int other_flags = (other._flags & significant_flags);
@ -185,7 +185,7 @@ get_hash() const {
size_t hash = 0; size_t hash = 0;
static const int significant_flags = 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); int flags = (_flags & significant_flags);
hash = int_hash::add_hash(hash, flags); hash = int_hash::add_hash(hash, flags);
@ -327,6 +327,74 @@ make_mat(const LMatrix4f &mat) {
return return_new(state); 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 // Function: TransformState::set_pos
// Access: Published // 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 // Function: TransformState::compose
// Access: Published // Access: Published
@ -672,26 +836,50 @@ output(ostream &out) const {
} }
char lead = '('; char lead = '(';
if (!get_pos().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) { if (is_2d()) {
out << lead << "pos " << get_pos(); if (!get_pos2d().almost_equal(LVecBase2f(0.0f, 0.0f))) {
lead = ' '; out << lead << "pos " << get_pos2d();
} lead = ' ';
if (output_hpr) { }
out << lead << "hpr " << get_hpr(); if (output_hpr) {
lead = ' '; out << lead << "rotate " << get_rotate2d();
} lead = ' ';
if (!get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) { }
if (has_uniform_scale()) { if (!get_scale2d().almost_equal(LVecBase2f(1.0f, 1.0f))) {
out << lead << "scale " << get_uniform_scale(); if (has_uniform_scale()) {
lead = ' '; out << lead << "scale " << get_uniform_scale();
} else { lead = ' ';
out << lead << "scale " << get_scale(); } 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 = ' '; lead = ' ';
} }
}
if (has_nonzero_shear()) {
out << lead << "shear " << get_shear();
lead = ' ';
} }
if (lead == '(') { if (lead == '(') {
out << "(almost identity)"; out << "(almost identity)";
@ -700,7 +888,11 @@ output(ostream &out) const {
} }
} else { } else {
out << get_mat(); if (is_2d()) {
out << get_mat3();
} else {
out << get_mat();
}
} }
} }
@ -1082,17 +1274,35 @@ do_compose(const TransformState *other) const {
// was given componentwise (and there is no non-uniform scale in // was given componentwise (and there is no non-uniform scale in
// the way). // the way).
LVecBase3f pos = get_pos(); CPT(TransformState) result;
LQuaternionf quat = get_quat(); if (is_2d() && other->is_2d()) {
float scale = get_uniform_scale(); // 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; LPoint3f op = quat.xform(other->get_pos());
quat = other->get_quat() * quat; pos += LVecBase2f(op[0], op[1]) * scale;
quat.normalize();
LVecBase3f new_scale = other->get_scale() * scale;
CPT(TransformState) result = rotate += other->get_rotate2d();
make_pos_quat_scale(pos, quat, new_scale); 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 #ifndef NDEBUG
if (paranoid_compose) { if (paranoid_compose) {
@ -1113,8 +1323,13 @@ do_compose(const TransformState *other) const {
} }
// Do the operation with matrices. // Do the operation with matrices.
LMatrix4f new_mat = other->get_mat() * get_mat(); if (is_2d()) {
return make_mat(new_mat); 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 // was given componentwise (and there is no non-uniform scale in
// the way). // the way).
LVecBase3f pos = get_pos(); CPT(TransformState) result;
LQuaternionf quat = get_quat(); if (is_2d() && other->is_2d()) {
float scale = get_uniform_scale(); // 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. // First, invert our own transform.
if (scale == 0.0f) { if (scale == 0.0f) {
((TransformState *)this)->_flags |= F_is_singular | F_singular_known; ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
return make_invalid(); 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;
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 #ifndef NDEBUG
if (paranoid_compose) { if (paranoid_compose) {
@ -1195,10 +1443,22 @@ do_invert_compose(const TransformState *other) const {
// _inv_mat has been allocated and filled in. // _inv_mat has been allocated and filled in.
nassertr(_inv_mat != (LMatrix4f *)NULL, make_invalid()); nassertr(_inv_mat != (LMatrix4f *)NULL, make_invalid());
if (other->is_identity()) { if (is_2d()) {
return make_mat(*_inv_mat); 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 { } 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) { if ((_flags & F_is_identity) != 0) {
// Identity, nothing much to that. // Identity, nothing much to that.
int flags = F_is_identity | F_singular_known; int flags = F_is_identity | F_singular_known | F_is_2d;
dg.add_uint16(flags); dg.add_uint32(flags);
} else if ((_flags & F_is_invalid) != 0) { } else if ((_flags & F_is_invalid) != 0) {
// Invalid, nothing much to that either. // Invalid, nothing much to that either.
int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known; 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) { } else if ((_flags & F_components_given) != 0) {
// A component-based transform. // A component-based transform.
int flags = F_components_given | F_components_known | F_has_components; int flags = F_components_given | F_components_known | F_has_components;
flags |= (_flags & F_is_2d);
if ((_flags & F_quat_given) != 0) { if ((_flags & F_quat_given) != 0) {
flags |= (F_quat_given | F_quat_known); flags |= (F_quat_given | F_quat_known);
} else if ((_flags & F_hpr_given) != 0) { } else if ((_flags & F_hpr_given) != 0) {
flags |= (F_hpr_given | F_hpr_known); flags |= (F_hpr_given | F_hpr_known);
} }
dg.add_uint16(flags); dg.add_uint32(flags);
_pos.write_datagram(dg); _pos.write_datagram(dg);
if ((_flags & F_quat_given) != 0) { if ((_flags & F_quat_given) != 0) {
@ -1579,7 +1840,8 @@ write_datagram(BamWriter *manager, Datagram &dg) {
// A general matrix. // A general matrix.
nassertv((_flags & F_mat_known) != 0); nassertv((_flags & F_mat_known) != 0);
int flags = F_mat_known; int flags = F_mat_known;
dg.add_uint16(flags); flags |= (_flags & F_is_2d);
dg.add_uint32(flags);
_mat.write_datagram(dg); _mat.write_datagram(dg);
} }
} }
@ -1668,7 +1930,11 @@ void TransformState::
fillin(DatagramIterator &scan, BamReader *manager) { fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, 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) { if ((_flags & F_components_given) != 0) {
// Componentwise transform. // Componentwise transform.
@ -1677,9 +1943,6 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_quat.read_datagram(scan); _quat.read_datagram(scan);
} else { } else {
_hpr.read_datagram(scan); _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); _scale.read_datagram(scan);
_shear.read_datagram(scan); _shear.read_datagram(scan);

View File

@ -79,7 +79,7 @@ PUBLISHED:
const LVecBase3f &hpr); const LVecBase3f &hpr);
INLINE static CPT(TransformState) make_scale(float scale); INLINE static CPT(TransformState) make_scale(float scale);
INLINE static CPT(TransformState) make_scale(const LVecBase3f &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, INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos,
const LVecBase3f &hpr, const LVecBase3f &hpr,
const LVecBase3f &scale); const LVecBase3f &scale);
@ -96,9 +96,29 @@ PUBLISHED:
const LVecBase3f &shear); const LVecBase3f &shear);
static CPT(TransformState) make_mat(const LMatrix4f &mat); 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_identity() const;
INLINE bool is_invalid() const; INLINE bool is_invalid() const;
INLINE bool is_singular() const; INLINE bool is_singular() const;
INLINE bool is_2d() const;
INLINE bool has_components() const; INLINE bool has_components() const;
INLINE bool components_given() const; INLINE bool components_given() const;
INLINE bool hpr_given() const; INLINE bool hpr_given() const;
@ -112,6 +132,7 @@ PUBLISHED:
INLINE bool has_shear() const; INLINE bool has_shear() const;
INLINE bool has_nonzero_shear() const; INLINE bool has_nonzero_shear() const;
INLINE bool has_mat() const; INLINE bool has_mat() const;
INLINE const LVecBase3f &get_pos() const; INLINE const LVecBase3f &get_pos() const;
INLINE const LVecBase3f &get_hpr() const; INLINE const LVecBase3f &get_hpr() const;
INLINE const LQuaternionf &get_quat() const; INLINE const LQuaternionf &get_quat() const;
@ -120,12 +141,23 @@ PUBLISHED:
INLINE const LVecBase3f &get_shear() const; INLINE const LVecBase3f &get_shear() const;
INLINE const LMatrix4f &get_mat() 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_pos(const LVecBase3f &pos) const;
CPT(TransformState) set_hpr(const LVecBase3f &hpr) const; CPT(TransformState) set_hpr(const LVecBase3f &hpr) const;
CPT(TransformState) set_quat(const LQuaternionf &quat) const; CPT(TransformState) set_quat(const LQuaternionf &quat) const;
CPT(TransformState) set_scale(const LVecBase3f &scale) const; CPT(TransformState) set_scale(const LVecBase3f &scale) const;
CPT(TransformState) set_shear(const LVecBase3f &shear) 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) compose(const TransformState *other) const;
CPT(TransformState) invert_compose(const TransformState *other) const; CPT(TransformState) invert_compose(const TransformState *other) const;
@ -229,6 +261,7 @@ private:
void calc_mat(); void calc_mat();
INLINE void check_uniform_scale(); INLINE void check_uniform_scale();
INLINE void check_uniform_scale2d();
INLINE void set_destructing(); INLINE void set_destructing();
INLINE bool is_destructing() const; INLINE bool is_destructing() const;
@ -237,29 +270,30 @@ private:
static void update_pstats(int old_referenced_bits, int new_referenced_bits); static void update_pstats(int old_referenced_bits, int new_referenced_bits);
enum Flags { enum Flags {
F_is_identity = 0x0001, F_is_identity = 0x00000001,
F_is_singular = 0x0002, F_is_singular = 0x00000002,
F_singular_known = 0x0004, // set if we know F_is_singular F_singular_known = 0x00000004, // set if we know F_is_singular
F_components_given = 0x0008, F_components_given = 0x00000008,
F_components_known = 0x0010, // set if we know F_has_components F_components_known = 0x00000010, // set if we know F_has_components
F_has_components = 0x0020, F_has_components = 0x00000020,
F_mat_known = 0x0040, // set if _mat is defined F_mat_known = 0x00000040, // set if _mat is defined
F_is_invalid = 0x0080, F_is_invalid = 0x00000080,
F_quat_given = 0x0100, F_quat_given = 0x00000100,
F_quat_known = 0x0200, // set if _quat is defined F_quat_known = 0x00000200, // set if _quat is defined
F_hpr_given = 0x0400, F_hpr_given = 0x00000400,
F_hpr_known = 0x0800, // set if _hpr is defined F_hpr_known = 0x00000800, // set if _hpr is defined
F_uniform_scale = 0x1000, F_uniform_scale = 0x00001000,
F_identity_scale = 0x2000, F_identity_scale = 0x00002000,
F_has_nonzero_shear = 0x4000, F_has_nonzero_shear = 0x00004000,
F_is_destructing = 0x8000, F_is_destructing = 0x00008000,
F_is_2d = 0x00010000,
}; };
LVecBase3f _pos, _hpr, _scale, _shear; LVecBase3f _pos, _hpr, _scale, _shear;
LQuaternionf _quat; LQuaternionf _quat;
LMatrix4f _mat; LMatrix4f _mat;
LMatrix4f *_inv_mat; LMatrix4f *_inv_mat;
unsigned short _flags; unsigned int _flags;
public: public:
static void register_with_read_factory(); static void register_with_read_factory();

View File

@ -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 4 on 4/10/02 to store new scene graph.
// Bumped to major version 5 on 5/6/05 for new Geom implementation. // 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 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 #endif