00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00024
00025
00026
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
00053
00054
00055
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
00066
00067 Entries::iterator ei = result.first;
00068 (*ei)._weight += weight;
00069 if (IS_NEARLY_ZERO((*ei)._weight)) {
00070
00071 _entries.erase(ei);
00072 }
00073 }
00074 Thread *current_thread = Thread::get_current_thread();
00075 clear_result(current_thread);
00076 }
00077 }
00078
00079
00080
00081
00082
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
00099
00100
00101
00102
00103
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
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
00131
00132
00133
00134
00135
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
00155
00156
00157
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
00170
00171
00172
00173
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
00189
00190
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
00209
00210
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
00233
00234
00235
00236
00237 void TransformBlend::
00238 recompute_result(CData *cdata, Thread *current_thread) {
00239
00240
00241 cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
00242
00243
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
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
00263
00264
00265
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
00279
00280
00281
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
00296
00297
00298
00299
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
00311
00312 _entries.sort();
00313
00314 return pi;
00315 }
00316
00317
00318
00319
00320
00321
00322
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
00338
00339
00340
00341 CycleData *TransformBlend::CData::
00342 make_copy() const {
00343 return new CData(*this);
00344 }