00001 // Filename: transformBlendTable.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 "transformBlendTable.h" 00016 #include "indent.h" 00017 #include "bamReader.h" 00018 #include "bamWriter.h" 00019 00020 TypeHandle TransformBlendTable::_type_handle; 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: TransformBlendTable::make_cow_copy 00024 // Access: Protected, Virtual 00025 // Description: Required to implement CopyOnWriteObject. 00026 //////////////////////////////////////////////////////////////////// 00027 PT(CopyOnWriteObject) TransformBlendTable:: 00028 make_cow_copy() { 00029 return new TransformBlendTable(*this); 00030 } 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: TransformBlendTable::Constructor 00034 // Access: Published 00035 // Description: 00036 //////////////////////////////////////////////////////////////////// 00037 TransformBlendTable:: 00038 TransformBlendTable() { 00039 } 00040 00041 //////////////////////////////////////////////////////////////////// 00042 // Function: TransformBlendTable::Copy Constructor 00043 // Access: Published 00044 // Description: 00045 //////////////////////////////////////////////////////////////////// 00046 TransformBlendTable:: 00047 TransformBlendTable(const TransformBlendTable ©) : 00048 _blends(copy._blends), 00049 _rows(copy._rows) 00050 { 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: TransformBlendTable::Copy Assignment Operator 00055 // Access: Published 00056 // Description: 00057 //////////////////////////////////////////////////////////////////// 00058 void TransformBlendTable:: 00059 operator = (const TransformBlendTable ©) { 00060 _blends = copy._blends; 00061 _rows = copy._rows; 00062 clear_index(); 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: TransformBlendTable::Destructor 00067 // Access: Published, Virtual 00068 // Description: 00069 //////////////////////////////////////////////////////////////////// 00070 TransformBlendTable:: 00071 ~TransformBlendTable() { 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: TransformBlendTable::set_blend 00076 // Access: Published 00077 // Description: Replaces the blend at the nth position with the 00078 // indicated value. 00079 //////////////////////////////////////////////////////////////////// 00080 void TransformBlendTable:: 00081 set_blend(int n, const TransformBlend &blend) { 00082 nassertv(n >= 0 && n < (int)_blends.size()); 00083 _blends[n] = blend; 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: TransformBlendTable::remove_blend 00088 // Access: Published 00089 // Description: Removes the blend at the nth position. 00090 //////////////////////////////////////////////////////////////////// 00091 void TransformBlendTable:: 00092 remove_blend(int n) { 00093 nassertv(n >= 0 && n < (int)_blends.size()); 00094 _blends.erase(_blends.begin() + n); 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: TransformBlendTable::add_blend 00099 // Access: Published 00100 // Description: Adds a new blend to the table, and returns its 00101 // index number. If there is already an identical blend 00102 // in the table, simply returns that number instead. 00103 //////////////////////////////////////////////////////////////////// 00104 int TransformBlendTable:: 00105 add_blend(const TransformBlend &blend) { 00106 consider_rebuild_index(); 00107 00108 BlendIndex::iterator bi; 00109 bi = _blend_index.find(&blend); 00110 if (bi != _blend_index.end()) { 00111 // Already had it. 00112 return (*bi).second; 00113 } 00114 00115 bool needs_realloc = (_blends.size() >= _blends.capacity()); 00116 int new_position = (int)_blends.size(); 00117 _blends.push_back(blend); 00118 00119 if (needs_realloc) { 00120 // We just reallocated the blends vector, so we must rebuild the 00121 // index. 00122 clear_index(); 00123 00124 } else { 00125 // Since we didn't realloc the blends vector, just update it with 00126 // the latest. 00127 const TransformBlend &added_blend = _blends[new_position]; 00128 _blend_index[&added_blend] = new_position; 00129 _max_simultaneous_transforms = max(_max_simultaneous_transforms, 00130 blend.get_num_transforms()); 00131 00132 // We can't compute this one as we go, so set it to a special 00133 // value to indicate it needs to be recomputed. 00134 _num_transforms = -1; 00135 } 00136 00137 return new_position; 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: TransformBlendTable::write 00142 // Access: Published 00143 // Description: 00144 //////////////////////////////////////////////////////////////////// 00145 void TransformBlendTable:: 00146 write(ostream &out, int indent_level) const { 00147 for (int i = 0; i < (int)_blends.size(); i++) { 00148 indent(out, indent_level) 00149 << i << ". " << _blends[i] << "\n"; 00150 } 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: TransformBlendTable::clear_index 00155 // Access: Private 00156 // Description: Resets the index so that it will be rebuilt next time 00157 // it is needed. 00158 //////////////////////////////////////////////////////////////////// 00159 void TransformBlendTable:: 00160 clear_index() { 00161 _blend_index.clear(); 00162 } 00163 00164 //////////////////////////////////////////////////////////////////// 00165 // Function: TransformBlendTable::rebuild_index 00166 // Access: Private 00167 // Description: Rebuilds the index so that we can easily determine 00168 // what blend combinations are already present in the 00169 // table. 00170 //////////////////////////////////////////////////////////////////// 00171 void TransformBlendTable:: 00172 rebuild_index() { 00173 _blend_index.clear(); 00174 00175 // We'll also count up these two statistics while we rebuild the 00176 // index. 00177 _num_transforms = 0; 00178 _max_simultaneous_transforms = 0; 00179 00180 pset<const VertexTransform *> transforms; 00181 00182 for (int i = 0; i < (int)_blends.size(); ++i) { 00183 const TransformBlend &blend = _blends[i]; 00184 _blend_index[&blend] = i; 00185 00186 for (int ti = 0; ti < blend.get_num_transforms(); ++ti) { 00187 transforms.insert(blend.get_transform(ti)); 00188 } 00189 _max_simultaneous_transforms = max(_max_simultaneous_transforms, 00190 blend.get_num_transforms()); 00191 } 00192 00193 _num_transforms = transforms.size(); 00194 } 00195 00196 //////////////////////////////////////////////////////////////////// 00197 // Function: TransformBlendTable::recompute_modified 00198 // Access: Private 00199 // Description: Recomputes the modified stamp from the various 00200 // TransformBlend objects, if necessary. 00201 //////////////////////////////////////////////////////////////////// 00202 void TransformBlendTable:: 00203 recompute_modified(TransformBlendTable::CData *cdata, Thread *current_thread) { 00204 // Update the global_modified sequence number first, to prevent race 00205 // conditions. 00206 cdata->_global_modified = VertexTransform::get_global_modified(current_thread); 00207 00208 // Now get the local modified number. 00209 UpdateSeq seq; 00210 Blends::const_iterator bi; 00211 for (bi = _blends.begin(); bi != _blends.end(); ++bi) { 00212 seq = max(seq, (*bi).get_modified(current_thread)); 00213 } 00214 00215 cdata->_modified = seq; 00216 } 00217 00218 //////////////////////////////////////////////////////////////////// 00219 // Function: TransformBlendTable::clear_modified 00220 // Access: Private 00221 // Description: Clears the modified stamp to force it to be 00222 // recomputed. 00223 //////////////////////////////////////////////////////////////////// 00224 void TransformBlendTable:: 00225 clear_modified(Thread *current_thread) { 00226 CDWriter cdata(_cycler, true, current_thread); 00227 cdata->_global_modified = UpdateSeq(); 00228 cdata->_modified = UpdateSeq(); 00229 } 00230 00231 //////////////////////////////////////////////////////////////////// 00232 // Function: TransformBlendTable::register_with_read_factory 00233 // Access: Public, Static 00234 // Description: Tells the BamReader how to create objects of type 00235 // TransformBlendTable. 00236 //////////////////////////////////////////////////////////////////// 00237 void TransformBlendTable:: 00238 register_with_read_factory() { 00239 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00240 } 00241 00242 //////////////////////////////////////////////////////////////////// 00243 // Function: TransformBlendTable::write_datagram 00244 // Access: Public, Virtual 00245 // Description: Writes the contents of this object to the datagram 00246 // for shipping out to a Bam file. 00247 //////////////////////////////////////////////////////////////////// 00248 void TransformBlendTable:: 00249 write_datagram(BamWriter *manager, Datagram &dg) { 00250 TypedWritable::write_datagram(manager, dg); 00251 00252 dg.add_uint16(_blends.size()); 00253 Blends::const_iterator bi; 00254 for (bi = _blends.begin(); bi != _blends.end(); ++bi) { 00255 (*bi).write_datagram(manager, dg); 00256 } 00257 00258 _rows.write_datagram(manager, dg); 00259 00260 manager->write_cdata(dg, _cycler); 00261 } 00262 00263 //////////////////////////////////////////////////////////////////// 00264 // Function: TransformBlendTable::complete_pointers 00265 // Access: Public, Virtual 00266 // Description: Receives an array of pointers, one for each time 00267 // manager->read_pointer() was called in fillin(). 00268 // Returns the number of pointers processed. 00269 //////////////////////////////////////////////////////////////////// 00270 int TransformBlendTable:: 00271 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00272 int pi = TypedWritable::complete_pointers(p_list, manager); 00273 00274 Blends::iterator bi; 00275 for (bi = _blends.begin(); bi != _blends.end(); ++bi) { 00276 pi += (*bi).complete_pointers(p_list + pi, manager); 00277 } 00278 00279 return pi; 00280 } 00281 00282 //////////////////////////////////////////////////////////////////// 00283 // Function: TransformBlendTable::make_from_bam 00284 // Access: Protected, Static 00285 // Description: This function is called by the BamReader's factory 00286 // when a new object of type TransformBlendTable is encountered 00287 // in the Bam file. It should create the TransformBlendTable 00288 // and extract its information from the file. 00289 //////////////////////////////////////////////////////////////////// 00290 TypedWritable *TransformBlendTable:: 00291 make_from_bam(const FactoryParams ¶ms) { 00292 TransformBlendTable *object = new TransformBlendTable; 00293 DatagramIterator scan; 00294 BamReader *manager; 00295 00296 parse_params(params, scan, manager); 00297 object->fillin(scan, manager); 00298 00299 return object; 00300 } 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: TransformBlendTable::fillin 00304 // Access: Protected 00305 // Description: This internal function is called by make_from_bam to 00306 // read in all of the relevant data from the BamFile for 00307 // the new TransformBlendTable. 00308 //////////////////////////////////////////////////////////////////// 00309 void TransformBlendTable:: 00310 fillin(DatagramIterator &scan, BamReader *manager) { 00311 TypedWritable::fillin(scan, manager); 00312 00313 size_t num_blends = scan.get_uint16(); 00314 _blends.reserve(num_blends); 00315 size_t i; 00316 for (i = 0; i < num_blends; ++i) { 00317 TransformBlend blend; 00318 blend.fillin(scan, manager); 00319 _blends.push_back(blend); 00320 } 00321 00322 if (manager->get_file_minor_ver() >= 7) { 00323 _rows.read_datagram(scan, manager); 00324 } else { 00325 // In this case, for bam files prior to 6.7, we must define the 00326 // SparseArray with the full number of vertices. This is done 00327 // in GeomVertexData::complete_pointers(). 00328 } 00329 00330 manager->read_cdata(scan, _cycler); 00331 } 00332 00333 //////////////////////////////////////////////////////////////////// 00334 // Function: TransformBlendTable::CData::make_copy 00335 // Access: Public, Virtual 00336 // Description: 00337 //////////////////////////////////////////////////////////////////// 00338 CycleData *TransformBlendTable::CData:: 00339 make_copy() const { 00340 return new CData(*this); 00341 } 00342 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: TransformBlendTable::CData::write_datagram 00345 // Access: Public, Virtual 00346 // Description: Writes the contents of this object to the datagram 00347 // for shipping out to a Bam file. 00348 //////////////////////////////////////////////////////////////////// 00349 void TransformBlendTable::CData:: 00350 write_datagram(BamWriter *manager, Datagram &dg) const { 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: TransformBlendTable::CData::fillin 00355 // Access: Public, Virtual 00356 // Description: This internal function is called by make_from_bam to 00357 // read in all of the relevant data from the BamFile for 00358 // the new TransformBlendTable. 00359 //////////////////////////////////////////////////////////////////// 00360 void TransformBlendTable::CData:: 00361 fillin(DatagramIterator &scan, BamReader *manager) { 00362 Thread *current_thread = Thread::get_current_thread(); 00363 _modified = VertexTransform::get_next_modified(current_thread); 00364 _global_modified = VertexTransform::get_global_modified(current_thread); 00365 }