Panda3D

geomVertexData.cxx

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