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