// Filename: texMatrixAttrib.cxx // Created by: drose (14Mar02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #include "texMatrixAttrib.h" #include "graphicsStateGuardianBase.h" #include "dcast.h" #include "bamReader.h" #include "bamWriter.h" #include "datagram.h" #include "datagramIterator.h" #include "textureStagePool.h" CPT(RenderAttrib) TexMatrixAttrib::_empty_attrib; TypeHandle TexMatrixAttrib::_type_handle; int TexMatrixAttrib::_attrib_slot; //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::Destructor // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// TexMatrixAttrib:: ~TexMatrixAttrib() { } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make // Access: Published, Static // Description: Constructs a TexMatrixAttrib that applies // no stages at all. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make() { // We make it a special case and store a pointer to the empty attrib // forever once we find it the first time, as an optimization. if (_empty_attrib == (RenderAttrib *)NULL) { _empty_attrib = return_new(new TexMatrixAttrib); } return _empty_attrib; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make // Access: Published, Static // Description: Constructs a TexMatrixAttrib that applies the // indicated matrix to the default texture stage. This // interface is deprecated. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(const LMatrix4 &mat) { pgraph_cat.warning() << "Using deprecated TexMatrixAttrib interface.\n"; if (mat == LMatrix4::ident_mat()) { return make(); } CPT(TransformState) transform = TransformState::make_mat(mat); return make(TextureStage::get_default(), transform); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make // Access: Published, Static // Description: Constructs a TexMatrixAttrib that applies the // indicated transform to the named texture stage. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(TextureStage *stage, const TransformState *transform) { return DCAST(TexMatrixAttrib, make())->add_stage(stage, transform); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make_default // Access: Published, Static // Description: Returns a RenderAttrib that corresponds to whatever // the standard default properties for render attributes // of this type ought to be. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make_default() { return return_new(new TexMatrixAttrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::add_stage // Access: Published, Static // Description: Returns a new TexMatrixAttrib just like this one, // with the indicated transform for the given stage. If // this stage already exists, its transform is replaced. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: add_stage(TextureStage *stage, const TransformState *transform, int override) const { TexMatrixAttrib *attrib = new TexMatrixAttrib(*this); Stages::iterator si = attrib->_stages.insert(StageNode(stage)).first; (*si)._transform = transform; (*si)._override = override; return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::remove_stage // Access: Published, Static // Description: Returns a new TexMatrixAttrib just like this one, // with the indicated stage removed. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: remove_stage(TextureStage *stage) const { TexMatrixAttrib *attrib = new TexMatrixAttrib(*this); attrib->_stages.erase(StageNode(stage)); return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_mat // Access: Published // Description: Returns the transformation matrix associated with // the default texture stage. //////////////////////////////////////////////////////////////////// const LMatrix4 &TexMatrixAttrib:: get_mat() const { return get_mat(TextureStage::get_default()); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::is_empty // Access: Published // Description: Returns true if no stages are defined in the // TexMatrixAttrib, false if at least one is. //////////////////////////////////////////////////////////////////// bool TexMatrixAttrib:: is_empty() const { return _stages.empty(); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::has_stage // Access: Published // Description: Returns true if there is a transform associated with // the indicated stage, or false otherwise (in which // case get_transform(stage) will return the identity // transform). //////////////////////////////////////////////////////////////////// bool TexMatrixAttrib:: has_stage(TextureStage *stage) const { Stages::const_iterator mi = _stages.find(StageNode(stage)); return (mi != _stages.end()); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_num_stages // Access: Published // Description: Returns the number of stages that are represented by // this attrib. //////////////////////////////////////////////////////////////////// int TexMatrixAttrib:: get_num_stages() const { return _stages.size(); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_stage // Access: Published // Description: Returns the nth stage that is represented by this // attrib. The TextureStages are in no particular // order. //////////////////////////////////////////////////////////////////// TextureStage *TexMatrixAttrib:: get_stage(int n) const { nassertr(n >= 0 && n < (int)_stages.size(), NULL); return _stages[n]._stage; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_mat // Access: Published // Description: Returns the transformation matrix associated with // the indicated texture stage, or identity matrix if // nothing is associated with the indicated stage. //////////////////////////////////////////////////////////////////// const LMatrix4 &TexMatrixAttrib:: get_mat(TextureStage *stage) const { return get_transform(stage)->get_mat(); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_transform // Access: Published // Description: Returns the transformation associated with // the indicated texture stage, or identity matrix if // nothing is associated with the indicated stage. //////////////////////////////////////////////////////////////////// CPT(TransformState) TexMatrixAttrib:: get_transform(TextureStage *stage) const { Stages::const_iterator mi = _stages.find(StageNode(stage)); if (mi != _stages.end()) { return (*mi)._transform; } return TransformState::make_identity(); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::output // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// void TexMatrixAttrib:: output(ostream &out) const { out << get_type() << ":"; Stages::const_iterator mi; for (mi = _stages.begin(); mi != _stages.end(); ++mi) { const StageNode &sn = (*mi); out << " " << sn._stage->get_name() << "(" << *sn._transform << ")"; if (sn._override != 0) { out << "^" << sn._override; } } } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::compare_to_impl // Access: Protected, Virtual // Description: Intended to be overridden by derived TexMatrixAttrib // types to return a unique number indicating whether // this TexMatrixAttrib is equivalent to the other one. // // This should return 0 if the two TexMatrixAttrib objects // are equivalent, a number less than zero if this one // should be sorted before the other one, and a number // greater than zero otherwise. // // This will only be called with two TexMatrixAttrib // objects whose get_type() functions return the same. //////////////////////////////////////////////////////////////////// int TexMatrixAttrib:: compare_to_impl(const RenderAttrib *other) const { const TexMatrixAttrib *ta; DCAST_INTO_R(ta, other, 0); Stages::const_iterator ai, bi; ai = _stages.begin(); bi = ta->_stages.begin(); while (ai != _stages.end() && bi != ta->_stages.end()) { if ((*ai) < (*bi)) { // This stage is in a but not in b. return -1; } else if ((*bi) < (*ai)) { // This stage is in b but not in a. return 1; } else { // This stage is in both. ++ai; ++bi; } } if (bi != ta->_stages.end()) { // a ran out first; b was longer. return -1; } if (ai != _stages.end()) { // b ran out first; a was longer. return 1; } return 0; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_hash_impl // Access: Protected, Virtual // Description: Intended to be overridden by derived RenderAttrib // types to return a unique hash for these particular // properties. RenderAttribs that compare the same with // compare_to_impl(), above, should return the same // hash; RenderAttribs that compare differently should // return a different hash. //////////////////////////////////////////////////////////////////// size_t TexMatrixAttrib:: get_hash_impl() const { size_t hash = 0; Stages::const_iterator si; for (si = _stages.begin(); si != _stages.end(); ++si) { const StageNode &sn = (*si); hash = pointer_hash::add_hash(hash, sn._stage); hash = pointer_hash::add_hash(hash, sn._transform); hash = int_hash::add_hash(hash, sn._override); } return hash; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::compose_impl // Access: Protected, Virtual // Description: Intended to be overridden by derived RenderAttrib // types to specify how two consecutive RenderAttrib // objects of the same type interact. // // This should return the result of applying the other // RenderAttrib to a node in the scene graph below this // RenderAttrib, which was already applied. In most // cases, the result is the same as the other // RenderAttrib (that is, a subsequent RenderAttrib // completely replaces the preceding one). On the other // hand, some kinds of RenderAttrib (for instance, // ColorTransformAttrib) might combine in meaningful // ways. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: compose_impl(const RenderAttrib *other) const { const TexMatrixAttrib *ta; DCAST_INTO_R(ta, other, 0); // The composition is the union of the two attribs. In the case // when a stage is in both attribs, we compose the stages. TexMatrixAttrib *attrib = new TexMatrixAttrib; Stages::const_iterator ai, bi; ai = _stages.begin(); bi = ta->_stages.begin(); while (ai != _stages.end() && bi != ta->_stages.end()) { if ((*ai)._stage < (*bi)._stage) { // This stage is in a but not in b. attrib->_stages.insert(attrib->_stages.end(), *ai); ++ai; } else if ((*bi)._stage < (*ai)._stage) { // This stage is in b but not in a. attrib->_stages.insert(attrib->_stages.end(), *bi); ++bi; } else { // This stage is in both. if ((*ai)._override == (*bi)._override) { // Same override; compose them. CPT(TransformState) new_transform = (*ai)._transform->compose((*bi)._transform); StageNode sn((*ai)._stage); sn._transform = new_transform; sn._override = (*ai)._override; attrib->_stages.insert(attrib->_stages.end(), sn); } else if ((*ai)._override < (*bi)._override) { // Override b wins. attrib->_stages.insert(attrib->_stages.end(), *bi); } else { // Override a wins. attrib->_stages.insert(attrib->_stages.end(), *ai); } ++ai; ++bi; } } while (ai != _stages.end()) { // This stage is in a but not in b. attrib->_stages.insert(attrib->_stages.end(), *ai); ++ai; } while (bi != ta->_stages.end()) { // This stage is in b but not in a. attrib->_stages.insert(attrib->_stages.end(), *bi); ++bi; } return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::invert_compose_impl // Access: Protected, Virtual // Description: Intended to be overridden by derived RenderAttrib // types to specify how two consecutive RenderAttrib // objects of the same type interact. // // See invert_compose() and compose_impl(). //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: invert_compose_impl(const RenderAttrib *other) const { const TexMatrixAttrib *ta; DCAST_INTO_R(ta, other, 0); // The inverse composition works a lot like the composition, except // we invert the ai stages. TexMatrixAttrib *attrib = new TexMatrixAttrib; Stages::const_iterator ai, bi; ai = _stages.begin(); bi = ta->_stages.begin(); while (ai != _stages.end() && bi != ta->_stages.end()) { if ((*ai)._stage < (*bi)._stage) { // This stage is in a but not in b. CPT(TransformState) inv_a = (*ai)._transform->invert_compose(TransformState::make_identity()); StageNode sn((*ai)._stage); sn._transform = inv_a; sn._override = (*ai)._override; attrib->_stages.insert(attrib->_stages.end(), sn); ++ai; } else if ((*bi)._stage < (*ai)._stage) { // This stage is in b but not in a. attrib->_stages.insert(attrib->_stages.end(), *bi); ++bi; } else { // This stage is in both. if ((*ai)._override == (*bi)._override) { // Same override; compose them. CPT(TransformState) new_transform = (*ai)._transform->invert_compose((*bi)._transform); StageNode sn((*ai)._stage); sn._transform = new_transform; sn._override = (*ai)._override; attrib->_stages.insert(attrib->_stages.end(), sn); } else if ((*ai)._override < (*bi)._override) { // Override b wins. attrib->_stages.insert(attrib->_stages.end(), *bi); } else { // Override a wins. CPT(TransformState) inv_a = (*ai)._transform->invert_compose(TransformState::make_identity()); StageNode sn((*ai)._stage); sn._transform = inv_a; sn._override = (*ai)._override; attrib->_stages.insert(attrib->_stages.end(), sn); } ++ai; ++bi; } } while (ai != _stages.end()) { // This stage is in a but not in b. CPT(TransformState) inv_a = (*ai)._transform->invert_compose(TransformState::make_identity()); StageNode sn((*ai)._stage); sn._transform = inv_a; sn._override = (*ai)._override; attrib->_stages.insert(attrib->_stages.end(), sn); ++ai; } while (bi != ta->_stages.end()) { // This stage is in b but not in a. attrib->_stages.insert(attrib->_stages.end(), *bi); ++bi; } return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_auto_shader_attrib_impl // Access: Protected, Virtual // Description: //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: get_auto_shader_attrib_impl(const RenderState *state) const { // For a TexMatrixAttrib, the particular matrix per TextureStage // isn't important, just whether there is a matrix at all. So we // create a new state with an identity matrix everywhere there is a // matrix at all in the original. TexMatrixAttrib *attrib = new TexMatrixAttrib; Stages::const_iterator ai; for (ai = _stages.begin(); ai != _stages.end(); ++ai) { StageNode sn((*ai)._stage); sn._transform = TransformState::make_identity(); attrib->_stages.insert(attrib->_stages.end(), sn); } return return_new(attrib); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::register_with_read_factory // Access: Public, Static // Description: Tells the BamReader how to create objects of type // TexMatrixAttrib. //////////////////////////////////////////////////////////////////// void TexMatrixAttrib:: register_with_read_factory() { BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::write_datagram // Access: Public, Virtual // Description: Writes the contents of this object to the datagram // for shipping out to a Bam file. //////////////////////////////////////////////////////////////////// void TexMatrixAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); dg.add_uint16(_stages.size()); Stages::const_iterator si; for (si = _stages.begin(); si != _stages.end(); ++si) { const StageNode &sn = (*si); manager->write_pointer(dg, sn._stage); manager->write_pointer(dg, sn._transform); dg.add_int32(sn._override); } } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::complete_pointers // Access: Public, Virtual // Description: Receives an array of pointers, one for each time // manager->read_pointer() was called in fillin(). // Returns the number of pointers processed. //////////////////////////////////////////////////////////////////// int TexMatrixAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); for (size_t sni = 0; sni < _stages.size(); ++sni) { // Filter the TextureStage through the TextureStagePool. PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]); ts = TextureStagePool::get_stage(ts); const TransformState *transform = DCAST(TransformState, p_list[pi++]); StageNode &sn = _stages[sni]; sn._stage = ts; sn._transform = transform; } _stages.sort(); return pi; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::make_from_bam // Access: Protected, Static // Description: This function is called by the BamReader's factory // when a new object of type TexMatrixAttrib is encountered // in the Bam file. It should create the TexMatrixAttrib // and extract its information from the file. //////////////////////////////////////////////////////////////////// TypedWritable *TexMatrixAttrib:: make_from_bam(const FactoryParams ¶ms) { TexMatrixAttrib *attrib = new TexMatrixAttrib; DatagramIterator scan; BamReader *manager; parse_params(params, scan, manager); attrib->fillin(scan, manager); return attrib; } //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::fillin // Access: Protected // Description: This internal function is called by make_from_bam to // read in all of the relevant data from the BamFile for // the new TexMatrixAttrib. //////////////////////////////////////////////////////////////////// void TexMatrixAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); size_t num_stages = scan.get_uint16(); for (size_t i = 0; i < num_stages; i++) { manager->read_pointer(scan); manager->read_pointer(scan); int override = 0; if (manager->get_file_minor_ver() >= 24) { override = scan.get_int32(); } StageNode sn(NULL); sn._override = override; _stages.push_back(sn); } }