Panda3D
|
00001 // Filename: geomVertexData.cxx 00002 // Created by: drose (06Mar05) 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 "geomVertexData.h" 00016 #include "geom.h" 00017 #include "geomVertexReader.h" 00018 #include "geomVertexWriter.h" 00019 #include "geomVertexRewriter.h" 00020 #include "pStatTimer.h" 00021 #include "bamReader.h" 00022 #include "bamWriter.h" 00023 #include "pset.h" 00024 #include "indent.h" 00025 00026 TypeHandle GeomVertexData::_type_handle; 00027 TypeHandle GeomVertexData::CDataCache::_type_handle; 00028 TypeHandle GeomVertexData::CacheEntry::_type_handle; 00029 TypeHandle GeomVertexData::CData::_type_handle; 00030 TypeHandle GeomVertexDataPipelineReader::_type_handle; 00031 TypeHandle GeomVertexDataPipelineWriter::_type_handle; 00032 00033 PStatCollector GeomVertexData::_convert_pcollector("*:Munge:Convert"); 00034 PStatCollector GeomVertexData::_scale_color_pcollector("*:Munge:Scale color"); 00035 PStatCollector GeomVertexData::_set_color_pcollector("*:Munge:Set color"); 00036 PStatCollector GeomVertexData::_animation_pcollector("*:Animation"); 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: GeomVertexData::Default Constructor 00040 // Access: Private 00041 // Description: Constructs an invalid object. This is only used when 00042 // reading from the bam file. 00043 //////////////////////////////////////////////////////////////////// 00044 GeomVertexData:: 00045 GeomVertexData() : 00046 _char_pcollector(_animation_pcollector, "unnamed"), 00047 _skinning_pcollector(_char_pcollector, "Skinning"), 00048 _morphs_pcollector(_char_pcollector, "Morphs") 00049 { 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: GeomVertexData::make_cow_copy 00054 // Access: Protected, Virtual 00055 // Description: Required to implement CopyOnWriteObject. 00056 //////////////////////////////////////////////////////////////////// 00057 PT(CopyOnWriteObject) GeomVertexData:: 00058 make_cow_copy() { 00059 return new GeomVertexData(*this); 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: GeomVertexData::Constructor 00064 // Access: Published 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 GeomVertexData:: 00068 GeomVertexData(const string &name, 00069 const GeomVertexFormat *format, 00070 GeomVertexData::UsageHint usage_hint) : 00071 _name(name), 00072 _char_pcollector(PStatCollector(_animation_pcollector, name)), 00073 _skinning_pcollector(_char_pcollector, "Skinning"), 00074 _morphs_pcollector(_char_pcollector, "Morphs") 00075 { 00076 nassertv(format->is_registered()); 00077 00078 // Create some empty arrays as required by the format. 00079 // Let's ensure the vertex data gets set on all stages at once. 00080 OPEN_ITERATE_ALL_STAGES(_cycler) { 00081 CDStageWriter cdata(_cycler, pipeline_stage); 00082 cdata->_format = format; 00083 cdata->_usage_hint = usage_hint; 00084 int num_arrays = format->get_num_arrays(); 00085 for (int i = 0; i < num_arrays; i++) { 00086 PT(GeomVertexArrayData) array = new GeomVertexArrayData 00087 (format->get_array(i), usage_hint); 00088 cdata->_arrays.push_back(array.p()); 00089 } 00090 } 00091 CLOSE_ITERATE_ALL_STAGES(_cycler); 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: GeomVertexData::Copy Constructor 00096 // Access: Published 00097 // Description: 00098 //////////////////////////////////////////////////////////////////// 00099 GeomVertexData:: 00100 GeomVertexData(const GeomVertexData ©) : 00101 CopyOnWriteObject(copy), 00102 _name(copy._name), 00103 _cycler(copy._cycler), 00104 _char_pcollector(copy._char_pcollector), 00105 _skinning_pcollector(copy._skinning_pcollector), 00106 _morphs_pcollector(copy._morphs_pcollector) 00107 { 00108 OPEN_ITERATE_ALL_STAGES(_cycler) { 00109 CDStageWriter cdata(_cycler, pipeline_stage); 00110 // It's important that we *not* copy the animated_vertices pointer. 00111 cdata->_animated_vertices = NULL; 00112 cdata->_animated_vertices_modified = UpdateSeq(); 00113 } 00114 CLOSE_ITERATE_ALL_STAGES(_cycler); 00115 } 00116 00117 //////////////////////////////////////////////////////////////////// 00118 // Function: GeomVertexData::Constructor 00119 // Access: Published 00120 // Description: This constructor copies all of the basic properties 00121 // of the source VertexData, like usage_hint and 00122 // animation tables, but does not copy the actual data, 00123 // and it allows you to specify a different format. 00124 //////////////////////////////////////////////////////////////////// 00125 GeomVertexData:: 00126 GeomVertexData(const GeomVertexData ©, 00127 const GeomVertexFormat *format) : 00128 CopyOnWriteObject(copy), 00129 _name(copy._name), 00130 _cycler(copy._cycler), 00131 _char_pcollector(copy._char_pcollector), 00132 _skinning_pcollector(copy._skinning_pcollector), 00133 _morphs_pcollector(copy._morphs_pcollector) 00134 { 00135 nassertv(format->is_registered()); 00136 00137 // Create some empty arrays as required by the format. 00138 OPEN_ITERATE_ALL_STAGES(_cycler) { 00139 CDStageWriter cdata(_cycler, pipeline_stage); 00140 00141 UsageHint usage_hint = cdata->_usage_hint; 00142 cdata->_arrays.clear(); 00143 cdata->_format = format; 00144 int num_arrays = format->get_num_arrays(); 00145 for (int i = 0; i < num_arrays; i++) { 00146 PT(GeomVertexArrayData) array = new GeomVertexArrayData 00147 (format->get_array(i), usage_hint); 00148 cdata->_arrays.push_back(array.p()); 00149 } 00150 00151 // It's important that we *not* copy the animated_vertices pointer. 00152 cdata->_animated_vertices = NULL; 00153 cdata->_animated_vertices_modified = UpdateSeq(); 00154 } 00155 CLOSE_ITERATE_ALL_STAGES(_cycler); 00156 } 00157 00158 //////////////////////////////////////////////////////////////////// 00159 // Function: GeomVertexData::Copy Assignment Operator 00160 // Access: Published 00161 // Description: The copy assignment operator is not pipeline-safe. 00162 // This will completely obliterate all stages of the 00163 // pipeline, so don't do it for a GeomVertexData that is 00164 // actively being used for rendering. 00165 //////////////////////////////////////////////////////////////////// 00166 void GeomVertexData:: 00167 operator = (const GeomVertexData ©) { 00168 CopyOnWriteObject::operator = (copy); 00169 00170 clear_cache(); 00171 00172 _name = copy._name; 00173 _cycler = copy._cycler; 00174 _char_pcollector = copy._char_pcollector; 00175 _skinning_pcollector = copy._skinning_pcollector; 00176 _morphs_pcollector = copy._morphs_pcollector; 00177 00178 OPEN_ITERATE_ALL_STAGES(_cycler) { 00179 CDStageWriter cdata(_cycler, pipeline_stage); 00180 cdata->_modified = Geom::get_next_modified(); 00181 cdata->_animated_vertices = NULL; 00182 cdata->_animated_vertices_modified = UpdateSeq(); 00183 } 00184 CLOSE_ITERATE_ALL_STAGES(_cycler); 00185 } 00186 00187 //////////////////////////////////////////////////////////////////// 00188 // Function: GeomVertexData::Destructor 00189 // Access: Published, Virtual 00190 // Description: 00191 //////////////////////////////////////////////////////////////////// 00192 GeomVertexData:: 00193 ~GeomVertexData() { 00194 clear_cache(); 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: GeomVertexData::compare_to 00199 // Access: Published 00200 // Description: Returns 0 if the two objects are equivalent, even if 00201 // they are not the same pointer. 00202 //////////////////////////////////////////////////////////////////// 00203 int GeomVertexData:: 00204 compare_to(const GeomVertexData &other) const { 00205 CDReader cdata(_cycler); 00206 CDReader other_cdata(other._cycler); 00207 00208 if (cdata->_usage_hint != other_cdata->_usage_hint) { 00209 return (int)cdata->_usage_hint - (int)other_cdata->_usage_hint; 00210 } 00211 if (cdata->_format != other_cdata->_format) { 00212 return cdata->_format < other_cdata->_format ? -1 : 1; 00213 } 00214 if (cdata->_transform_table != other_cdata->_transform_table) { 00215 return cdata->_transform_table < other_cdata->_transform_table ? -1 : 1; 00216 } 00217 if (cdata->_transform_blend_table != other_cdata->_transform_blend_table) { 00218 return cdata->_transform_blend_table < other_cdata->_transform_blend_table ? -1 : 1; 00219 } 00220 if (cdata->_slider_table != other_cdata->_slider_table) { 00221 return cdata->_slider_table < other_cdata->_slider_table ? -1 : 1; 00222 } 00223 if (cdata->_arrays.size() != other_cdata->_arrays.size()) { 00224 return (int)cdata->_arrays.size() - (int)other_cdata->_arrays.size(); 00225 } 00226 for (size_t i = 0; i < cdata->_arrays.size(); ++i) { 00227 if (cdata->_arrays[i] != other_cdata->_arrays[i]) { 00228 return cdata->_arrays[i] < other_cdata->_arrays[i] ? -1 : 1; 00229 } 00230 } 00231 00232 return 0; 00233 } 00234 00235 //////////////////////////////////////////////////////////////////// 00236 // Function: GeomVertexData::set_name 00237 // Access: Published 00238 // Description: Changes the name of the vertex data. This name is 00239 // reported on the PStats graph for vertex computations. 00240 //////////////////////////////////////////////////////////////////// 00241 void GeomVertexData:: 00242 set_name(const string &name) { 00243 _name = name; 00244 _char_pcollector = PStatCollector(_animation_pcollector, name); 00245 _skinning_pcollector = PStatCollector(_char_pcollector, "Skinning"); 00246 _morphs_pcollector = PStatCollector(_char_pcollector, "Morphs"); 00247 } 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: GeomVertexData::set_usage_hint 00251 // Access: Published 00252 // Description: Changes the UsageHint hint for this vertex data, and 00253 // for all of the arrays that share this data. See 00254 // get_usage_hint(). 00255 // 00256 // Don't call this in a downstream thread unless you 00257 // don't mind it blowing away other changes you might 00258 // have recently made in an upstream thread. 00259 //////////////////////////////////////////////////////////////////// 00260 void GeomVertexData:: 00261 set_usage_hint(GeomVertexData::UsageHint usage_hint) { 00262 CDWriter cdata(_cycler, true); 00263 cdata->_usage_hint = usage_hint; 00264 00265 Arrays::iterator ai; 00266 for (ai = cdata->_arrays.begin(); 00267 ai != cdata->_arrays.end(); 00268 ++ai) { 00269 PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); 00270 array_obj->set_usage_hint(usage_hint); 00271 } 00272 clear_cache_stage(); 00273 cdata->_modified = Geom::get_next_modified(); 00274 cdata->_animated_vertices_modified = UpdateSeq(); 00275 } 00276 00277 //////////////////////////////////////////////////////////////////// 00278 // Function: GeomVertexData::set_format 00279 // Access: Published 00280 // Description: Changes the format of the vertex data. If the data 00281 // is not empty, this will implicitly change every row 00282 // to match the new format. 00283 // 00284 // Don't call this in a downstream thread unless you 00285 // don't mind it blowing away other changes you might 00286 // have recently made in an upstream thread. 00287 //////////////////////////////////////////////////////////////////// 00288 void GeomVertexData:: 00289 set_format(const GeomVertexFormat *format) { 00290 Thread *current_thread = Thread::get_current_thread(); 00291 nassertv(format->is_registered()); 00292 00293 CDLockedReader cdata(_cycler, current_thread); 00294 00295 if (format == cdata->_format) { 00296 // Trivially no-op. 00297 return; 00298 } 00299 00300 CDWriter cdataw(_cycler, cdata, true); 00301 00302 // Put the current data aside, so we can copy it back in below. 00303 CPT(GeomVertexData) orig_data = new GeomVertexData(*this); 00304 00305 // Assign the new format. This means clearing out all of our 00306 // current arrays and replacing them with new, empty arrays. 00307 cdataw->_format = format; 00308 00309 UsageHint usage_hint = cdataw->_usage_hint; 00310 cdataw->_arrays.clear(); 00311 int num_arrays = cdataw->_format->get_num_arrays(); 00312 for (int i = 0; i < num_arrays; i++) { 00313 PT(GeomVertexArrayData) array = new GeomVertexArrayData 00314 (cdataw->_format->get_array(i), usage_hint); 00315 cdataw->_arrays.push_back(array.p()); 00316 } 00317 00318 // Now copy the original data back in. This will automatically 00319 // convert it to the new format. 00320 copy_from(orig_data, false, current_thread); 00321 00322 clear_cache_stage(); 00323 cdataw->_modified = Geom::get_next_modified(); 00324 cdataw->_animated_vertices.clear(); 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: GeomVertexData::clear_rows 00329 // Access: Published 00330 // Description: Removes all of the rows from the arrays; 00331 // functionally equivalent to set_num_rows(0) (but 00332 // faster). 00333 // 00334 // Don't call this in a downstream thread unless you 00335 // don't mind it blowing away other changes you might 00336 // have recently made in an upstream thread. 00337 //////////////////////////////////////////////////////////////////// 00338 void GeomVertexData:: 00339 clear_rows() { 00340 Thread *current_thread = Thread::get_current_thread(); 00341 CDWriter cdata(_cycler, true, current_thread); 00342 nassertv(cdata->_format->get_num_arrays() == (int)cdata->_arrays.size()); 00343 00344 Arrays::iterator ai; 00345 for (ai = cdata->_arrays.begin(); 00346 ai != cdata->_arrays.end(); 00347 ++ai) { 00348 PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); 00349 array_obj->clear_rows(); 00350 } 00351 clear_cache_stage(); 00352 cdata->_modified = Geom::get_next_modified(); 00353 cdata->_animated_vertices.clear(); 00354 } 00355 00356 //////////////////////////////////////////////////////////////////// 00357 // Function: GeomVertexData::set_transform_table 00358 // Access: Published 00359 // Description: Replaces the TransformTable on this vertex 00360 // data with the indicated table. The length of this 00361 // table should be consistent with the maximum table 00362 // index assigned to the vertices under the 00363 // "transform_index" name. 00364 // 00365 // Don't call this in a downstream thread unless you 00366 // don't mind it blowing away other changes you might 00367 // have recently made in an upstream thread. 00368 //////////////////////////////////////////////////////////////////// 00369 void GeomVertexData:: 00370 set_transform_table(const TransformTable *table) { 00371 Thread *current_thread = Thread::get_current_thread(); 00372 nassertv(table == (TransformTable *)NULL || table->is_registered()); 00373 00374 CDWriter cdata(_cycler, true, current_thread); 00375 cdata->_transform_table = (TransformTable *)table; 00376 clear_cache_stage(); 00377 cdata->_modified = Geom::get_next_modified(); 00378 cdata->_animated_vertices_modified = UpdateSeq(); 00379 } 00380 00381 //////////////////////////////////////////////////////////////////// 00382 // Function: GeomVertexData::modify_transform_blend_table 00383 // Access: Published 00384 // Description: Returns a modifiable pointer to the current 00385 // TransformBlendTable on this vertex data, if any, or 00386 // NULL if there is not a TransformBlendTable. See 00387 // get_transform_blend_table(). 00388 // 00389 // Don't call this in a downstream thread unless you 00390 // don't mind it blowing away other changes you might 00391 // have recently made in an upstream thread. 00392 //////////////////////////////////////////////////////////////////// 00393 PT(TransformBlendTable) GeomVertexData:: 00394 modify_transform_blend_table() { 00395 CDWriter cdata(_cycler, true); 00396 00397 clear_cache_stage(); 00398 cdata->_modified = Geom::get_next_modified(); 00399 cdata->_animated_vertices_modified = UpdateSeq(); 00400 00401 return cdata->_transform_blend_table.get_write_pointer(); 00402 } 00403 00404 //////////////////////////////////////////////////////////////////// 00405 // Function: GeomVertexData::set_transform_blend_table 00406 // Access: Published 00407 // Description: Replaces the TransformBlendTable on this vertex 00408 // data with the indicated table. The length of this 00409 // table should be consistent with the maximum table 00410 // index assigned to the vertices under the 00411 // "transform_blend" name. 00412 // 00413 // Don't call this in a downstream thread unless you 00414 // don't mind it blowing away other changes you might 00415 // have recently made in an upstream thread. 00416 //////////////////////////////////////////////////////////////////// 00417 void GeomVertexData:: 00418 set_transform_blend_table(const TransformBlendTable *table) { 00419 CDWriter cdata(_cycler, true); 00420 cdata->_transform_blend_table = (TransformBlendTable *)table; 00421 clear_cache_stage(); 00422 cdata->_modified = Geom::get_next_modified(); 00423 cdata->_animated_vertices_modified = UpdateSeq(); 00424 } 00425 00426 //////////////////////////////////////////////////////////////////// 00427 // Function: GeomVertexData::set_slider_table 00428 // Access: Published 00429 // Description: Replaces the SliderTable on this vertex 00430 // data with the indicated table. There should be an 00431 // entry in this table for each kind of morph offset 00432 // defined in the vertex data. 00433 // 00434 // The SliderTable object must have been registered 00435 // prior to setting it on the GeomVertexData. 00436 // 00437 // Don't call this in a downstream thread unless you 00438 // don't mind it blowing away other changes you might 00439 // have recently made in an upstream thread. 00440 //////////////////////////////////////////////////////////////////// 00441 void GeomVertexData:: 00442 set_slider_table(const SliderTable *table) { 00443 nassertv(table == (SliderTable *)NULL || table->is_registered()); 00444 00445 CDWriter cdata(_cycler, true); 00446 cdata->_slider_table = (SliderTable *)table; 00447 clear_cache_stage(); 00448 cdata->_modified = Geom::get_next_modified(); 00449 cdata->_animated_vertices_modified = UpdateSeq(); 00450 } 00451 00452 //////////////////////////////////////////////////////////////////// 00453 // Function: GeomVertexData::request_resident 00454 // Access: Published 00455 // Description: Returns true if the vertex data is currently resident 00456 // in memory. If this returns false, the vertex data will 00457 // be brought back into memory shortly; try again later. 00458 //////////////////////////////////////////////////////////////////// 00459 bool GeomVertexData:: 00460 request_resident() const { 00461 CDReader cdata(_cycler); 00462 00463 bool resident = true; 00464 00465 Arrays::const_iterator ai; 00466 for (ai = cdata->_arrays.begin(); 00467 ai != cdata->_arrays.end(); 00468 ++ai) { 00469 if (!(*ai).get_read_pointer()->request_resident()) { 00470 resident = false; 00471 } 00472 } 00473 00474 return resident; 00475 } 00476 00477 //////////////////////////////////////////////////////////////////// 00478 // Function: GeomVertexData::copy_from 00479 // Access: Published 00480 // Description: Copies all the data from the other array into the 00481 // corresponding data types in this array, by matching 00482 // data types name-by-name. 00483 // 00484 // keep_data_objects specifies what to do when one or 00485 // more of the arrays can be copied without the need to 00486 // apply any conversion operation. If it is true, the 00487 // original GeomVertexArrayData objects in this object 00488 // are retained, and their data arrays are copied 00489 // byte-by-byte from the source; if it is false, then the 00490 // GeomVertexArrayData objects are copied pointerwise 00491 // from the source. 00492 // 00493 // Don't call this in a downstream thread unless you 00494 // don't mind it blowing away other changes you might 00495 // have recently made in an upstream thread. 00496 //////////////////////////////////////////////////////////////////// 00497 void GeomVertexData:: 00498 copy_from(const GeomVertexData *source, bool keep_data_objects, 00499 Thread *current_thread) { 00500 const GeomVertexFormat *source_format = source->get_format(); 00501 const GeomVertexFormat *dest_format = get_format(); 00502 00503 int num_rows = source->get_num_rows(); 00504 int num_arrays = source_format->get_num_arrays(); 00505 int source_i; 00506 00507 // First, check to see if any arrays can be simply appropriated for 00508 // the new format, without changing the data. 00509 pset<int> done_arrays; 00510 00511 for (source_i = 0; source_i < num_arrays; ++source_i) { 00512 const GeomVertexArrayFormat *source_array_format = 00513 source_format->get_array(source_i); 00514 00515 bool array_done = false; 00516 00517 int dest_num_arrays = dest_format->get_num_arrays(); 00518 for (int dest_i = 0; 00519 dest_i < dest_num_arrays && !array_done; 00520 ++dest_i) { 00521 const GeomVertexArrayFormat *dest_array_format = 00522 dest_format->get_array(dest_i); 00523 if (dest_array_format->is_data_subset_of(*source_array_format)) { 00524 // Great! Just use the same data for this one. 00525 if (keep_data_objects) { 00526 // Copy the data, but keep the same GeomVertexArrayData object. 00527 00528 PT(GeomVertexArrayData) dest_data = modify_array(dest_i); 00529 CPT(GeomVertexArrayData) source_data = source->get_array(source_i); 00530 dest_data->modify_handle()->copy_data_from(source_data->get_handle()); 00531 } else { 00532 // Copy the GeomVertexArrayData object. 00533 if (get_array(dest_i) != source->get_array(source_i)) { 00534 set_array(dest_i, source->get_array(source_i)); 00535 } 00536 } 00537 00538 array_done = true; 00539 done_arrays.insert(dest_i); 00540 } 00541 } 00542 } 00543 00544 // Now make sure the arrays we didn't share are all filled in. 00545 set_num_rows(num_rows); 00546 00547 // Now go back through and copy any data that's left over. 00548 for (source_i = 0; source_i < num_arrays; ++source_i) { 00549 CPT(GeomVertexArrayData) array_obj = source->get_array(source_i); 00550 CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle(); 00551 const unsigned char *array_data = array_handle->get_read_pointer(true); 00552 const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i); 00553 int num_columns = source_array_format->get_num_columns(); 00554 for (int di = 0; di < num_columns; ++di) { 00555 const GeomVertexColumn *source_column = source_array_format->get_column(di); 00556 00557 int dest_i = dest_format->get_array_with(source_column->get_name()); 00558 if (dest_i >= 0 && done_arrays.count(dest_i) == 0) { 00559 // The data type exists in the new format; we have to copy it. 00560 const GeomVertexArrayFormat *dest_array_format = 00561 dest_format->get_array(dest_i); 00562 const GeomVertexColumn *dest_column = 00563 dest_array_format->get_column(source_column->get_name()); 00564 nassertv(dest_column != (const GeomVertexColumn *)NULL); 00565 00566 if (dest_column->is_bytewise_equivalent(*source_column)) { 00567 // We can do a quick bytewise copy. 00568 PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); 00569 PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); 00570 unsigned char *dest_array_data = dest_handle->get_write_pointer(); 00571 00572 bytewise_copy(dest_array_data + dest_column->get_start(), 00573 dest_array_format->get_stride(), 00574 array_data + source_column->get_start(), source_array_format->get_stride(), 00575 source_column, num_rows); 00576 00577 } else if (dest_column->is_packed_argb() && 00578 source_column->is_uint8_rgba()) { 00579 // A common special case: OpenGL color to DirectX color. 00580 PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); 00581 PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); 00582 unsigned char *dest_array_data = dest_handle->get_write_pointer(); 00583 00584 uint8_rgba_to_packed_argb 00585 (dest_array_data + dest_column->get_start(), 00586 dest_array_format->get_stride(), 00587 array_data + source_column->get_start(), source_array_format->get_stride(), 00588 num_rows); 00589 00590 } else if (dest_column->is_uint8_rgba() && 00591 source_column->is_packed_argb()) { 00592 // Another common special case: DirectX color to OpenGL 00593 // color. 00594 PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); 00595 PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); 00596 unsigned char *dest_array_data = dest_handle->get_write_pointer(); 00597 00598 packed_argb_to_uint8_rgba 00599 (dest_array_data + dest_column->get_start(), 00600 dest_array_format->get_stride(), 00601 array_data + source_column->get_start(), source_array_format->get_stride(), 00602 num_rows); 00603 00604 } else { 00605 // A generic copy. 00606 if (gobj_cat.is_debug()) { 00607 gobj_cat.debug() 00608 << "generic copy " << *dest_column << " from " 00609 << *source_column << "\n"; 00610 } 00611 GeomVertexWriter to(this); 00612 to.set_column(dest_i, dest_column); 00613 GeomVertexReader from(source); 00614 from.set_column(source_i, source_column); 00615 00616 while (!from.is_at_end()) { 00617 to.set_data4f(from.get_data4f()); 00618 } 00619 } 00620 } 00621 } 00622 } 00623 00624 // Also convert the animation tables as necessary. 00625 const GeomVertexAnimationSpec &source_animation = source_format->get_animation(); 00626 const GeomVertexAnimationSpec &dest_animation = dest_format->get_animation(); 00627 if (source_animation != dest_animation) { 00628 if (dest_animation.get_animation_type() == AT_hardware) { 00629 // Convert Panda-style animation tables to hardware-style 00630 // animation tables. 00631 CPT(TransformBlendTable) blend_table = source->get_transform_blend_table(); 00632 if (blend_table != (TransformBlendTable *)NULL) { 00633 PT(TransformTable) transform_table = new TransformTable; 00634 TransformMap already_added; 00635 00636 if (dest_animation.get_indexed_transforms()) { 00637 // Build an indexed transform array. This is easier; this 00638 // means we can put the blends in any order. 00639 GeomVertexWriter weight(this, InternalName::get_transform_weight()); 00640 GeomVertexWriter index(this, InternalName::get_transform_index()); 00641 GeomVertexReader from(source, InternalName::get_transform_blend()); 00642 00643 while (!from.is_at_end()) { 00644 const TransformBlend &blend = blend_table->get_blend(from.get_data1i()); 00645 LVecBase4f weights = LVecBase4f::zero(); 00646 int indices[4] = {0, 0, 0, 0}; 00647 nassertv(blend.get_num_transforms() <= 4); 00648 00649 for (int i = 0; i < blend.get_num_transforms(); i++) { 00650 weights[i] = blend.get_weight(i); 00651 indices[i] = add_transform(transform_table, blend.get_transform(i), 00652 already_added); 00653 } 00654 if (weight.has_column()) { 00655 weight.set_data4f(weights); 00656 } 00657 index.set_data4i(indices); 00658 } 00659 } else { 00660 // Build a nonindexed transform array. This means we have to 00661 // use the same n transforms, in the same order, for each vertex. 00662 GeomVertexWriter weight(this, InternalName::get_transform_weight()); 00663 GeomVertexReader from(source, InternalName::get_transform_blend()); 00664 00665 while (!from.is_at_end()) { 00666 const TransformBlend &blend = blend_table->get_blend(from.get_data1i()); 00667 LVecBase4f weights = LVecBase4f::zero(); 00668 00669 for (int i = 0; i < blend.get_num_transforms(); i++) { 00670 int index = add_transform(transform_table, blend.get_transform(i), 00671 already_added); 00672 nassertv(index <= 4); 00673 weights[index] = blend.get_weight(i); 00674 } 00675 if (weight.has_column()) { 00676 weight.set_data4f(weights); 00677 } 00678 } 00679 } 00680 00681 clear_transform_blend_table(); 00682 set_transform_table(TransformTable::register_table(transform_table)); 00683 } 00684 } 00685 } 00686 } 00687 00688 //////////////////////////////////////////////////////////////////// 00689 // Function: GeomVertexData::copy_row_from 00690 // Access: Published 00691 // Description: Copies a single row of the data from the other array 00692 // into the indicated row of this array. In this case, 00693 // the source format must exactly match the destination 00694 // format. 00695 // 00696 // Don't call this in a downstream thread unless you 00697 // don't mind it blowing away other changes you might 00698 // have recently made in an upstream thread. 00699 //////////////////////////////////////////////////////////////////// 00700 void GeomVertexData:: 00701 copy_row_from(int dest_row, const GeomVertexData *source, 00702 int source_row, Thread *current_thread) { 00703 const GeomVertexFormat *source_format = source->get_format(); 00704 const GeomVertexFormat *dest_format = get_format(); 00705 nassertv(source_format == dest_format); 00706 nassertv(source_row >= 0 && source_row < source->get_num_rows()); 00707 00708 if (dest_row >= get_num_rows()) { 00709 // Implicitly add enough rows to get to the indicated row. 00710 set_num_rows(dest_row + 1); 00711 } 00712 00713 int num_arrays = source_format->get_num_arrays(); 00714 00715 for (int i = 0; i < num_arrays; ++i) { 00716 PT(GeomVertexArrayData) dest_array_obj = modify_array(i); 00717 PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); 00718 unsigned char *dest_array_data = dest_handle->get_write_pointer(); 00719 00720 CPT(GeomVertexArrayData) source_array_obj = source->get_array(i); 00721 CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle(); 00722 const unsigned char *source_array_data = source_array_handle->get_read_pointer(true); 00723 00724 const GeomVertexArrayFormat *array_format = source_format->get_array(i); 00725 int stride = array_format->get_stride(); 00726 00727 memcpy(dest_array_data + stride * dest_row, 00728 source_array_data + stride * source_row, 00729 stride); 00730 } 00731 } 00732 00733 //////////////////////////////////////////////////////////////////// 00734 // Function: GeomVertexData::convert_to 00735 // Access: Published 00736 // Description: Returns a new GeomVertexData that represents the same 00737 // contents as this one, with all data types matched up 00738 // name-by-name to the indicated new format. 00739 //////////////////////////////////////////////////////////////////// 00740 CPT(GeomVertexData) GeomVertexData:: 00741 convert_to(const GeomVertexFormat *new_format) const { 00742 Thread *current_thread = Thread::get_current_thread(); 00743 00744 if (new_format == get_format()) { 00745 // Trivial case: no change is needed. 00746 return this; 00747 } 00748 00749 // Look up the new format in our cache--maybe we've recently applied 00750 // it. 00751 PT(CacheEntry) entry; 00752 00753 CacheKey key(new_format); 00754 00755 _cache_lock.acquire(); 00756 Cache::const_iterator ci = _cache.find(&key); 00757 if (ci == _cache.end()) { 00758 _cache_lock.release(); 00759 00760 } else { 00761 entry = (*ci).second; 00762 _cache_lock.release(); 00763 nassertr(entry->_source == this, NULL); 00764 00765 // Here's an element in the cache for this computation. Record a 00766 // cache hit, so this element will stay in the cache a while 00767 // longer. 00768 entry->refresh(current_thread); 00769 00770 CDCacheReader cdata(entry->_cycler); 00771 if (cdata->_result != (GeomVertexData *)NULL) { 00772 return cdata->_result; 00773 } 00774 00775 // The cache entry is stale, but we'll recompute it below. Note 00776 // that there's a small race condition here; another thread might 00777 // recompute the cache at the same time. No big deal, since it'll 00778 // compute the same result. 00779 } 00780 00781 // Okay, convert the data to the new format. 00782 if (gobj_cat.is_debug()) { 00783 gobj_cat.debug() 00784 << "Converting " << get_num_rows() << " rows from " << *get_format() 00785 << " to " << *new_format << "\n"; 00786 } 00787 PStatTimer timer(_convert_pcollector); 00788 00789 PT(GeomVertexData) new_data = 00790 new GeomVertexData(get_name(), new_format, get_usage_hint()); 00791 new_data->set_transform_blend_table(get_transform_blend_table()); 00792 new_data->set_slider_table(get_slider_table()); 00793 00794 new_data->copy_from(this, false); 00795 00796 // Record the new result in the cache. 00797 if (entry == (CacheEntry *)NULL) { 00798 // Create a new entry for the result. 00799 entry = new CacheEntry((GeomVertexData *)this, new_format); 00800 { 00801 LightMutexHolder holder(_cache_lock); 00802 bool inserted = ((GeomVertexData *)this)->_cache.insert(Cache::value_type(&entry->_key, entry)).second; 00803 if (!inserted) { 00804 // Some other thread must have beat us to the punch. Never 00805 // mind. 00806 return new_data; 00807 } 00808 } 00809 00810 // And tell the cache manager about the new entry. (It might 00811 // immediately request a delete from the cache of the thing we 00812 // just added.) 00813 entry->record(current_thread); 00814 } 00815 00816 // Finally, store the cached result on the entry. 00817 CDCacheWriter cdata(entry->_cycler, true, current_thread); 00818 cdata->_result = new_data; 00819 00820 return new_data; 00821 } 00822 00823 00824 //////////////////////////////////////////////////////////////////// 00825 // Function: GeomVertexData::scale_color 00826 // Access: Published 00827 // Description: Returns a new GeomVertexData object with the color 00828 // table modified in-place to apply the indicated scale. 00829 // 00830 // If the vertex data does not include a color column, a 00831 // new one will not be added. 00832 //////////////////////////////////////////////////////////////////// 00833 CPT(GeomVertexData) GeomVertexData:: 00834 scale_color(const LVecBase4f &color_scale) const { 00835 const GeomVertexColumn *old_column = 00836 get_format()->get_column(InternalName::get_color()); 00837 if (old_column == (GeomVertexColumn *)NULL) { 00838 return this; 00839 } 00840 00841 PT(GeomVertexData) new_data = new GeomVertexData(*this); 00842 GeomVertexRewriter data(new_data, InternalName::get_color()); 00843 while (!data.is_at_end()) { 00844 Colorf color = data.get_data4f(); 00845 data.set_data4f(color[0] * color_scale[0], 00846 color[1] * color_scale[1], 00847 color[2] * color_scale[2], 00848 color[3] * color_scale[3]); 00849 } 00850 00851 return new_data; 00852 } 00853 00854 //////////////////////////////////////////////////////////////////// 00855 // Function: GeomVertexData::scale_color 00856 // Access: Published 00857 // Description: Returns a new GeomVertexData object with the color 00858 // table replaced with a new color table that has been 00859 // scaled by the indicated value. The new color table 00860 // will be added as a new array; if the old color table 00861 // was interleaved with a previous array, the previous 00862 // array will not be repacked. 00863 //////////////////////////////////////////////////////////////////// 00864 CPT(GeomVertexData) GeomVertexData:: 00865 scale_color(const LVecBase4f &color_scale, int num_components, 00866 GeomVertexData::NumericType numeric_type, 00867 GeomVertexData::Contents contents) const { 00868 int old_color_array = get_format()->get_array_with(InternalName::get_color()); 00869 if (old_color_array == -1) { 00870 // Oops, no color anyway. 00871 return set_color(color_scale, num_components, numeric_type, contents); 00872 } 00873 00874 int num_rows = get_num_rows(); 00875 00876 if (gobj_cat.is_debug()) { 00877 gobj_cat.debug() 00878 << "Scaling color for " << num_rows << " vertices by " 00879 << color_scale << ".\n"; 00880 } 00881 PStatTimer timer(_scale_color_pcollector); 00882 00883 PT(GeomVertexData) new_data = replace_column 00884 (InternalName::get_color(), num_components, numeric_type, contents); 00885 00886 // Now go through and apply the scale, copying it to the new data. 00887 GeomVertexWriter to(new_data, InternalName::get_color()); 00888 GeomVertexReader from(this, InternalName::get_color()); 00889 00890 for (int i = 0; i < num_rows; i++) { 00891 Colorf color = from.get_data4f(); 00892 to.set_data4f(color[0] * color_scale[0], 00893 color[1] * color_scale[1], 00894 color[2] * color_scale[2], 00895 color[3] * color_scale[3]); 00896 } 00897 00898 return new_data; 00899 } 00900 00901 //////////////////////////////////////////////////////////////////// 00902 // Function: GeomVertexData::set_color 00903 // Access: Published 00904 // Description: Returns a new GeomVertexData object with the color 00905 // data modified in-place with the new value. 00906 // 00907 // If the vertex data does not include a color column, a 00908 // new one will not be added. 00909 //////////////////////////////////////////////////////////////////// 00910 CPT(GeomVertexData) GeomVertexData:: 00911 set_color(const Colorf &color) const { 00912 const GeomVertexColumn *old_column = 00913 get_format()->get_column(InternalName::get_color()); 00914 if (old_column == (GeomVertexColumn *)NULL) { 00915 return this; 00916 } 00917 00918 PT(GeomVertexData) new_data = new GeomVertexData(*this); 00919 GeomVertexWriter to(new_data, InternalName::get_color()); 00920 while (!to.is_at_end()) { 00921 to.set_data4f(color); 00922 } 00923 00924 return new_data; 00925 } 00926 00927 //////////////////////////////////////////////////////////////////// 00928 // Function: GeomVertexData::set_color 00929 // Access: Published 00930 // Description: Returns a new GeomVertexData object with the color 00931 // table replaced with a new color table for which each 00932 // vertex has the indicated value. The new color table 00933 // will be added as a new array; if the old color table 00934 // was interleaved with a previous array, the previous 00935 // array will not be repacked. 00936 //////////////////////////////////////////////////////////////////// 00937 CPT(GeomVertexData) GeomVertexData:: 00938 set_color(const Colorf &color, int num_components, 00939 GeomVertexData::NumericType numeric_type, 00940 GeomVertexData::Contents contents) const { 00941 if (gobj_cat.is_debug()) { 00942 gobj_cat.debug() 00943 << "Setting color for " << get_num_rows() << " vertices to " 00944 << color << ".\n"; 00945 } 00946 PStatTimer timer(_set_color_pcollector); 00947 00948 PT(GeomVertexData) new_data = replace_column 00949 (InternalName::get_color(), num_components, numeric_type, contents); 00950 00951 // Now go through and set the new color value. 00952 GeomVertexWriter to(new_data, InternalName::get_color()); 00953 while (!to.is_at_end()) { 00954 to.set_data4f(color); 00955 } 00956 00957 return new_data; 00958 } 00959 00960 //////////////////////////////////////////////////////////////////// 00961 // Function: GeomVertexData::reverse_normals 00962 // Access: Published 00963 // Description: Returns a new GeomVertexData object with the normal 00964 // data modified in-place, so that each lighting normal 00965 // is now facing in the opposite direction. 00966 // 00967 // If the vertex data does not include a normal column, 00968 // this returns the original GeomVertexData object, 00969 // unchanged. 00970 //////////////////////////////////////////////////////////////////// 00971 CPT(GeomVertexData) GeomVertexData:: 00972 reverse_normals() const { 00973 const GeomVertexColumn *old_column = 00974 get_format()->get_column(InternalName::get_normal()); 00975 if (old_column == (GeomVertexColumn *)NULL) { 00976 return this; 00977 } 00978 00979 PT(GeomVertexData) new_data = new GeomVertexData(*this); 00980 GeomVertexRewriter to(new_data, InternalName::get_normal()); 00981 while (!to.is_at_end()) { 00982 to.set_data3f(-to.get_data3f()); 00983 } 00984 00985 return new_data; 00986 } 00987 00988 //////////////////////////////////////////////////////////////////// 00989 // Function: GeomVertexData::animate_vertices 00990 // Access: Published 00991 // Description: Returns a GeomVertexData that represents the results 00992 // of computing the vertex animation on the CPU for this 00993 // GeomVertexData. 00994 // 00995 // If there is no CPU-defined vertex animation on this 00996 // object, this just returns the original object. 00997 // 00998 // If there is vertex animation, but the VertexTransform 00999 // values have not changed since last time, this may 01000 // return the same pointer it returned previously. Even 01001 // if the VertexTransform values have changed, it may 01002 // still return the same pointer, but with its contents 01003 // modified (this is preferred, since it allows the 01004 // graphics backend to update vertex buffers optimally). 01005 // 01006 // If force is false, this method may return immediately 01007 // with stale data, if the vertex data is not completely 01008 // resident. If force is true, this method will never 01009 // return stale data, but may block until the data is 01010 // available. 01011 //////////////////////////////////////////////////////////////////// 01012 CPT(GeomVertexData) GeomVertexData:: 01013 animate_vertices(bool force, Thread *current_thread) const { 01014 CDLockedReader cdata(_cycler, current_thread); 01015 01016 if (cdata->_format->get_animation().get_animation_type() != AT_panda) { 01017 return this; 01018 } 01019 01020 UpdateSeq modified; 01021 if (!cdata->_transform_blend_table.is_null()) { 01022 if (cdata->_slider_table != (SliderTable *)NULL) { 01023 modified = 01024 max(cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread), 01025 cdata->_slider_table->get_modified(current_thread)); 01026 } else { 01027 modified = cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread); 01028 } 01029 01030 } else if (cdata->_slider_table != (SliderTable *)NULL) { 01031 modified = cdata->_slider_table->get_modified(current_thread); 01032 01033 } else { 01034 // No transform blend table or slider table--ergo, no vertex 01035 // animation. 01036 return this; 01037 } 01038 01039 if (cdata->_animated_vertices_modified == modified && 01040 cdata->_animated_vertices != (GeomVertexData *)NULL) { 01041 // No changes. 01042 return cdata->_animated_vertices; 01043 } 01044 01045 if (!force && !request_resident()) { 01046 // The vertex data isn't resident. Return the best information 01047 // we've got. 01048 if (cdata->_animated_vertices != (GeomVertexData *)NULL) { 01049 return cdata->_animated_vertices; 01050 } 01051 return this; 01052 } 01053 01054 CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false); 01055 cdataw->_animated_vertices_modified = modified; 01056 ((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread); 01057 01058 return cdataw->_animated_vertices; 01059 } 01060 01061 //////////////////////////////////////////////////////////////////// 01062 // Function: GeomVertexData::clear_animated_vertices 01063 // Access: Published 01064 // Description: Removes the cache of animated vertices computed by a 01065 // previous call to animate_vertices() within the same 01066 // frame. This will force the next call to 01067 // animate_vertices() to recompute these values from 01068 // scratch. Normally it is not necessary to call this. 01069 //////////////////////////////////////////////////////////////////// 01070 void GeomVertexData:: 01071 clear_animated_vertices() { 01072 CDWriter cdata(_cycler, true); 01073 cdata->_animated_vertices_modified.clear(); 01074 cdata->_animated_vertices.clear(); 01075 } 01076 01077 //////////////////////////////////////////////////////////////////// 01078 // Function: GeomVertexData::bytewise_copy 01079 // Access: Private, Static 01080 // Description: Quickly copies data without the need to convert it. 01081 //////////////////////////////////////////////////////////////////// 01082 void GeomVertexData:: 01083 bytewise_copy(unsigned char *to, int to_stride, 01084 const unsigned char *from, int from_stride, 01085 const GeomVertexColumn *from_type, 01086 int num_records) { 01087 if (gobj_cat.is_debug()) { 01088 gobj_cat.debug() 01089 << "bytewise_copy(" << (void *)to << ", " << to_stride 01090 << ", " << (const void *)from << ", " << from_stride 01091 << ", " << *from_type << ", " << num_records << ")\n"; 01092 } 01093 if (to_stride == from_type->get_total_bytes() && 01094 from_stride == from_type->get_total_bytes()) { 01095 // Fantastic! It's just a linear array of this one data type. 01096 // Copy the whole thing all at once. 01097 memcpy(to, from, num_records * from_type->get_total_bytes()); 01098 01099 } else { 01100 // Ok, it's interleaved in with other data. Copy them one record 01101 // at a time. 01102 while (num_records > 0) { 01103 memcpy(to, from, from_type->get_total_bytes()); 01104 to += to_stride; 01105 from += from_stride; 01106 num_records--; 01107 } 01108 } 01109 } 01110 01111 //////////////////////////////////////////////////////////////////// 01112 // Function: GeomVertexData::replace_column 01113 // Access: Published 01114 // Description: Returns a new GeomVertexData object, suitable for 01115 // modification, with the indicated data type replaced 01116 // with a new table filled with undefined values. The 01117 // new table will be added as a new array; if the old 01118 // table was interleaved with a previous array, the 01119 // previous array will not be repacked. 01120 // 01121 // If num_components is 0, the indicated name is simply 01122 // removed from the type, without replacing it with 01123 // anything else. 01124 //////////////////////////////////////////////////////////////////// 01125 PT(GeomVertexData) GeomVertexData:: 01126 replace_column(InternalName *name, int num_components, 01127 GeomVertexData::NumericType numeric_type, 01128 GeomVertexData::Contents contents) const { 01129 CDReader cdata(_cycler); 01130 PT(GeomVertexFormat) new_format = new GeomVertexFormat(*cdata->_format); 01131 01132 // Remove the old description of the type from the format. 01133 bool removed_type_array = false; 01134 int old_type_array = cdata->_format->get_array_with(name); 01135 if (old_type_array != -1) { 01136 GeomVertexArrayFormat *array_format = new_format->modify_array(old_type_array); 01137 if (array_format->get_num_columns() == 1) { 01138 // Actually, this array didn't have any other data types, so 01139 // just drop the whole array. 01140 new_format->remove_array(old_type_array); 01141 removed_type_array = true; 01142 01143 } else { 01144 // Remove the description for the type, but don't bother to 01145 // repack the array. 01146 array_format->remove_column(name); 01147 } 01148 } 01149 01150 // Now define a new array to contain just the type. 01151 int new_type_array = -1; 01152 if (num_components != 0) { 01153 PT(GeomVertexArrayFormat) type_array_format = 01154 new GeomVertexArrayFormat(name, num_components, numeric_type, contents); 01155 new_type_array = new_format->add_array(type_array_format); 01156 } 01157 01158 CPT(GeomVertexFormat) format = 01159 GeomVertexFormat::register_format(new_format); 01160 01161 if (gobj_cat.is_debug()) { 01162 gobj_cat.debug() 01163 << "Replacing data type " << *name << "; converting " 01164 << get_num_rows() << " rows from " 01165 << *cdata->_format << " to " << *format << "\n"; 01166 } 01167 01168 PT(GeomVertexData) new_data = new GeomVertexData(*this, format); 01169 01170 int j = 0; 01171 int num_arrays = get_num_arrays(); 01172 for (int i = 0; i < num_arrays; ++i) { 01173 if (i == old_type_array) { 01174 if (!removed_type_array) { 01175 // Pointer-copy the original array that includes the type 01176 // (since it also includes other data). 01177 new_data->set_array(j, get_array(i)); 01178 ++j; 01179 } 01180 01181 } else { 01182 // Just pointer-copy any arrays other than type. 01183 new_data->set_array(j, get_array(i)); 01184 ++j; 01185 } 01186 } 01187 01188 if (new_type_array != -1) { 01189 nassertr(j == new_type_array, new_data); 01190 01191 // For the new type array, we set up a temporary array that has 01192 // room for the right number of rows. 01193 PT(GeomVertexArrayData) new_array = new GeomVertexArrayData 01194 (format->get_array(j), get_usage_hint()); 01195 new_array->set_num_rows(get_num_rows()); 01196 new_data->set_array(j, new_array); 01197 } 01198 01199 return new_data; 01200 } 01201 01202 //////////////////////////////////////////////////////////////////// 01203 // Function: GeomVertexData::output 01204 // Access: Published 01205 // Description: 01206 //////////////////////////////////////////////////////////////////// 01207 void GeomVertexData:: 01208 output(ostream &out) const { 01209 if (!get_name().empty()) { 01210 out << get_name() << " "; 01211 } 01212 out << get_num_rows() << " rows: " << *get_format(); 01213 } 01214 01215 //////////////////////////////////////////////////////////////////// 01216 // Function: GeomVertexData::write 01217 // Access: Published 01218 // Description: 01219 //////////////////////////////////////////////////////////////////// 01220 void GeomVertexData:: 01221 write(ostream &out, int indent_level) const { 01222 if (!get_name().empty()) { 01223 indent(out, indent_level) << get_name() << "\n"; 01224 } 01225 get_format()->write_with_data(out, indent_level + 2, this); 01226 CPT(TransformBlendTable) table = get_transform_blend_table(); 01227 if (table != (TransformBlendTable *)NULL) { 01228 indent(out, indent_level) 01229 << "Transform blend table:\n"; 01230 table->write(out, indent_level + 2); 01231 } 01232 } 01233 01234 //////////////////////////////////////////////////////////////////// 01235 // Function: GeomVertexData::describe_vertex 01236 // Access: Published 01237 // Description: Writes a verbose, human-friendly description of the 01238 // indicated vertex number. 01239 //////////////////////////////////////////////////////////////////// 01240 void GeomVertexData:: 01241 describe_vertex(ostream &out, int row) const { 01242 nassertv_always(row >= 0 && row < get_num_rows()); 01243 01244 out << "Vertex " << row << ":\n"; 01245 01246 GeomVertexReader reader(this); 01247 reader.set_row(row); 01248 const GeomVertexFormat *format = get_format(); 01249 01250 const TransformBlendTable *tb_table = NULL; 01251 if (format->get_animation().get_animation_type() == AT_panda) { 01252 tb_table = get_transform_blend_table(); 01253 } 01254 01255 int num_columns = format->get_num_columns(); 01256 for (int ci = 0; ci < num_columns; ++ci) { 01257 int ai = format->get_array_with(ci); 01258 const GeomVertexColumn *column = format->get_column(ci); 01259 reader.set_column(ai, column); 01260 01261 int num_values = min(column->get_num_values(), 4); 01262 const LVecBase4f &d = reader.get_data4f(); 01263 01264 out << " " << *column->get_name(); 01265 for (int v = 0; v < num_values; v++) { 01266 out << " " << d[v]; 01267 } 01268 out << "\n"; 01269 01270 if (column->get_name() == InternalName::get_transform_blend() && 01271 tb_table != NULL) { 01272 // This is an index into the transform blend table. Look up the 01273 // index and report the vertex weighting. 01274 reader.set_column(ai, column); 01275 int bi = reader.get_data1i(); 01276 if (bi >= 0 && bi < tb_table->get_num_blends()) { 01277 const TransformBlend &blend = tb_table->get_blend(bi); 01278 out << " " << blend << "\n"; 01279 } 01280 } 01281 } 01282 01283 // Also show the raw vertex data, why not? 01284 out << "\nraw data:\n"; 01285 int num_arrays = format->get_num_arrays(); 01286 for (int ai = 0; ai < num_arrays; ++ai) { 01287 const GeomVertexArrayData *array = get_array(ai); 01288 const GeomVertexArrayFormat *aformat = format->get_array(ai); 01289 nassertv(array != NULL && aformat != NULL); 01290 out << " " << *aformat << "\n"; 01291 CPT(GeomVertexArrayDataHandle) handle = array->get_handle(); 01292 nassertv(handle != (const GeomVertexArrayDataHandle *)NULL); 01293 const unsigned char *data = handle->get_read_pointer(true); 01294 nassertv(data != NULL); 01295 int stride = aformat->get_stride(); 01296 int start = stride * row; 01297 if (data != NULL) { 01298 Datagram dg(data + start, stride); 01299 dg.dump_hex(out, 4); 01300 } 01301 } 01302 } 01303 01304 //////////////////////////////////////////////////////////////////// 01305 // Function: GeomVertexData::clear_cache 01306 // Access: Published 01307 // Description: Removes all of the previously-cached results of 01308 // convert_to(). 01309 // 01310 // This blows away the entire cache, upstream and 01311 // downstream the pipeline. Use clear_cache_stage() 01312 // instead if you only want to blow away the cache at 01313 // the current stage and upstream. 01314 //////////////////////////////////////////////////////////////////// 01315 void GeomVertexData:: 01316 clear_cache() { 01317 LightMutexHolder holder(_cache_lock); 01318 for (Cache::iterator ci = _cache.begin(); 01319 ci != _cache.end(); 01320 ++ci) { 01321 CacheEntry *entry = (*ci).second; 01322 entry->erase(); 01323 } 01324 _cache.clear(); 01325 } 01326 01327 //////////////////////////////////////////////////////////////////// 01328 // Function: GeomVertexData::clear_cache_stage 01329 // Access: Published 01330 // Description: Removes all of the previously-cached results of 01331 // convert_to(), at the current pipeline stage and 01332 // upstream. Does not affect the downstream cache. 01333 // 01334 // Don't call this in a downstream thread unless you 01335 // don't mind it blowing away other changes you might 01336 // have recently made in an upstream thread. 01337 //////////////////////////////////////////////////////////////////// 01338 void GeomVertexData:: 01339 clear_cache_stage() { 01340 LightMutexHolder holder(_cache_lock); 01341 for (Cache::iterator ci = _cache.begin(); 01342 ci != _cache.end(); 01343 ++ci) { 01344 CacheEntry *entry = (*ci).second; 01345 CDCacheWriter cdata(entry->_cycler); 01346 cdata->_result = NULL; 01347 } 01348 } 01349 01350 //////////////////////////////////////////////////////////////////// 01351 // Function: GeomVertexData::packed_argb_to_uint8_rgba 01352 // Access: Private, Static 01353 // Description: Quickly converts DirectX-style color to OpenGL-style 01354 // color. 01355 //////////////////////////////////////////////////////////////////// 01356 void GeomVertexData:: 01357 packed_argb_to_uint8_rgba(unsigned char *to, int to_stride, 01358 const unsigned char *from, int from_stride, 01359 int num_records) { 01360 if (gobj_cat.is_debug()) { 01361 gobj_cat.debug() 01362 << "packed_argb_to_uint8_rgba(" << (void *)to << ", " << to_stride 01363 << ", " << (const void *)from << ", " << from_stride 01364 << ", " << num_records << ")\n"; 01365 } 01366 01367 while (num_records > 0) { 01368 PN_uint32 dword = *(const PN_uint32 *)from; 01369 to[0] = unpack_abcd_b(dword); 01370 to[1] = unpack_abcd_c(dword); 01371 to[2] = unpack_abcd_d(dword); 01372 to[3] = unpack_abcd_a(dword); 01373 01374 to += to_stride; 01375 from += from_stride; 01376 num_records--; 01377 } 01378 } 01379 01380 //////////////////////////////////////////////////////////////////// 01381 // Function: GeomVertexData::uint8_rgba_to_packed_argb 01382 // Access: Private, Static 01383 // Description: Quickly converts OpenGL-style color to DirectX-style 01384 // color. 01385 //////////////////////////////////////////////////////////////////// 01386 void GeomVertexData:: 01387 uint8_rgba_to_packed_argb(unsigned char *to, int to_stride, 01388 const unsigned char *from, int from_stride, 01389 int num_records) { 01390 if (gobj_cat.is_debug()) { 01391 gobj_cat.debug() 01392 << "uint8_rgba_to_packed_argb(" << (void *)to << ", " << to_stride 01393 << ", " << (const void *)from << ", " << from_stride 01394 << ", " << num_records << ")\n"; 01395 } 01396 01397 while (num_records > 0) { 01398 *(PN_uint32 *)to = pack_abcd(from[3], from[0], from[1], from[2]); 01399 01400 to += to_stride; 01401 from += from_stride; 01402 num_records--; 01403 } 01404 } 01405 01406 //////////////////////////////////////////////////////////////////// 01407 // Function: GeomVertexData::update_animated_vertices 01408 // Access: Private 01409 // Description: Recomputes the results of computing the vertex 01410 // animation on the CPU, and applies them to the 01411 // existing animated_vertices object. 01412 //////////////////////////////////////////////////////////////////// 01413 void GeomVertexData:: 01414 update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { 01415 int num_rows = get_num_rows(); 01416 01417 if (gobj_cat.is_debug()) { 01418 gobj_cat.debug() 01419 << "Animating " << num_rows << " vertices for " << get_name() 01420 << "\n"; 01421 } 01422 01423 PStatTimer timer(_char_pcollector, current_thread); 01424 01425 const GeomVertexFormat *orig_format = cdata->_format; 01426 CPT(GeomVertexFormat) new_format = orig_format; 01427 01428 if (cdata->_animated_vertices == (GeomVertexData *)NULL) { 01429 new_format = orig_format->get_post_animated_format(); 01430 cdata->_animated_vertices = 01431 new GeomVertexData(get_name(), new_format, 01432 min(get_usage_hint(), UH_dynamic)); 01433 } 01434 PT(GeomVertexData) new_data = cdata->_animated_vertices; 01435 01436 // We have to make a complete copy of the data first so we can 01437 // modify it. If we were clever, we could maybe just figure out the 01438 // subset of the data that might have changed since last frame, but 01439 // that's too much trouble (and isn't obviously faster than just 01440 // copying the whole thing). 01441 new_data->copy_from(this, true); 01442 01443 // First, apply all of the morphs. 01444 CPT(SliderTable) slider_table = cdata->_slider_table; 01445 if (slider_table != (SliderTable *)NULL) { 01446 PStatTimer timer2(_morphs_pcollector); 01447 int num_morphs = orig_format->get_num_morphs(); 01448 for (int mi = 0; mi < num_morphs; mi++) { 01449 CPT(InternalName) slider_name = orig_format->get_morph_slider(mi); 01450 01451 const SparseArray &sliders = slider_table->find_sliders(slider_name); 01452 if (!sliders.is_zero()) { 01453 nassertv(!sliders.is_inverse()); 01454 int num_slider_subranges = sliders.get_num_subranges(); 01455 for (int sni = 0; sni < num_slider_subranges; ++sni) { 01456 int slider_begin = sliders.get_subrange_begin(sni); 01457 int slider_end = sliders.get_subrange_end(sni); 01458 for (int sn = slider_begin; sn < slider_end; ++sn) { 01459 const VertexSlider *slider = slider_table->get_slider(sn); 01460 const SparseArray &rows = slider_table->get_slider_rows(sn); 01461 nassertv(!rows.is_inverse()); 01462 01463 float slider_value = slider->get_slider(); 01464 if (slider_value != 0.0f) { 01465 CPT(InternalName) base_name = orig_format->get_morph_base(mi); 01466 CPT(InternalName) delta_name = orig_format->get_morph_delta(mi); 01467 01468 GeomVertexRewriter data(new_data, base_name); 01469 GeomVertexReader delta(this, delta_name); 01470 int num_subranges = rows.get_num_subranges(); 01471 01472 if (data.get_column()->get_num_values() == 4) { 01473 if (data.get_column()->has_homogeneous_coord()) { 01474 // Scale the delta by the homogeneous coordinate. 01475 for (int i = 0; i < num_subranges; ++i) { 01476 int begin = rows.get_subrange_begin(i); 01477 int end = rows.get_subrange_end(i); 01478 data.set_row(begin); 01479 delta.set_row(begin); 01480 for (int j = begin; j < end; ++j) { 01481 LPoint4f vertex = data.get_data4f(); 01482 LPoint3f d = delta.get_data3f(); 01483 d *= slider_value * vertex[3]; 01484 data.set_data4f(vertex[0] + d[0], 01485 vertex[1] + d[1], 01486 vertex[2] + d[2], 01487 vertex[3]); 01488 } 01489 } 01490 } else { 01491 // Just apply the four-component delta. 01492 for (int i = 0; i < num_subranges; ++i) { 01493 int begin = rows.get_subrange_begin(i); 01494 int end = rows.get_subrange_end(i); 01495 data.set_row(begin); 01496 delta.set_row(begin); 01497 for (int j = begin; j < end; ++j) { 01498 const LPoint4f &vertex = data.get_data4f(); 01499 LPoint4f d = delta.get_data4f(); 01500 data.set_data4f(vertex + d * slider_value); 01501 } 01502 } 01503 } 01504 } else { 01505 // 3-component or smaller values; don't worry about a 01506 // homogeneous coordinate. 01507 for (int i = 0; i < num_subranges; ++i) { 01508 int begin = rows.get_subrange_begin(i); 01509 int end = rows.get_subrange_end(i); 01510 data.set_row(begin); 01511 delta.set_row(begin); 01512 for (int j = begin; j < end; ++j) { 01513 const LPoint3f &vertex = data.get_data3f(); 01514 LPoint3f d = delta.get_data3f(); 01515 data.set_data3f(vertex + d * slider_value); 01516 } 01517 } 01518 } 01519 } 01520 } 01521 } 01522 } 01523 } 01524 } 01525 01526 // Then apply the transforms. 01527 CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(); 01528 if (tb_table != (TransformBlendTable *)NULL) { 01529 PStatTimer timer3(_skinning_pcollector); 01530 01531 // Recompute all the blends up front, so we don't have to test 01532 // each one for staleness at each vertex. 01533 int num_blends = tb_table->get_num_blends(); 01534 int bi; 01535 for (bi = 0; bi < num_blends; bi++) { 01536 tb_table->get_blend(bi).update_blend(current_thread); 01537 } 01538 01539 // Now go through and apply the transforms. 01540 01541 const SparseArray &rows = tb_table->get_rows(); 01542 int num_subranges = rows.get_num_subranges(); 01543 01544 int blend_array_index = orig_format->get_array_with(InternalName::get_transform_blend()); 01545 if (blend_array_index < 0) { 01546 gobj_cat.warning() 01547 << "Vertex data " << get_name() 01548 << " has a transform_blend_table, but no transform_blend data.\n"; 01549 return; 01550 } 01551 01552 CPT(GeomVertexArrayFormat) blend_array_format = orig_format->get_array(blend_array_index); 01553 01554 if (blend_array_format->get_num_columns() == 1 && 01555 blend_array_format->get_stride() == 2 && 01556 blend_array_format->get_column(0)->get_component_bytes() == 2) { 01557 // The blend indices are a table of ushorts. Optimize this 01558 // common case. 01559 CPT(GeomVertexArrayDataHandle) blend_array_handle = cdata->_arrays[blend_array_index].get_read_pointer()->get_handle(current_thread); 01560 const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true); 01561 01562 int ci; 01563 for (ci = 0; ci < new_format->get_num_points(); ci++) { 01564 GeomVertexRewriter data(new_data, new_format->get_point(ci)); 01565 const GeomVertexColumn *data_column = data.get_column(); 01566 if (data_column->get_num_values() == 3 && 01567 data_column->get_numeric_type() == NT_float32) { 01568 // Table of points is a table of LPoint3f's. Optimize this 01569 // common case. 01570 int data_index = new_format->get_array_with(new_format->get_point(ci)); 01571 PT(GeomVertexArrayData) data_array = new_data->modify_array(data_index); 01572 PT(GeomVertexArrayDataHandle) data_handle = data_array->modify_handle(); 01573 unsigned char *datat = data_handle->get_write_pointer(); 01574 datat += data_column->get_start(); 01575 size_t stride = data_array->get_array_format()->get_stride(); 01576 01577 for (int i = 0; i < num_subranges; ++i) { 01578 int begin = rows.get_subrange_begin(i); 01579 int end = rows.get_subrange_end(i); 01580 for (int j = begin; j < end; ++j) { 01581 LPoint3f &vertex = *(LPoint3f *)(&datat[j * stride]); 01582 int bi = blendt[j]; 01583 tb_table->get_blend(bi).transform_point(vertex, current_thread); 01584 } 01585 } 01586 01587 } else if (data_column->get_num_values() == 4) { 01588 // Use the GeomVertexRewriter to adjust the 4-component 01589 // points. 01590 for (int i = 0; i < num_subranges; ++i) { 01591 int begin = rows.get_subrange_begin(i); 01592 int end = rows.get_subrange_end(i); 01593 data.set_row(begin); 01594 for (int j = begin; j < end; ++j) { 01595 LPoint4f vertex = data.get_data4f(); 01596 int bi = blendt[j]; 01597 tb_table->get_blend(bi).transform_point(vertex, current_thread); 01598 data.set_data4f(vertex); 01599 } 01600 } 01601 01602 } else { 01603 // Use the GeomVertexRewriter to adjust the 3-component 01604 // points. 01605 for (int i = 0; i < num_subranges; ++i) { 01606 int begin = rows.get_subrange_begin(i); 01607 int end = rows.get_subrange_end(i); 01608 data.set_row(begin); 01609 for (int j = begin; j < end; ++j) { 01610 LPoint3f vertex = data.get_data3f(); 01611 int bi = blendt[j]; 01612 tb_table->get_blend(bi).transform_point(vertex, current_thread); 01613 data.set_data3f(vertex); 01614 } 01615 } 01616 } 01617 } 01618 01619 // Also process vectors: normals, etc. 01620 for (ci = 0; ci < new_format->get_num_vectors(); ci++) { 01621 GeomVertexRewriter data(new_data, new_format->get_vector(ci)); 01622 const GeomVertexColumn *data_column = data.get_column(); 01623 if (data_column->get_num_values() == 3 && 01624 data_column->get_numeric_type() == NT_float32) { 01625 // Table of vectors is a table of LVector3f's. Optimize this 01626 // common case. 01627 int data_index = new_format->get_array_with(new_format->get_vector(ci)); 01628 PT(GeomVertexArrayData) data_array = new_data->modify_array(data_index); 01629 PT(GeomVertexArrayDataHandle) data_handle = data_array->modify_handle(); 01630 unsigned char *datat = data_handle->get_write_pointer(); 01631 datat += data_column->get_start(); 01632 size_t stride = data_array->get_array_format()->get_stride(); 01633 01634 for (int i = 0; i < num_subranges; ++i) { 01635 int begin = rows.get_subrange_begin(i); 01636 int end = rows.get_subrange_end(i); 01637 for (int j = begin; j < end; ++j) { 01638 LVector3f &vertex = *(LVector3f *)(&datat[j * stride]); 01639 int bi = blendt[j]; 01640 tb_table->get_blend(bi).transform_vector(vertex, current_thread); 01641 } 01642 } 01643 01644 } else { 01645 // Use the GeomVertexRewriter to adjust the vectors. 01646 01647 for (int i = 0; i < num_subranges; ++i) { 01648 int begin = rows.get_subrange_begin(i); 01649 int end = rows.get_subrange_end(i); 01650 data.set_row(begin); 01651 for (int j = begin; j < end; ++j) { 01652 LVector3f vertex = data.get_data3f(); 01653 int bi = blendt[j]; 01654 tb_table->get_blend(bi).transform_vector(vertex, current_thread); 01655 data.set_data3f(vertex); 01656 } 01657 } 01658 } 01659 } 01660 01661 } else { 01662 // The blend indices are anything else. Use the 01663 // GeomVertexReader to iterate through them. 01664 GeomVertexReader blendi(this, InternalName::get_transform_blend()); 01665 nassertv(blendi.has_column()); 01666 01667 int ci; 01668 for (ci = 0; ci < new_format->get_num_points(); ci++) { 01669 GeomVertexRewriter data(new_data, new_format->get_point(ci)); 01670 const GeomVertexColumn *data_column = data.get_column(); 01671 01672 if (data_column->get_num_values() == 4) { 01673 for (int i = 0; i < num_subranges; ++i) { 01674 int begin = rows.get_subrange_begin(i); 01675 int end = rows.get_subrange_end(i); 01676 data.set_row(begin); 01677 blendi.set_row(begin); 01678 for (int j = begin; j < end; ++j) { 01679 LPoint4f vertex = data.get_data4f(); 01680 int bi = blendi.get_data1i(); 01681 tb_table->get_blend(bi).transform_point(vertex, current_thread); 01682 data.set_data4f(vertex); 01683 } 01684 } 01685 } else { 01686 for (int i = 0; i < num_subranges; ++i) { 01687 int begin = rows.get_subrange_begin(i); 01688 int end = rows.get_subrange_end(i); 01689 data.set_row(begin); 01690 blendi.set_row(begin); 01691 for (int j = begin; j < end; ++j) { 01692 LPoint3f vertex = data.get_data3f(); 01693 int bi = blendi.get_data1i(); 01694 tb_table->get_blend(bi).transform_point(vertex, current_thread); 01695 data.set_data3f(vertex); 01696 } 01697 } 01698 } 01699 } 01700 for (ci = 0; ci < new_format->get_num_vectors(); ci++) { 01701 GeomVertexRewriter data(new_data, new_format->get_vector(ci)); 01702 for (int i = 0; i < num_subranges; ++i) { 01703 int begin = rows.get_subrange_begin(i); 01704 int end = rows.get_subrange_end(i); 01705 data.set_row(begin); 01706 blendi.set_row(begin); 01707 for (int j = begin; j < end; ++j) { 01708 LVector3f vertex = data.get_data3f(); 01709 int bi = blendi.get_data1i(); 01710 tb_table->get_blend(bi).transform_vector(vertex, current_thread); 01711 data.set_data3f(vertex); 01712 } 01713 } 01714 } 01715 } 01716 } 01717 } 01718 01719 //////////////////////////////////////////////////////////////////// 01720 // Function: GeomVertexData::register_with_read_factory 01721 // Access: Public, Static 01722 // Description: Tells the BamReader how to create objects of type 01723 // GeomVertexData. 01724 //////////////////////////////////////////////////////////////////// 01725 void GeomVertexData:: 01726 register_with_read_factory() { 01727 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 01728 } 01729 01730 //////////////////////////////////////////////////////////////////// 01731 // Function: GeomVertexData::write_datagram 01732 // Access: Public, Virtual 01733 // Description: Writes the contents of this object to the datagram 01734 // for shipping out to a Bam file. 01735 //////////////////////////////////////////////////////////////////// 01736 void GeomVertexData:: 01737 write_datagram(BamWriter *manager, Datagram &dg) { 01738 CopyOnWriteObject::write_datagram(manager, dg); 01739 01740 dg.add_string(_name); 01741 manager->write_cdata(dg, _cycler); 01742 } 01743 01744 //////////////////////////////////////////////////////////////////// 01745 // Function: GeomVertexData::make_from_bam 01746 // Access: Protected, Static 01747 // Description: This function is called by the BamReader's factory 01748 // when a new object of type GeomVertexData is encountered 01749 // in the Bam file. It should create the GeomVertexData 01750 // and extract its information from the file. 01751 //////////////////////////////////////////////////////////////////// 01752 TypedWritable *GeomVertexData:: 01753 make_from_bam(const FactoryParams ¶ms) { 01754 GeomVertexData *object = new GeomVertexData; 01755 DatagramIterator scan; 01756 BamReader *manager; 01757 01758 parse_params(params, scan, manager); 01759 object->fillin(scan, manager); 01760 manager->register_finalize(object); 01761 01762 return object; 01763 } 01764 01765 //////////////////////////////////////////////////////////////////// 01766 // Function: GeomVertexData::complete_pointers 01767 // Access: Public, Virtual 01768 // Description: Receives an array of pointers, one for each time 01769 // manager->read_pointer() was called in fillin(). 01770 // Returns the number of pointers processed. 01771 //////////////////////////////////////////////////////////////////// 01772 int GeomVertexData:: 01773 complete_pointers(TypedWritable **p_list, BamReader *manager) { 01774 int pi = CopyOnWriteObject::complete_pointers(p_list, manager); 01775 return pi; 01776 } 01777 01778 //////////////////////////////////////////////////////////////////// 01779 // Function: GeomVertexData::require_fully_complete 01780 // Access: Public, Virtual 01781 // Description: Some objects require all of their nested pointers to 01782 // have been completed before the objects themselves can 01783 // be completed. If this is the case, override this 01784 // method to return true, and be careful with circular 01785 // references (which would make the object unreadable 01786 // from a bam file). 01787 //////////////////////////////////////////////////////////////////// 01788 bool GeomVertexData:: 01789 require_fully_complete() const { 01790 return true; 01791 } 01792 01793 //////////////////////////////////////////////////////////////////// 01794 // Function: GeomVertexData::finalize 01795 // Access: Public, Virtual 01796 // Description: Called by the BamReader to perform any final actions 01797 // needed for setting up the object after all objects 01798 // have been read and all pointers have been completed. 01799 //////////////////////////////////////////////////////////////////// 01800 void GeomVertexData:: 01801 finalize(BamReader *manager) { 01802 // NOTE: This method may be called more than once, because the 01803 // Geom::finalize() will call it explicitly. We have to be prepared 01804 // to accept multiple finalize() calls. 01805 01806 // Now we need to register the format that we have read from the bam 01807 // file (since it doesn't come out of the bam file automatically 01808 // registered). This may change the format's pointer, which we 01809 // should then update our own data to reflect. But since this may 01810 // cause the unregistered object to destruct, we have to also tell 01811 // the BamReader to return the new object from now on. 01812 01813 // This extends to the nested array datas, as well as the transform 01814 // table and slider tables, as well. 01815 01816 CDWriter cdata(_cycler, true); 01817 01818 for (size_t i = 0; i < cdata->_arrays.size(); ++i) { 01819 CPT(GeomVertexFormat) new_format = 01820 GeomVertexFormat::register_format(cdata->_format); 01821 manager->change_pointer(cdata->_format, new_format); 01822 cdata->_format = new_format; 01823 01824 CPT(GeomVertexArrayFormat) new_array_format = new_format->get_array(i); 01825 PT(GeomVertexArrayData) array_obj = cdata->_arrays[i].get_unsafe_pointer(); 01826 nassertv(new_array_format->is_data_subset_of(*array_obj->_array_format)); 01827 01828 manager->change_pointer(array_obj->_array_format, new_array_format); 01829 array_obj->_array_format = new_array_format; 01830 } 01831 01832 if (cdata->_transform_table != (TransformTable *)NULL) { 01833 CPT(TransformTable) new_transform_table = 01834 TransformTable::register_table(cdata->_transform_table); 01835 manager->change_pointer(cdata->_transform_table, new_transform_table); 01836 cdata->_transform_table = new_transform_table; 01837 } 01838 01839 if (cdata->_slider_table != (SliderTable *)NULL) { 01840 CPT(SliderTable) new_slider_table = 01841 SliderTable::register_table(cdata->_slider_table); 01842 manager->change_pointer(cdata->_slider_table, new_slider_table); 01843 cdata->_slider_table = new_slider_table; 01844 } 01845 } 01846 01847 //////////////////////////////////////////////////////////////////// 01848 // Function: GeomVertexData::fillin 01849 // Access: Protected 01850 // Description: This internal function is called by make_from_bam to 01851 // read in all of the relevant data from the BamFile for 01852 // the new GeomVertexData. 01853 //////////////////////////////////////////////////////////////////// 01854 void GeomVertexData:: 01855 fillin(DatagramIterator &scan, BamReader *manager) { 01856 CopyOnWriteObject::fillin(scan, manager); 01857 01858 set_name(scan.get_string()); 01859 manager->read_cdata(scan, _cycler); 01860 } 01861 01862 //////////////////////////////////////////////////////////////////// 01863 // Function: GeomVertexData::CDataCache::make_copy 01864 // Access: Public, Virtual 01865 // Description: 01866 //////////////////////////////////////////////////////////////////// 01867 CycleData *GeomVertexData::CDataCache:: 01868 make_copy() const { 01869 return new CDataCache(*this); 01870 } 01871 01872 //////////////////////////////////////////////////////////////////// 01873 // Function: GeomVertexData::CacheEntry::evict_callback 01874 // Access: Public, Virtual 01875 // Description: Called when the entry is evicted from the cache, this 01876 // should clean up the owning object appropriately. 01877 //////////////////////////////////////////////////////////////////// 01878 void GeomVertexData::CacheEntry:: 01879 evict_callback() { 01880 LightMutexHolder holder(_source->_cache_lock); 01881 Cache::iterator ci = _source->_cache.find(&_key); 01882 nassertv(ci != _source->_cache.end()); 01883 nassertv((*ci).second == this); 01884 _source->_cache.erase(ci); 01885 } 01886 01887 //////////////////////////////////////////////////////////////////// 01888 // Function: GeomVertexData::CacheEntry::output 01889 // Access: Public, Virtual 01890 // Description: 01891 //////////////////////////////////////////////////////////////////// 01892 void GeomVertexData::CacheEntry:: 01893 output(ostream &out) const { 01894 out << "vertex data " << (void *)_source << " to " 01895 << *_key._modifier; 01896 } 01897 01898 //////////////////////////////////////////////////////////////////// 01899 // Function: GeomVertexData::CData::make_copy 01900 // Access: Public, Virtual 01901 // Description: 01902 //////////////////////////////////////////////////////////////////// 01903 CycleData *GeomVertexData::CData:: 01904 make_copy() const { 01905 return new CData(*this); 01906 } 01907 01908 //////////////////////////////////////////////////////////////////// 01909 // Function: GeomVertexData::CData::write_datagram 01910 // Access: Public, Virtual 01911 // Description: Writes the contents of this object to the datagram 01912 // for shipping out to a Bam file. 01913 //////////////////////////////////////////////////////////////////// 01914 void GeomVertexData::CData:: 01915 write_datagram(BamWriter *manager, Datagram &dg) const { 01916 manager->write_pointer(dg, _format); 01917 dg.add_uint8(_usage_hint); 01918 01919 dg.add_uint16(_arrays.size()); 01920 Arrays::const_iterator ai; 01921 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) { 01922 manager->write_pointer(dg, (*ai).get_read_pointer()); 01923 } 01924 01925 manager->write_pointer(dg, _transform_table); 01926 manager->write_pointer(dg, _transform_blend_table.get_read_pointer()); 01927 manager->write_pointer(dg, _slider_table); 01928 } 01929 01930 //////////////////////////////////////////////////////////////////// 01931 // Function: GeomVertexData::CData::complete_pointers 01932 // Access: Public, Virtual 01933 // Description: Receives an array of pointers, one for each time 01934 // manager->read_pointer() was called in fillin(). 01935 // Returns the number of pointers processed. 01936 //////////////////////////////////////////////////////////////////// 01937 int GeomVertexData::CData:: 01938 complete_pointers(TypedWritable **p_list, BamReader *manager) { 01939 int pi = CycleData::complete_pointers(p_list, manager); 01940 01941 _format = DCAST(GeomVertexFormat, p_list[pi++]); 01942 01943 Arrays::iterator ai; 01944 for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) { 01945 (*ai) = DCAST(GeomVertexArrayData, p_list[pi++]); 01946 } 01947 01948 _transform_table = DCAST(TransformTable, p_list[pi++]); 01949 _transform_blend_table = DCAST(TransformBlendTable, p_list[pi++]); 01950 _slider_table = DCAST(SliderTable, p_list[pi++]); 01951 01952 _modified = Geom::get_next_modified(); 01953 01954 if (!_arrays.empty() && manager->get_file_minor_ver() < 7) { 01955 // Bam files prior to 6.7 did not store a SparseArray in the 01956 // SliderTable or TransformBlendTable entries. We need to make up 01957 // a SparseArray for each of them that reflects the complete 01958 // number of rows in the data. 01959 SparseArray all_rows; 01960 CPT(GeomVertexArrayData) adata = _arrays[0].get_read_pointer(); 01961 all_rows.set_range(0, adata->get_num_rows()); 01962 01963 if (_slider_table != (SliderTable *)NULL) { 01964 int num_sliders = _slider_table->get_num_sliders(); 01965 for (int i = 0; i < num_sliders; ++i) { 01966 ((SliderTable *)_slider_table.p())->set_slider_rows(i, all_rows); 01967 } 01968 } 01969 if (!_transform_blend_table.is_null()) { 01970 _transform_blend_table.get_unsafe_pointer()->set_rows(all_rows); 01971 } 01972 } 01973 01974 return pi; 01975 } 01976 01977 //////////////////////////////////////////////////////////////////// 01978 // Function: GeomVertexData::CData::fillin 01979 // Access: Public, Virtual 01980 // Description: This internal function is called by make_from_bam to 01981 // read in all of the relevant data from the BamFile for 01982 // the new GeomVertexData. 01983 //////////////////////////////////////////////////////////////////// 01984 void GeomVertexData::CData:: 01985 fillin(DatagramIterator &scan, BamReader *manager) { 01986 manager->read_pointer(scan); 01987 _usage_hint = (UsageHint)scan.get_uint8(); 01988 01989 size_t num_arrays = scan.get_uint16(); 01990 _arrays.reserve(num_arrays); 01991 for (size_t i = 0; i < num_arrays; ++i) { 01992 manager->read_pointer(scan); 01993 _arrays.push_back(NULL); 01994 } 01995 01996 manager->read_pointer(scan); 01997 manager->read_pointer(scan); 01998 manager->read_pointer(scan); 01999 } 02000 02001 //////////////////////////////////////////////////////////////////// 02002 // Function: GeomVertexDataPipelineBase::get_num_bytes 02003 // Access: Public 02004 // Description: 02005 //////////////////////////////////////////////////////////////////// 02006 int GeomVertexDataPipelineBase:: 02007 get_num_bytes() const { 02008 int num_bytes = sizeof(GeomVertexData); 02009 02010 GeomVertexData::Arrays::const_iterator ai; 02011 for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { 02012 num_bytes += (*ai).get_read_pointer()->get_data_size_bytes(); 02013 } 02014 02015 return num_bytes; 02016 } 02017 02018 //////////////////////////////////////////////////////////////////// 02019 // Function: GeomVertexDataPipelineReader::get_num_rows 02020 // Access: Published 02021 // Description: 02022 //////////////////////////////////////////////////////////////////// 02023 int GeomVertexDataPipelineReader:: 02024 get_num_rows() const { 02025 nassertr(_cdata->_format->get_num_arrays() == (int)_cdata->_arrays.size(), 0); 02026 nassertr(_got_array_readers, 0); 02027 02028 if (_cdata->_format->get_num_arrays() == 0) { 02029 // No arrays means no rows. Weird but legal. 02030 return 0; 02031 } 02032 02033 // Look up the answer on the first array (since any array will do). 02034 int stride = _cdata->_format->get_array(0)->get_stride(); 02035 return _array_readers[0]->get_data_size_bytes() / stride; 02036 } 02037 02038 //////////////////////////////////////////////////////////////////// 02039 // Function: GeomVertexDataPipelineReader::get_array_info 02040 // Access: Public 02041 // Description: 02042 //////////////////////////////////////////////////////////////////// 02043 bool GeomVertexDataPipelineReader:: 02044 get_array_info(const InternalName *name, 02045 const GeomVertexArrayDataHandle *&array_reader, 02046 int &num_values, 02047 GeomVertexDataPipelineReader::NumericType &numeric_type, 02048 int &start, int &stride) const { 02049 nassertr(_got_array_readers, false); 02050 int array_index; 02051 const GeomVertexColumn *column; 02052 if (_cdata->_format->get_array_info(name, array_index, column)) { 02053 array_reader = _array_readers[array_index]; 02054 num_values = column->get_num_values(); 02055 numeric_type = column->get_numeric_type(); 02056 start = column->get_start(); 02057 stride = _cdata->_format->get_array(array_index)->get_stride(); 02058 return true; 02059 } 02060 return false; 02061 } 02062 02063 //////////////////////////////////////////////////////////////////// 02064 // Function: GeomVertexDataPipelineReader::get_vertex_info 02065 // Access: Public 02066 // Description: 02067 //////////////////////////////////////////////////////////////////// 02068 bool GeomVertexDataPipelineReader:: 02069 get_vertex_info(const GeomVertexArrayDataHandle *&array_reader, 02070 int &num_values, 02071 GeomVertexDataPipelineReader::NumericType &numeric_type, 02072 int &start, int &stride) const { 02073 nassertr(_got_array_readers, false); 02074 int array_index = _cdata->_format->get_vertex_array_index(); 02075 if (array_index >= 0) { 02076 const GeomVertexColumn *column = _cdata->_format->get_vertex_column(); 02077 02078 array_reader = _array_readers[array_index]; 02079 num_values = column->get_num_values(); 02080 numeric_type = column->get_numeric_type(); 02081 start = column->get_start(); 02082 stride = _cdata->_format->get_array(array_index)->get_stride(); 02083 return true; 02084 } 02085 return false; 02086 } 02087 02088 //////////////////////////////////////////////////////////////////// 02089 // Function: GeomVertexDataPipelineReader::get_normal_info 02090 // Access: Public 02091 // Description: 02092 //////////////////////////////////////////////////////////////////// 02093 bool GeomVertexDataPipelineReader:: 02094 get_normal_info(const GeomVertexArrayDataHandle *&array_reader, 02095 GeomVertexDataPipelineReader::NumericType &numeric_type, 02096 int &start, int &stride) const { 02097 nassertr(_got_array_readers, false); 02098 int array_index = _cdata->_format->get_normal_array_index(); 02099 if (array_index >= 0) { 02100 const GeomVertexColumn *column = _cdata->_format->get_normal_column(); 02101 nassertr(column->get_num_values() == 3, false); 02102 02103 array_reader = _array_readers[array_index]; 02104 numeric_type = column->get_numeric_type(); 02105 start = column->get_start(); 02106 stride = _cdata->_format->get_array(array_index)->get_stride(); 02107 return true; 02108 } 02109 return false; 02110 } 02111 02112 //////////////////////////////////////////////////////////////////// 02113 // Function: GeomVertexDataPipelineReader::get_color_info 02114 // Access: Public 02115 // Description: 02116 //////////////////////////////////////////////////////////////////// 02117 bool GeomVertexDataPipelineReader:: 02118 get_color_info(const GeomVertexArrayDataHandle *&array_reader, 02119 int &num_values, 02120 GeomVertexDataPipelineReader::NumericType &numeric_type, 02121 int &start, int &stride) const { 02122 nassertr(_got_array_readers, false); 02123 int array_index = _cdata->_format->get_color_array_index(); 02124 if (array_index >= 0) { 02125 const GeomVertexColumn *column = _cdata->_format->get_color_column(); 02126 02127 array_reader = _array_readers[array_index]; 02128 num_values = column->get_num_values(); 02129 numeric_type = column->get_numeric_type(); 02130 start = column->get_start(); 02131 stride = _cdata->_format->get_array(array_index)->get_stride(); 02132 return true; 02133 } 02134 return false; 02135 } 02136 02137 //////////////////////////////////////////////////////////////////// 02138 // Function: GeomVertexDataPipelineReader::make_array_readers 02139 // Access: Private 02140 // Description: 02141 //////////////////////////////////////////////////////////////////// 02142 void GeomVertexDataPipelineReader:: 02143 make_array_readers() { 02144 nassertv(!_got_array_readers); 02145 02146 _array_readers.reserve(_cdata->_arrays.size()); 02147 GeomVertexData::Arrays::const_iterator ai; 02148 for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { 02149 CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer(); 02150 _array_readers.push_back(array_obj->get_handle(_current_thread)); 02151 } 02152 02153 _got_array_readers = true; 02154 } 02155 02156 //////////////////////////////////////////////////////////////////// 02157 // Function: GeomVertexDataPipelineReader::delete_array_readers 02158 // Access: Private 02159 // Description: 02160 //////////////////////////////////////////////////////////////////// 02161 void GeomVertexDataPipelineReader:: 02162 delete_array_readers() { 02163 nassertv(_got_array_readers); 02164 02165 _array_readers.clear(); 02166 _got_array_readers = false; 02167 } 02168 02169 //////////////////////////////////////////////////////////////////// 02170 // Function: GeomVertexDataPipelineWriter::get_num_rows 02171 // Access: Published 02172 // Description: 02173 //////////////////////////////////////////////////////////////////// 02174 int GeomVertexDataPipelineWriter:: 02175 get_num_rows() const { 02176 nassertr(_cdata->_format->get_num_arrays() == (int)_cdata->_arrays.size(), 0); 02177 nassertr(_got_array_writers, 0); 02178 02179 if (_cdata->_format->get_num_arrays() == 0) { 02180 // No arrays means no rows. Weird but legal. 02181 return 0; 02182 } 02183 02184 // Look up the answer on the first array (since any array will do). 02185 int stride = _cdata->_format->get_array(0)->get_stride(); 02186 return _array_writers[0]->get_data_size_bytes() / stride; 02187 } 02188 02189 //////////////////////////////////////////////////////////////////// 02190 // Function: GeomVertexDataPipelineWriter::set_num_rows 02191 // Access: Public 02192 // Description: 02193 //////////////////////////////////////////////////////////////////// 02194 bool GeomVertexDataPipelineWriter:: 02195 set_num_rows(int n) { 02196 nassertr(_got_array_writers, false); 02197 nassertr(_cdata->_format->get_num_arrays() == (int)_cdata->_arrays.size(), false); 02198 02199 bool any_changed = false; 02200 02201 int color_array = -1; 02202 int orig_color_rows = -1; 02203 02204 for (size_t i = 0; i < _cdata->_arrays.size(); i++) { 02205 if (_array_writers[i]->get_num_rows() != n) { 02206 if (_array_writers[i]->get_object()->has_column(InternalName::get_color())) { 02207 color_array = i; 02208 orig_color_rows = _array_writers[i]->get_num_rows(); 02209 } 02210 _array_writers[i]->set_num_rows(n); 02211 any_changed = true; 02212 } 02213 } 02214 02215 if (color_array >= 0 && orig_color_rows < n) { 02216 // We have just added some rows; fill the "color" column with 02217 // (1, 1, 1, 1), for the programmer's convenience. 02218 GeomVertexArrayDataHandle *array_writer = _array_writers[color_array]; 02219 const GeomVertexArrayFormat *array_format = array_writer->get_array_format(); 02220 const GeomVertexColumn *column = 02221 array_format->get_column(InternalName::get_color()); 02222 int stride = array_format->get_stride(); 02223 unsigned char *start = 02224 array_writer->get_write_pointer() + column->get_start(); 02225 unsigned char *stop = start + array_writer->get_data_size_bytes(); 02226 unsigned char *pointer = start + stride * orig_color_rows; 02227 int num_values = column->get_num_values(); 02228 02229 switch (column->get_numeric_type()) { 02230 case NT_packed_dcba: 02231 case NT_packed_dabc: 02232 case NT_uint8: 02233 case NT_uint16: 02234 case NT_uint32: 02235 while (pointer < stop) { 02236 memset(pointer, 0xff, column->get_total_bytes()); 02237 pointer += stride; 02238 } 02239 break; 02240 02241 case NT_float32: 02242 while (pointer < stop) { 02243 PN_float32 *pi = (PN_float32 *)pointer; 02244 for (int i = 0; i < num_values; i++) { 02245 pi[i] = 1.0f; 02246 } 02247 pointer += stride; 02248 } 02249 break; 02250 } 02251 } 02252 02253 if (any_changed) { 02254 _object->clear_cache_stage(); 02255 _cdata->_modified = Geom::get_next_modified(); 02256 _cdata->_animated_vertices.clear(); 02257 } 02258 02259 return any_changed; 02260 } 02261 02262 //////////////////////////////////////////////////////////////////// 02263 // Function: GeomVertexDataPipelineWriter::unclean_set_num_rows 02264 // Access: Public 02265 // Description: 02266 //////////////////////////////////////////////////////////////////// 02267 bool GeomVertexDataPipelineWriter:: 02268 unclean_set_num_rows(int n) { 02269 nassertr(_got_array_writers, false); 02270 nassertr(_cdata->_format->get_num_arrays() == (int)_cdata->_arrays.size(), false); 02271 02272 bool any_changed = false; 02273 02274 for (size_t i = 0; i < _cdata->_arrays.size(); i++) { 02275 if (_array_writers[i]->get_num_rows() != n) { 02276 _array_writers[i]->unclean_set_num_rows(n); 02277 any_changed = true; 02278 } 02279 } 02280 02281 if (any_changed) { 02282 _object->clear_cache_stage(); 02283 _cdata->_modified = Geom::get_next_modified(); 02284 _cdata->_animated_vertices.clear(); 02285 } 02286 02287 return any_changed; 02288 } 02289 02290 //////////////////////////////////////////////////////////////////// 02291 // Function: GeomVertexDataPipelineWriter::modify_array 02292 // Access: Public 02293 // Description: 02294 //////////////////////////////////////////////////////////////////// 02295 PT(GeomVertexArrayData) GeomVertexDataPipelineWriter:: 02296 modify_array(int i) { 02297 nassertr(i >= 0 && i < (int)_cdata->_arrays.size(), NULL); 02298 02299 PT(GeomVertexArrayData) new_data; 02300 if (_got_array_writers) { 02301 new_data = _array_writers[i]->get_object(); 02302 } else { 02303 new_data = _cdata->_arrays[i].get_write_pointer(); 02304 } 02305 02306 _object->clear_cache_stage(); 02307 _cdata->_modified = Geom::get_next_modified(); 02308 _cdata->_animated_vertices_modified = UpdateSeq(); 02309 02310 return new_data; 02311 } 02312 02313 //////////////////////////////////////////////////////////////////// 02314 // Function: GeomVertexDataPipelineWriter::set_array 02315 // Access: Public 02316 // Description: 02317 //////////////////////////////////////////////////////////////////// 02318 void GeomVertexDataPipelineWriter:: 02319 set_array(int i, const GeomVertexArrayData *array) { 02320 nassertv(i >= 0 && i < (int)_cdata->_arrays.size()); 02321 _cdata->_arrays[i] = (GeomVertexArrayData *)array; 02322 _object->clear_cache_stage(); 02323 _cdata->_modified = Geom::get_next_modified(); 02324 _cdata->_animated_vertices_modified = UpdateSeq(); 02325 02326 if (_got_array_writers) { 02327 _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread); 02328 } 02329 } 02330 02331 //////////////////////////////////////////////////////////////////// 02332 // Function: GeomVertexDataPipelineWriter::make_array_writers 02333 // Access: Private 02334 // Description: 02335 //////////////////////////////////////////////////////////////////// 02336 void GeomVertexDataPipelineWriter:: 02337 make_array_writers() { 02338 nassertv(!_got_array_writers); 02339 02340 _array_writers.reserve(_cdata->_arrays.size()); 02341 GeomVertexData::Arrays::iterator ai; 02342 for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { 02343 PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); 02344 _array_writers.push_back(array_obj->modify_handle(_current_thread)); 02345 } 02346 02347 _object->clear_cache_stage(); 02348 _cdata->_modified = Geom::get_next_modified(); 02349 _cdata->_animated_vertices_modified = UpdateSeq(); 02350 02351 _got_array_writers = true; 02352 } 02353 02354 //////////////////////////////////////////////////////////////////// 02355 // Function: GeomVertexDataPipelineWriter::delete_array_writers 02356 // Access: Private 02357 // Description: 02358 //////////////////////////////////////////////////////////////////// 02359 void GeomVertexDataPipelineWriter:: 02360 delete_array_writers() { 02361 nassertv(_got_array_writers); 02362 02363 _array_writers.clear(); 02364 _got_array_writers = false; 02365 }