Panda3D
|
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, PN_stdfloat 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 from 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::limit_transforms 00099 // Access: Published 00100 // Description: If the total number of transforms in the blend 00101 // exceeds max_transforms, removes the n least-important 00102 // transforms as needed to reduce the number of 00103 // transforms to max_transforms. 00104 //////////////////////////////////////////////////////////////////// 00105 void TransformBlend:: 00106 limit_transforms(int max_transforms) { 00107 if (max_transforms <= 0) { 00108 _entries.clear(); 00109 return; 00110 } 00111 00112 while (_entries.size() > max_transforms) { 00113 // Repeatedly find and remove the least-important transform. 00114 nassertv(!_entries.empty()); 00115 Entries::iterator ei_least = _entries.begin(); 00116 Entries::iterator ei = ei_least; 00117 ++ei; 00118 while (ei != _entries.end()) { 00119 if ((*ei)._weight < (*ei_least)._weight) { 00120 ei_least = ei; 00121 } 00122 ++ei; 00123 } 00124 00125 _entries.erase(ei_least); 00126 } 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: TransformBlend::normalize_weights 00131 // Access: Published 00132 // Description: Rescales all of the weights on the various transforms 00133 // so that they sum to 1.0. It is generally a good idea 00134 // to call this after adding or removing transforms from 00135 // the blend. 00136 //////////////////////////////////////////////////////////////////// 00137 void TransformBlend:: 00138 normalize_weights() { 00139 PN_stdfloat net_weight = 0.0f; 00140 Entries::iterator ei; 00141 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00142 net_weight += (*ei)._weight; 00143 } 00144 if (net_weight != 0.0f) { 00145 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00146 (*ei)._weight /= net_weight; 00147 } 00148 } 00149 Thread *current_thread = Thread::get_current_thread(); 00150 clear_result(current_thread); 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: TransformBlend::has_transform 00155 // Access: Published 00156 // Description: Returns true if the blend has the indicated 00157 // transform, false otherwise. 00158 //////////////////////////////////////////////////////////////////// 00159 bool TransformBlend:: 00160 has_transform(const VertexTransform *transform) const { 00161 TransformEntry entry; 00162 entry._transform = transform; 00163 entry._weight = 0.0f; 00164 Entries::const_iterator ei = _entries.find(entry); 00165 return (ei != _entries.end()); 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: TransformBlend::get_weight 00170 // Access: Published 00171 // Description: Returns the weight associated with the indicated 00172 // transform, or 0 if there is no entry for the 00173 // transform. 00174 //////////////////////////////////////////////////////////////////// 00175 PN_stdfloat TransformBlend:: 00176 get_weight(const VertexTransform *transform) const { 00177 TransformEntry entry; 00178 entry._transform = transform; 00179 entry._weight = 0.0f; 00180 Entries::const_iterator ei = _entries.find(entry); 00181 if (ei != _entries.end()) { 00182 return (*ei)._weight; 00183 } 00184 return 0.0f; 00185 } 00186 00187 //////////////////////////////////////////////////////////////////// 00188 // Function: TransformBlend::output 00189 // Access: Published 00190 // Description: 00191 //////////////////////////////////////////////////////////////////// 00192 void TransformBlend:: 00193 output(ostream &out) const { 00194 if (_entries.empty()) { 00195 out << "empty"; 00196 } else { 00197 Entries::const_iterator ei = _entries.begin(); 00198 out << *(*ei)._transform << ":" << (*ei)._weight; 00199 ++ei; 00200 while (ei != _entries.end()) { 00201 out << " " << *(*ei)._transform << ":" << (*ei)._weight; 00202 ++ei; 00203 } 00204 } 00205 } 00206 00207 //////////////////////////////////////////////////////////////////// 00208 // Function: TransformBlend::write 00209 // Access: Published 00210 // Description: 00211 //////////////////////////////////////////////////////////////////// 00212 void TransformBlend:: 00213 write(ostream &out, int indent_level) const { 00214 Thread *current_thread = Thread::get_current_thread(); 00215 Entries::const_iterator ei; 00216 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00217 indent(out, indent_level) 00218 << *(*ei)._transform << ":" << (*ei)._weight << "\n"; 00219 LMatrix4 mat; 00220 (*ei)._transform->get_matrix(mat); 00221 mat.write(out, indent_level + 4); 00222 } 00223 LMatrix4 blend; 00224 update_blend(current_thread); 00225 get_blend(blend, current_thread); 00226 indent(out, indent_level) 00227 << "Blended result =\n"; 00228 blend.write(out, indent_level + 2); 00229 } 00230 00231 //////////////////////////////////////////////////////////////////// 00232 // Function: TransformBlend::recompute_result 00233 // Access: Private 00234 // Description: Recomputes the blend result from the various 00235 // VertexTransform objects, if necessary. 00236 //////////////////////////////////////////////////////////////////// 00237 void TransformBlend:: 00238 recompute_result(CData *cdata, Thread *current_thread) { 00239 // Update the global_modified sequence number first, to prevent race 00240 // conditions. 00241 cdata->_global_modified = VertexTransform::get_global_modified(current_thread); 00242 00243 // Now see if we really need to recompute. 00244 UpdateSeq seq; 00245 Entries::const_iterator ei; 00246 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00247 seq = max(seq, (*ei)._transform->get_modified(current_thread)); 00248 } 00249 00250 if (cdata->_modified != seq) { 00251 // We do need to recompute. 00252 cdata->_modified = seq; 00253 00254 cdata->_result = LMatrix4::zeros_mat(); 00255 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00256 (*ei)._transform->accumulate_matrix(cdata->_result, (*ei)._weight); 00257 } 00258 } 00259 } 00260 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: TransformBlend::clear_result 00263 // Access: Private 00264 // Description: Removes the computed result to force it to be 00265 // recomputed. 00266 //////////////////////////////////////////////////////////////////// 00267 void TransformBlend:: 00268 clear_result(Thread *current_thread) { 00269 CDWriter cdata(_cycler, true, current_thread); 00270 cdata->_global_modified = UpdateSeq(); 00271 if (cdata->_modified != UpdateSeq()) { 00272 cdata->_modified = UpdateSeq(); 00273 cdata->_result = LMatrix4::ident_mat(); 00274 } 00275 } 00276 00277 //////////////////////////////////////////////////////////////////// 00278 // Function: TransformBlend::write_datagram 00279 // Access: Public 00280 // Description: Writes the contents of this object to the datagram 00281 // for shipping out to a Bam file. 00282 //////////////////////////////////////////////////////////////////// 00283 void TransformBlend:: 00284 write_datagram(BamWriter *manager, Datagram &dg) const { 00285 dg.add_uint16(_entries.size()); 00286 00287 Entries::const_iterator ei; 00288 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00289 manager->write_pointer(dg, (*ei)._transform); 00290 dg.add_stdfloat((*ei)._weight); 00291 } 00292 } 00293 00294 //////////////////////////////////////////////////////////////////// 00295 // Function: TransformBlend::complete_pointers 00296 // Access: Public 00297 // Description: Receives an array of pointers, one for each time 00298 // manager->read_pointer() was called in fillin(). 00299 // Returns the number of pointers processed. 00300 //////////////////////////////////////////////////////////////////// 00301 int TransformBlend:: 00302 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00303 int pi = 0; 00304 00305 Entries::iterator ei; 00306 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00307 (*ei)._transform = DCAST(VertexTransform, p_list[pi++]); 00308 } 00309 00310 // Now that we have actual pointers, we can sort the list of 00311 // entries. 00312 _entries.sort(); 00313 00314 return pi; 00315 } 00316 00317 //////////////////////////////////////////////////////////////////// 00318 // Function: TransformBlend::fillin 00319 // Access: Public 00320 // Description: This internal function is called by make_from_bam to 00321 // read in all of the relevant data from the BamFile for 00322 // the new PandaNode. 00323 //////////////////////////////////////////////////////////////////// 00324 void TransformBlend:: 00325 fillin(DatagramIterator &scan, BamReader *manager) { 00326 size_t num_entries = scan.get_uint16(); 00327 _entries.reserve(num_entries); 00328 for (size_t i = 0; i < num_entries; ++i) { 00329 TransformEntry entry; 00330 manager->read_pointer(scan); 00331 entry._weight = scan.get_stdfloat(); 00332 _entries.push_back(entry); 00333 } 00334 } 00335 00336 //////////////////////////////////////////////////////////////////// 00337 // Function: TransformBlend::CData::make_copy 00338 // Access: Public, Virtual 00339 // Description: 00340 //////////////////////////////////////////////////////////////////// 00341 CycleData *TransformBlend::CData:: 00342 make_copy() const { 00343 return new CData(*this); 00344 }