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, 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 }