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