Panda3D

transformBlend.cxx

00001 // Filename: transformBlend.cxx
00002 // Created by:  drose (24Mar05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "transformBlend.h"
00016 #include "indent.h"
00017 #include "bamReader.h"
00018 #include "bamWriter.h"
00019 
00020 TypeHandle TransformBlend::_type_handle;
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: TransformBlend::compare_to
00024 //       Access: Published
00025 //  Description: Defines an arbitrary ordering for TransformBlend
00026 //               objects.
00027 ////////////////////////////////////////////////////////////////////
00028 int TransformBlend::
00029 compare_to(const TransformBlend &other) const {
00030   if (_entries.size() != other._entries.size()) {
00031     return (int)_entries.size() - (int)other._entries.size();
00032   }
00033 
00034   Entries::const_iterator ai, bi;
00035   ai = _entries.begin();
00036   bi = other._entries.begin();
00037   while (ai != _entries.end() && bi != other._entries.end()) {
00038     if ((*ai)._transform != (*bi)._transform) {
00039       return (*ai)._transform < (*bi)._transform ? -1 : 1;
00040     }
00041     if (!IS_NEARLY_EQUAL((*ai)._weight, (*bi)._weight)) {
00042       return (*ai)._weight < (*bi)._weight ? -1 : 1;
00043     }
00044     ++ai;
00045     ++bi;
00046   }
00047 
00048   return 0;
00049 }
00050 
00051 ////////////////////////////////////////////////////////////////////
00052 //     Function: TransformBlend::add_transform
00053 //       Access: Published
00054 //  Description: Adds a new transform to the blend.  If the transform
00055 //               already existed, increases its weight factor.
00056 ////////////////////////////////////////////////////////////////////
00057 void TransformBlend::
00058 add_transform(const VertexTransform *transform, float weight) {
00059   if (!IS_NEARLY_ZERO(weight)) {
00060     TransformEntry entry;
00061     entry._transform = transform;
00062     entry._weight = weight;
00063     pair<Entries::iterator, bool> result = _entries.insert(entry);
00064     if (!result.second) {
00065       // If the new value was not inserted, it was already there;
00066       // increment the existing weight factor.
00067       Entries::iterator ei = result.first;
00068       (*ei)._weight += weight;
00069       if (IS_NEARLY_ZERO((*ei)._weight)) {
00070         // If we have just zeroed out the weight, remove it.
00071         _entries.erase(ei);
00072       }
00073     }
00074     Thread *current_thread = Thread::get_current_thread();
00075     clear_result(current_thread);
00076   }
00077 }
00078 
00079 ////////////////////////////////////////////////////////////////////
00080 //     Function: TransformBlend::remove_transform
00081 //       Access: Published
00082 //  Description: Removes the indicated transform to the blend.
00083 ////////////////////////////////////////////////////////////////////
00084 void TransformBlend::
00085 remove_transform(const VertexTransform *transform) {
00086   TransformEntry entry;
00087   entry._transform = transform;
00088   entry._weight = 0.0f;
00089   Entries::iterator ei = _entries.find(entry);
00090   if (ei != _entries.end()) {
00091     _entries.erase(ei);
00092   }
00093   Thread *current_thread = Thread::get_current_thread();
00094   clear_result(current_thread);
00095 }
00096 
00097 ////////////////////////////////////////////////////////////////////
00098 //     Function: TransformBlend::normalize_weights
00099 //       Access: Published
00100 //  Description: Rescales all of the weights on the various transforms
00101 //               so that they sum to 1.0.  It is generally a good idea
00102 //               to call this after adding or removing transforms from
00103 //               the blend.
00104 ////////////////////////////////////////////////////////////////////
00105 void TransformBlend::
00106 normalize_weights() {
00107   float net_weight = 0.0f;
00108   Entries::iterator ei;
00109   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00110     net_weight += (*ei)._weight;
00111   }
00112   if (net_weight != 0.0f) {
00113     for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00114       (*ei)._weight /= net_weight;
00115     }
00116   }
00117   Thread *current_thread = Thread::get_current_thread();
00118   clear_result(current_thread);
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: TransformBlend::has_transform
00123 //       Access: Published
00124 //  Description: Returns true if the blend has the indicated
00125 //               transform, false otherwise.
00126 ////////////////////////////////////////////////////////////////////
00127 bool TransformBlend::
00128 has_transform(const VertexTransform *transform) const {
00129   TransformEntry entry;
00130   entry._transform = transform;
00131   entry._weight = 0.0f;
00132   Entries::const_iterator ei = _entries.find(entry);
00133   return (ei != _entries.end());
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////
00137 //     Function: TransformBlend::get_weight
00138 //       Access: Published
00139 //  Description: Returns the weight associated with the indicated
00140 //               transform, or 0 if there is no entry for the
00141 //               transform.
00142 ////////////////////////////////////////////////////////////////////
00143 float TransformBlend::
00144 get_weight(const VertexTransform *transform) const {
00145   TransformEntry entry;
00146   entry._transform = transform;
00147   entry._weight = 0.0f;
00148   Entries::const_iterator ei = _entries.find(entry);
00149   if (ei != _entries.end()) {
00150     return (*ei)._weight;
00151   }
00152   return 0.0f;
00153 }
00154 
00155 ////////////////////////////////////////////////////////////////////
00156 //     Function: TransformBlend::output
00157 //       Access: Published
00158 //  Description: 
00159 ////////////////////////////////////////////////////////////////////
00160 void TransformBlend::
00161 output(ostream &out) const {
00162   if (_entries.empty()) {
00163     out << "empty";
00164   } else {
00165     Entries::const_iterator ei = _entries.begin();
00166     out << *(*ei)._transform << ":" << (*ei)._weight;
00167     ++ei;
00168     while (ei != _entries.end()) {
00169       out << " " << *(*ei)._transform << ":" << (*ei)._weight;
00170       ++ei;
00171     }
00172   }
00173 }
00174 
00175 ////////////////////////////////////////////////////////////////////
00176 //     Function: TransformBlend::write
00177 //       Access: Published
00178 //  Description: 
00179 ////////////////////////////////////////////////////////////////////
00180 void TransformBlend::
00181 write(ostream &out, int indent_level) const {
00182   Thread *current_thread = Thread::get_current_thread();
00183   Entries::const_iterator ei;
00184   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00185     indent(out, indent_level)
00186       << *(*ei)._transform << ":" << (*ei)._weight << "\n";
00187     LMatrix4f mat;
00188     (*ei)._transform->get_matrix(mat);
00189     mat.write(out, indent_level + 4);
00190   }
00191   LMatrix4f blend;
00192   update_blend(current_thread);
00193   get_blend(blend, current_thread);
00194   indent(out, indent_level)
00195     << "Blended result =\n";
00196   blend.write(out, indent_level + 2);
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: TransformBlend::recompute_result
00201 //       Access: Private
00202 //  Description: Recomputes the blend result from the various
00203 //               VertexTransform objects, if necessary.
00204 ////////////////////////////////////////////////////////////////////
00205 void TransformBlend::
00206 recompute_result(CData *cdata, Thread *current_thread) {
00207   // Update the global_modified sequence number first, to prevent race
00208   // conditions.
00209   cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
00210 
00211   // Now see if we really need to recompute.
00212   UpdateSeq seq;
00213   Entries::const_iterator ei;
00214   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00215     seq = max(seq, (*ei)._transform->get_modified(current_thread));
00216   }
00217 
00218   if (cdata->_modified != seq) {
00219     // We do need to recompute.
00220     cdata->_modified = seq;
00221 
00222     cdata->_result.set(0.0f, 0.0f, 0.0f, 0.0f,
00223                        0.0f, 0.0f, 0.0f, 0.0f,
00224                        0.0f, 0.0f, 0.0f, 0.0f,
00225                        0.0f, 0.0f, 0.0f, 0.0f);
00226     for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00227       (*ei)._transform->accumulate_matrix(cdata->_result, (*ei)._weight);
00228     }
00229   }    
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: TransformBlend::clear_result
00234 //       Access: Private
00235 //  Description: Removes the computed result to force it to be
00236 //               recomputed.
00237 ////////////////////////////////////////////////////////////////////
00238 void TransformBlend::
00239 clear_result(Thread *current_thread) {
00240   CDWriter cdata(_cycler, true, current_thread);
00241   cdata->_global_modified = UpdateSeq();
00242   if (cdata->_modified != UpdateSeq()) {
00243     cdata->_modified = UpdateSeq();
00244     cdata->_result = LMatrix4f::ident_mat();
00245   }
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: TransformBlend::write_datagram
00250 //       Access: Public
00251 //  Description: Writes the contents of this object to the datagram
00252 //               for shipping out to a Bam file.
00253 ////////////////////////////////////////////////////////////////////
00254 void TransformBlend::
00255 write_datagram(BamWriter *manager, Datagram &dg) const {
00256   dg.add_uint16(_entries.size());
00257 
00258   Entries::const_iterator ei;
00259   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00260     manager->write_pointer(dg, (*ei)._transform);
00261     dg.add_float32((*ei)._weight);
00262   }
00263 }
00264 
00265 ////////////////////////////////////////////////////////////////////
00266 //     Function: TransformBlend::complete_pointers
00267 //       Access: Public
00268 //  Description: Receives an array of pointers, one for each time
00269 //               manager->read_pointer() was called in fillin().
00270 //               Returns the number of pointers processed.
00271 ////////////////////////////////////////////////////////////////////
00272 int TransformBlend::
00273 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00274   int pi = 0;
00275 
00276   Entries::iterator ei;
00277   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00278     (*ei)._transform = DCAST(VertexTransform, p_list[pi++]);
00279   }
00280 
00281   // Now that we have actual pointers, we can sort the list of
00282   // entries.
00283   _entries.sort();
00284 
00285   return pi;
00286 }
00287 
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: TransformBlend::fillin
00290 //       Access: Public
00291 //  Description: This internal function is called by make_from_bam to
00292 //               read in all of the relevant data from the BamFile for
00293 //               the new PandaNode.
00294 ////////////////////////////////////////////////////////////////////
00295 void TransformBlend::
00296 fillin(DatagramIterator &scan, BamReader *manager) {
00297   size_t num_entries = scan.get_uint16();
00298   _entries.reserve(num_entries);
00299   for (size_t i = 0; i < num_entries; ++i) {
00300     TransformEntry entry;
00301     manager->read_pointer(scan);
00302     entry._weight = scan.get_float32();
00303     _entries.push_back(entry);
00304   }
00305 }
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: TransformBlend::CData::make_copy
00309 //       Access: Public, Virtual
00310 //  Description:
00311 ////////////////////////////////////////////////////////////////////
00312 CycleData *TransformBlend::CData::
00313 make_copy() const {
00314   return new CData(*this);
00315 }
 All Classes Functions Variables Enumerations