Panda3D

geomVertexArrayData.cxx

00001 // Filename: geomVertexArrayData.cxx
00002 // Created by:  drose (17Mar05)
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 "geomVertexArrayData.h"
00016 #include "geom.h"
00017 #include "preparedGraphicsObjects.h"
00018 #include "reversedNumericData.h"
00019 #include "bamReader.h"
00020 #include "bamWriter.h"
00021 #include "pset.h"
00022 #include "config_gobj.h"
00023 #include "pStatTimer.h"
00024 #include "configVariableInt.h"
00025 #include "simpleAllocator.h"
00026 #include "vertexDataBuffer.h"
00027 
00028 ConfigVariableInt max_independent_vertex_data
00029 ("max-independent-vertex-data", -1,
00030  PRC_DESC("Specifies the maximum number of bytes of all vertex data "
00031           "that is independent of the paging system.  This is an "
00032           "initial buffer before max-ram-vertex-data, specifically "
00033           "designed for vertex datas that are dynamic in nature and "
00034           "may change size or be created and destroyed frequently."));
00035 
00036 ConfigVariableInt vertex_data_page_size
00037 ("vertex-data-page-size", 262144,
00038  PRC_DESC("The number of bytes to allocate at a time for vertex data.  "
00039           "This also controls the page size that is compressed or written "
00040           "to disk when vertex data pages are evicted from memory."));
00041 
00042 SimpleLru GeomVertexArrayData::_independent_lru("independent", max_independent_vertex_data);
00043 SimpleLru GeomVertexArrayData::_small_lru("small", max_independent_vertex_data);
00044 
00045 VertexDataBook GeomVertexArrayData::_book(vertex_data_page_size);
00046 
00047 
00048 TypeHandle GeomVertexArrayData::_type_handle;
00049 TypeHandle GeomVertexArrayData::CData::_type_handle;
00050 TypeHandle GeomVertexArrayDataHandle::_type_handle;
00051 
00052 ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle);
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: GeomVertexArrayData::Default Constructor
00056 //       Access: Private
00057 //  Description: Constructs an invalid object.  This is only used when
00058 //               reading from the bam file.
00059 ////////////////////////////////////////////////////////////////////
00060 GeomVertexArrayData::
00061 GeomVertexArrayData() : SimpleLruPage(0) {
00062   _contexts = NULL;
00063 
00064   // Can't put it in the LRU until it has been read in and made valid.
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: GeomVertexArrayData::make_cow_copy
00069 //       Access: Protected, Virtual
00070 //  Description: Required to implement CopyOnWriteObject.
00071 ////////////////////////////////////////////////////////////////////
00072 PT(CopyOnWriteObject) GeomVertexArrayData::
00073 make_cow_copy() {
00074   return new GeomVertexArrayData(*this);
00075 }
00076 
00077 ////////////////////////////////////////////////////////////////////
00078 //     Function: GeomVertexArrayData::Constructor
00079 //       Access: Published
00080 //  Description: 
00081 ////////////////////////////////////////////////////////////////////
00082 GeomVertexArrayData::
00083 GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
00084                     GeomVertexArrayData::UsageHint usage_hint) :
00085   SimpleLruPage(0),
00086   _array_format(array_format)
00087 {
00088   OPEN_ITERATE_ALL_STAGES(_cycler) {
00089     CDStageWriter cdata(_cycler, pipeline_stage);
00090     cdata->_usage_hint = usage_hint;
00091   }
00092   CLOSE_ITERATE_ALL_STAGES(_cycler);
00093 
00094   _contexts = NULL;
00095 
00096   set_lru_size(0);
00097   nassertv(_array_format->is_registered());
00098 }
00099   
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: GeomVertexArrayData::Copy Constructor
00102 //       Access: Published
00103 //  Description: 
00104 ////////////////////////////////////////////////////////////////////
00105 GeomVertexArrayData::
00106 GeomVertexArrayData(const GeomVertexArrayData &copy) :
00107   CopyOnWriteObject(copy),
00108   SimpleLruPage(copy),
00109   _array_format(copy._array_format),
00110   _cycler(copy._cycler)
00111 {
00112   _contexts = NULL;
00113 
00114   copy.mark_used_lru();
00115 
00116   set_lru_size(get_data_size_bytes());
00117   nassertv(_array_format->is_registered());
00118 }
00119 
00120 ////////////////////////////////////////////////////////////////////
00121 //     Function: GeomVertexArrayData::Copy Assignment Operator
00122 //       Access: Published
00123 //  Description: The copy assignment operator is not pipeline-safe.
00124 //               This will completely obliterate all stages of the
00125 //               pipeline, so don't do it for a GeomVertexArrayData
00126 //               that is actively being used for rendering.
00127 ////////////////////////////////////////////////////////////////////
00128 void GeomVertexArrayData::
00129 operator = (const GeomVertexArrayData &copy) {
00130   CopyOnWriteObject::operator = (copy);
00131   SimpleLruPage::operator = (copy);
00132 
00133   copy.mark_used_lru();
00134 
00135   _array_format = copy._array_format;
00136   _cycler = copy._cycler;
00137 
00138   OPEN_ITERATE_ALL_STAGES(_cycler) {
00139     CDStageWriter cdata(_cycler, pipeline_stage);
00140     cdata->_modified = Geom::get_next_modified();
00141   }
00142   CLOSE_ITERATE_ALL_STAGES(_cycler);
00143 
00144   nassertv(_array_format->is_registered());
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: GeomVertexArrayData::Destructor
00149 //       Access: Published, Virtual
00150 //  Description: 
00151 ////////////////////////////////////////////////////////////////////
00152 GeomVertexArrayData::
00153 ~GeomVertexArrayData() {
00154   release_all();
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: GeomVertexArrayData::compare_to
00159 //       Access: Published
00160 //  Description: Returns 0 if the two arrays are equivalent, even if
00161 //               they are not the same pointer.
00162 ////////////////////////////////////////////////////////////////////
00163 int GeomVertexArrayData::
00164 compare_to(const GeomVertexArrayData &other) const {
00165   Thread *current_thread = Thread::get_current_thread();
00166 
00167   CPT(GeomVertexArrayDataHandle) handle = get_handle(current_thread);
00168   CPT(GeomVertexArrayDataHandle) other_handle = other.get_handle(current_thread);
00169 
00170   if (handle->get_usage_hint() != other_handle->get_usage_hint()) {
00171     return (int)handle->get_usage_hint() - (int)other_handle->get_usage_hint();
00172   }
00173   if (handle->get_array_format() != other_handle->get_array_format()) {
00174     return handle->get_array_format() < other_handle->get_array_format() ? -1 : 1;
00175   }
00176   if (handle->get_data_size_bytes() != other_handle->get_data_size_bytes()) {
00177     return (int)handle->get_data_size_bytes() - (int)other_handle->get_data_size_bytes();
00178   }
00179   return memcmp(handle->get_read_pointer(true), 
00180                 other_handle->get_read_pointer(true),
00181                 handle->get_data_size_bytes());
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: GeomVertexArrayData::set_usage_hint
00186 //       Access: Published
00187 //  Description: Changes the UsageHint hint for this array.  See
00188 //               get_usage_hint().
00189 //
00190 //               Don't call this in a downstream thread unless you
00191 //               don't mind it blowing away other changes you might
00192 //               have recently made in an upstream thread.
00193 ////////////////////////////////////////////////////////////////////
00194 void GeomVertexArrayData::
00195 set_usage_hint(GeomVertexArrayData::UsageHint usage_hint) {
00196   CDWriter cdata(_cycler, true);
00197   cdata->_usage_hint = usage_hint;
00198   cdata->_modified = Geom::get_next_modified();
00199 }
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 //     Function: GeomVertexArrayData::output
00203 //       Access: Published
00204 //  Description: 
00205 ////////////////////////////////////////////////////////////////////
00206 void GeomVertexArrayData::
00207 output(ostream &out) const {
00208   out << get_num_rows() << " rows: " << *get_array_format();
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: GeomVertexArrayData::write
00213 //       Access: Published
00214 //  Description: 
00215 ////////////////////////////////////////////////////////////////////
00216 void GeomVertexArrayData::
00217 write(ostream &out, int indent_level) const {
00218   _array_format->write_with_data(out, indent_level, this);
00219 }
00220 
00221 ////////////////////////////////////////////////////////////////////
00222 //     Function: GeomVertexArrayData::prepare
00223 //       Access: Public
00224 //  Description: Indicates that the data should be enqueued to be
00225 //               prepared in the indicated prepared_objects at the
00226 //               beginning of the next frame.  This will ensure the
00227 //               data is already loaded into the GSG if it is expected
00228 //               to be rendered soon.
00229 //
00230 //               Use this function instead of prepare_now() to preload
00231 //               datas from a user interface standpoint.
00232 ////////////////////////////////////////////////////////////////////
00233 void GeomVertexArrayData::
00234 prepare(PreparedGraphicsObjects *prepared_objects) {
00235   prepared_objects->enqueue_vertex_buffer(this);
00236 }
00237 
00238 ////////////////////////////////////////////////////////////////////
00239 //     Function: GeomVertexArrayData::is_prepared
00240 //       Access: Published
00241 //  Description: Returns true if the data has already been prepared
00242 //               or enqueued for preparation on the indicated GSG,
00243 //               false otherwise.
00244 ////////////////////////////////////////////////////////////////////
00245 bool GeomVertexArrayData::
00246 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
00247   if (_contexts == (Contexts *)NULL) {
00248     return false;
00249   }
00250   Contexts::const_iterator ci;
00251   ci = _contexts->find(prepared_objects);
00252   if (ci != _contexts->end()) {
00253     return true;
00254   }
00255   return prepared_objects->is_vertex_buffer_queued(this);
00256 }
00257 
00258 ////////////////////////////////////////////////////////////////////
00259 //     Function: GeomVertexArrayData::prepare_now
00260 //       Access: Public
00261 //  Description: Creates a context for the data on the particular
00262 //               GSG, if it does not already exist.  Returns the new
00263 //               (or old) VertexBufferContext.  This assumes that the
00264 //               GraphicsStateGuardian is the currently active
00265 //               rendering context and that it is ready to accept new
00266 //               datas.  If this is not necessarily the case, you
00267 //               should use prepare() instead.
00268 //
00269 //               Normally, this is not called directly except by the
00270 //               GraphicsStateGuardian; a data does not need to be
00271 //               explicitly prepared by the user before it may be
00272 //               rendered.
00273 ////////////////////////////////////////////////////////////////////
00274 VertexBufferContext *GeomVertexArrayData::
00275 prepare_now(PreparedGraphicsObjects *prepared_objects, 
00276             GraphicsStateGuardianBase *gsg) {
00277   if (_contexts == (Contexts *)NULL) {
00278     _contexts = new Contexts;
00279   }
00280   Contexts::const_iterator ci;
00281   ci = _contexts->find(prepared_objects);
00282   if (ci != _contexts->end()) {
00283     return (*ci).second;
00284   }
00285 
00286   VertexBufferContext *vbc = prepared_objects->prepare_vertex_buffer_now(this, gsg);
00287   if (vbc != (VertexBufferContext *)NULL) {
00288     (*_contexts)[prepared_objects] = vbc;
00289   }
00290   return vbc;
00291 }
00292 
00293 ////////////////////////////////////////////////////////////////////
00294 //     Function: GeomVertexArrayData::release
00295 //       Access: Public
00296 //  Description: Frees the data context only on the indicated object,
00297 //               if it exists there.  Returns true if it was released,
00298 //               false if it had not been prepared.
00299 ////////////////////////////////////////////////////////////////////
00300 bool GeomVertexArrayData::
00301 release(PreparedGraphicsObjects *prepared_objects) {
00302   if (_contexts != (Contexts *)NULL) {
00303     Contexts::iterator ci;
00304     ci = _contexts->find(prepared_objects);
00305     if (ci != _contexts->end()) {
00306       VertexBufferContext *vbc = (*ci).second;
00307       prepared_objects->release_vertex_buffer(vbc);
00308       return true;
00309     }
00310   }
00311 
00312   // Maybe it wasn't prepared yet, but it's about to be.
00313   return prepared_objects->dequeue_vertex_buffer(this);
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: GeomVertexArrayData::release_all
00318 //       Access: Public
00319 //  Description: Frees the context allocated on all objects for which
00320 //               the data has been declared.  Returns the number of
00321 //               contexts which have been freed.
00322 ////////////////////////////////////////////////////////////////////
00323 int GeomVertexArrayData::
00324 release_all() {
00325   int num_freed = 0;
00326 
00327   if (_contexts != (Contexts *)NULL) {
00328     // We have to traverse a copy of the _contexts list, because the
00329     // PreparedGraphicsObjects object will call clear_prepared() in response
00330     // to each release_vertex_buffer(), and we don't want to be modifying the
00331     // _contexts list while we're traversing it.
00332     Contexts temp = *_contexts;
00333     num_freed = (int)_contexts->size();
00334     
00335     Contexts::const_iterator ci;
00336     for (ci = temp.begin(); ci != temp.end(); ++ci) {
00337       PreparedGraphicsObjects *prepared_objects = (*ci).first;
00338       VertexBufferContext *vbc = (*ci).second;
00339       prepared_objects->release_vertex_buffer(vbc);
00340     }
00341     
00342     // Now that we've called release_vertex_buffer() on every known context,
00343     // the _contexts list should have completely emptied itself.
00344     nassertr(_contexts == NULL, num_freed);
00345   }
00346 
00347   return num_freed;
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: GeomVertexArrayData::lru_epoch
00352 //       Access: Published, Static
00353 //  Description: Marks that an epoch has passed in each LRU.  Asks the
00354 //               LRU's to consider whether they should perform
00355 //               evictions.
00356 ////////////////////////////////////////////////////////////////////
00357 void GeomVertexArrayData::
00358 lru_epoch() {
00359   _independent_lru.begin_epoch();
00360   VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->begin_epoch();
00361   VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->begin_epoch();
00362 }
00363 
00364 ////////////////////////////////////////////////////////////////////
00365 //     Function: GeomVertexArrayData::evict_lru
00366 //       Access: Public, Virtual
00367 //  Description: Evicts the page from the LRU.  Called internally when
00368 //               the LRU determines that it is full.  May also be
00369 //               called externally when necessary to explicitly evict
00370 //               the page.
00371 //
00372 //               It is legal for this method to either evict the page
00373 //               as requested, do nothing (in which case the eviction
00374 //               will be requested again at the next epoch), or
00375 //               requeue itself on the tail of the queue (in which
00376 //               case the eviction will be requested again much
00377 //               later).
00378 ////////////////////////////////////////////////////////////////////
00379 void GeomVertexArrayData::
00380 evict_lru() {
00381   dequeue_lru();
00382   CDWriter cdata(_cycler, true);
00383   cdata->_buffer.page_out(_book);
00384 }
00385 
00386 ////////////////////////////////////////////////////////////////////
00387 //     Function: GeomVertexArrayData::clear_prepared
00388 //       Access: Private
00389 //  Description: Removes the indicated PreparedGraphicsObjects table
00390 //               from the data array's table, without actually
00391 //               releasing the data array.  This is intended to be
00392 //               called only from
00393 //               PreparedGraphicsObjects::release_vertex_buffer(); it should
00394 //               never be called by user code.
00395 ////////////////////////////////////////////////////////////////////
00396 void GeomVertexArrayData::
00397 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
00398   nassertv(_contexts != (Contexts *)NULL);
00399 
00400   Contexts::iterator ci;
00401   ci = _contexts->find(prepared_objects);
00402   if (ci != _contexts->end()) {
00403     _contexts->erase(ci);
00404     if (_contexts->empty()) {
00405       delete _contexts;
00406       _contexts = NULL;
00407     }
00408   } else {
00409     // If this assertion fails, clear_prepared() was given a
00410     // prepared_objects which the data array didn't know about.
00411     nassertv(false);
00412   }
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: GeomVertexArrayData::reverse_data_endianness
00417 //       Access: Private
00418 //  Description: Fills a new data array with all numeric values
00419 //               expressed in the indicated array reversed,
00420 //               byte-for-byte, to convert littleendian to bigendian
00421 //               and vice-versa.
00422 ////////////////////////////////////////////////////////////////////
00423 void GeomVertexArrayData::
00424 reverse_data_endianness(unsigned char *dest, const unsigned char *source, 
00425                         size_t size) {
00426   int num_columns = _array_format->get_num_columns();
00427 
00428   // Walk through each row of the data.
00429   for (size_t pi = 0; pi < size; pi += _array_format->get_stride()) {
00430     // For each row, visit all of the columns; and for each column,
00431     // visit all of the components of that column.
00432     for (int ci = 0; ci < num_columns; ++ci) {
00433       const GeomVertexColumn *col = _array_format->get_column(ci);
00434       int component_bytes = col->get_component_bytes();
00435       if (component_bytes > 1) {
00436         // Get the index of the beginning of the column.
00437         size_t ci = pi + col->get_start();
00438 
00439         int num_components = col->get_num_components();
00440         for (int cj = 0; cj < num_components; ++cj) {
00441           // Reverse the bytes of each component.
00442           ReversedNumericData nd(source + ci, component_bytes);
00443           nd.store_value(dest + ci, component_bytes);
00444           ci += component_bytes;
00445         }
00446       }
00447     }
00448   }
00449 }
00450 
00451 ////////////////////////////////////////////////////////////////////
00452 //     Function: GeomVertexArrayData::register_with_read_factory
00453 //       Access: Public, Static
00454 //  Description: Tells the BamReader how to create objects of type
00455 //               GeomVertexArrayData.
00456 ////////////////////////////////////////////////////////////////////
00457 void GeomVertexArrayData::
00458 register_with_read_factory() {
00459   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00460 }
00461 
00462 ////////////////////////////////////////////////////////////////////
00463 //     Function: GeomVertexArrayData::write_datagram
00464 //       Access: Public, Virtual
00465 //  Description: Writes the contents of this object to the datagram
00466 //               for shipping out to a Bam file.
00467 ////////////////////////////////////////////////////////////////////
00468 void GeomVertexArrayData::
00469 write_datagram(BamWriter *manager, Datagram &dg) {
00470   CopyOnWriteObject::write_datagram(manager, dg);
00471 
00472   manager->write_pointer(dg, _array_format);
00473   manager->write_cdata(dg, _cycler, this);
00474 }
00475 
00476 ////////////////////////////////////////////////////////////////////
00477 //     Function: GeomVertexArrayData::read_raw_data
00478 //       Access: Public
00479 //  Description: Called by CData::fillin to read the raw data
00480 //               of the array from the indicated datagram.
00481 ////////////////////////////////////////////////////////////////////
00482 PTA_uchar GeomVertexArrayData::
00483 read_raw_data(BamReader *manager, DatagramIterator &scan) {
00484   size_t size = scan.get_uint32();
00485   PTA_uchar data = PTA_uchar::empty_array(size, get_class_type());
00486   const unsigned char *source_data = 
00487     (const unsigned char *)scan.get_datagram().get_data();
00488   memcpy(data, source_data + scan.get_current_index(), size);
00489   scan.skip_bytes(size);
00490 
00491   return data;
00492 }
00493 
00494 ////////////////////////////////////////////////////////////////////
00495 //     Function: GeomVertexArrayData::complete_pointers
00496 //       Access: Public, Virtual
00497 //  Description: Receives an array of pointers, one for each time
00498 //               manager->read_pointer() was called in fillin().
00499 //               Returns the number of pointers processed.
00500 ////////////////////////////////////////////////////////////////////
00501 int GeomVertexArrayData::
00502 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00503   int pi = CopyOnWriteObject::complete_pointers(p_list, manager);
00504 
00505   _array_format = DCAST(GeomVertexArrayFormat, p_list[pi++]);
00506 
00507   return pi;
00508 }
00509 
00510 ////////////////////////////////////////////////////////////////////
00511 //     Function: GeomVertexArrayData::finalize
00512 //       Access: Public, Virtual
00513 //  Description: Called by the BamReader to perform any final actions
00514 //               needed for setting up the object after all objects
00515 //               have been read and all pointers have been completed.
00516 ////////////////////////////////////////////////////////////////////
00517 void GeomVertexArrayData::
00518 finalize(BamReader *manager) {
00519   // Now we need to register the format that we have read from the bam
00520   // file (since it doesn't come out of the bam file automatically
00521   // registered).  This may change the format's pointer, which we
00522   // should then update our own data to reflect.  But since this may
00523   // cause the unregistered object to destruct, we have to also tell
00524   // the BamReader to return the new object from now on.
00525 
00526   CDWriter cdata(_cycler, true);
00527 
00528   CPT(GeomVertexArrayFormat) new_array_format = 
00529     GeomVertexArrayFormat::register_format(_array_format);
00530 
00531   manager->change_pointer(_array_format, new_array_format);
00532   _array_format = new_array_format;
00533 
00534   PT(BamAuxData) aux_data = (BamAuxData *)manager->get_aux_data(this, "");
00535   if (aux_data != (BamAuxData *)NULL) {
00536     if (aux_data->_endian_reversed) {
00537       // Now is the time to endian-reverse the data.
00538       VertexDataBuffer new_buffer(cdata->_buffer.get_size());
00539       reverse_data_endianness(new_buffer.get_write_pointer(), cdata->_buffer.get_read_pointer(true), cdata->_buffer.get_size());
00540       cdata->_buffer.swap(new_buffer);
00541     }
00542   }
00543 
00544   set_lru_size(cdata->_buffer.get_size());
00545 }
00546 
00547 ////////////////////////////////////////////////////////////////////
00548 //     Function: GeomVertexArrayData::make_from_bam
00549 //       Access: Protected, Static
00550 //  Description: This function is called by the BamReader's factory
00551 //               when a new object of type GeomVertexArrayData is encountered
00552 //               in the Bam file.  It should create the GeomVertexArrayData
00553 //               and extract its information from the file.
00554 ////////////////////////////////////////////////////////////////////
00555 TypedWritable *GeomVertexArrayData::
00556 make_from_bam(const FactoryParams &params) {
00557   GeomVertexArrayData *object = new GeomVertexArrayData;
00558   DatagramIterator scan;
00559   BamReader *manager;
00560 
00561   parse_params(params, scan, manager);
00562   object->fillin(scan, manager);
00563   manager->register_finalize(object);
00564 
00565   return object;
00566 }
00567 
00568 ////////////////////////////////////////////////////////////////////
00569 //     Function: GeomVertexArrayData::fillin
00570 //       Access: Protected
00571 //  Description: This internal function is called by make_from_bam to
00572 //               read in all of the relevant data from the BamFile for
00573 //               the new GeomVertexArrayData.
00574 ////////////////////////////////////////////////////////////////////
00575 void GeomVertexArrayData::
00576 fillin(DatagramIterator &scan, BamReader *manager) {
00577   CopyOnWriteObject::fillin(scan, manager);
00578 
00579   manager->read_pointer(scan);
00580   manager->read_cdata(scan, _cycler, this);
00581 }
00582 
00583 ////////////////////////////////////////////////////////////////////
00584 //     Function: GeomVertexArrayData::CData::Destructor
00585 //       Access: Public, Virtual
00586 //  Description:
00587 ////////////////////////////////////////////////////////////////////
00588 GeomVertexArrayData::CData::
00589 ~CData() {
00590 }
00591 
00592 ////////////////////////////////////////////////////////////////////
00593 //     Function: GeomVertexArrayData::CData::make_copy
00594 //       Access: Public, Virtual
00595 //  Description:
00596 ////////////////////////////////////////////////////////////////////
00597 CycleData *GeomVertexArrayData::CData::
00598 make_copy() const {
00599   return new CData(*this);
00600 }
00601 
00602 ////////////////////////////////////////////////////////////////////
00603 //     Function: GeomVertexArrayData::CData::write_datagram
00604 //       Access: Public, Virtual
00605 //  Description: Writes the contents of this object to the datagram
00606 //               for shipping out to a Bam file.
00607 ////////////////////////////////////////////////////////////////////
00608 void GeomVertexArrayData::CData::
00609 write_datagram(BamWriter *manager, Datagram &dg, void *extra_data) const {
00610   GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
00611   dg.add_uint8(_usage_hint);
00612 
00613   dg.add_uint32(_buffer.get_size());
00614 
00615   if (manager->get_file_endian() == BamWriter::BE_native) {
00616     // For native endianness, we only have to write the data directly.
00617     dg.append_data(_buffer.get_read_pointer(true), _buffer.get_size());
00618 
00619   } else {
00620     // Otherwise, we have to convert it.
00621     unsigned char *new_data = (unsigned char *)alloca(_buffer.get_size());
00622     array_data->reverse_data_endianness(new_data, _buffer.get_read_pointer(true), _buffer.get_size());
00623     dg.append_data(new_data, _buffer.get_size());
00624   }
00625 }
00626 
00627 ////////////////////////////////////////////////////////////////////
00628 //     Function: GeomVertexArrayData::CData::fillin
00629 //       Access: Public, Virtual
00630 //  Description: This internal function is called by make_from_bam to
00631 //               read in all of the relevant data from the BamFile for
00632 //               the new GeomVertexArrayData.
00633 ////////////////////////////////////////////////////////////////////
00634 void GeomVertexArrayData::CData::
00635 fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
00636   GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
00637   _usage_hint = (UsageHint)scan.get_uint8();
00638 
00639   if (manager->get_file_minor_ver() < 8) {
00640     // Before bam version 6.8, the array data was a PTA_uchar.
00641     PTA_uchar new_data;
00642     READ_PTA(manager, scan, array_data->read_raw_data, new_data);
00643     _buffer.unclean_realloc(new_data.size());
00644     memcpy(_buffer.get_write_pointer(), &new_data[0], new_data.size());
00645 
00646   } else {
00647     // Now, the array data is just stored directly.
00648     size_t size = scan.get_uint32();
00649     _buffer.unclean_realloc(size);
00650 
00651     const unsigned char *source_data = 
00652       (const unsigned char *)scan.get_datagram().get_data();
00653     memcpy(_buffer.get_write_pointer(), source_data + scan.get_current_index(), size);
00654     scan.skip_bytes(size);
00655   }
00656 
00657   bool endian_reversed = false;
00658 
00659   if (manager->get_file_endian() != BamReader::BE_native) {
00660     // For non-native endian files, we have to convert the data.  
00661 
00662     if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) {
00663       // But we can't do that until we've completed the _array_format
00664       // pointer, which tells us how to convert it.
00665       endian_reversed = true;
00666     } else {
00667       // Since we have the _array_format pointer now, we can reverse
00668       // it immediately (and we should, to support threaded CData
00669       // updates).
00670       VertexDataBuffer new_buffer(_buffer.get_size());
00671       array_data->reverse_data_endianness(new_buffer.get_write_pointer(), _buffer.get_read_pointer(true), _buffer.get_size());
00672       _buffer.swap(new_buffer);
00673     }
00674   }
00675 
00676   if (endian_reversed) {
00677     PT(BamAuxData) aux_data = new BamAuxData;
00678     aux_data->_endian_reversed = endian_reversed;
00679     manager->set_aux_data(array_data, "", aux_data);
00680   }
00681 
00682   array_data->set_lru_size(_buffer.get_size());
00683 
00684   _modified = Geom::get_next_modified();
00685 }
00686 
00687 ////////////////////////////////////////////////////////////////////
00688 //     Function: GeomVertexArrayDataHandle::get_write_pointer
00689 //       Access: Public
00690 //  Description: Returns a writable pointer to the beginning of the
00691 //               actual data stream.
00692 ////////////////////////////////////////////////////////////////////
00693 unsigned char *GeomVertexArrayDataHandle::
00694 get_write_pointer() {
00695   nassertr(_writable, NULL);
00696   mark_used();
00697   _cdata->_modified = Geom::get_next_modified();
00698   return _cdata->_buffer.get_write_pointer();
00699 }
00700 
00701 ////////////////////////////////////////////////////////////////////
00702 //     Function: GeomVertexArrayDataHandle::set_num_rows
00703 //       Access: Public
00704 //  Description: 
00705 ////////////////////////////////////////////////////////////////////
00706 bool GeomVertexArrayDataHandle::
00707 set_num_rows(int n) {
00708   nassertr(_writable, false);
00709   mark_used();
00710 
00711   int stride = _object->_array_format->get_stride();
00712   size_t new_size = n * stride;
00713   size_t orig_size = _cdata->_buffer.get_size();
00714 
00715   if (new_size != orig_size) {
00716     _cdata->_buffer.clean_realloc(new_size);
00717 
00718     // Now ensure that the newly-added rows are initialized to 0.
00719     if (new_size > orig_size) {
00720       memset(_cdata->_buffer.get_write_pointer() + orig_size, 0,
00721              new_size - orig_size);
00722     }
00723 
00724     _cdata->_modified = Geom::get_next_modified();
00725 
00726     if (get_current_thread()->get_pipeline_stage() == 0) {
00727       _object->set_lru_size(_cdata->_buffer.get_size());
00728     }
00729     return true;
00730   }
00731   
00732   return false;
00733 }
00734 
00735 ////////////////////////////////////////////////////////////////////
00736 //     Function: GeomVertexArrayDataHandle::unclean_set_num_rows
00737 //       Access: Public
00738 //  Description: 
00739 ////////////////////////////////////////////////////////////////////
00740 bool GeomVertexArrayDataHandle::
00741 unclean_set_num_rows(int n) {
00742   nassertr(_writable, false);
00743   mark_used();
00744 
00745   int stride = _object->_array_format->get_stride();
00746   size_t new_size = n * stride;
00747   size_t orig_size = _cdata->_buffer.get_size();
00748 
00749   if (new_size != orig_size) {
00750     _cdata->_buffer.unclean_realloc(new_size);
00751     // No need to fill to zero or copy the old buffer, since this is
00752     // unclean_set_num_rows().
00753 
00754     _cdata->_modified = Geom::get_next_modified();
00755 
00756     if (get_current_thread()->get_pipeline_stage() == 0) {
00757       _object->set_lru_size(_cdata->_buffer.get_size());
00758     }
00759     return true;
00760   }
00761   
00762   return false;
00763 }
00764 
00765 ////////////////////////////////////////////////////////////////////
00766 //     Function: GeomVertexArrayDataHandle::copy_data_from
00767 //       Access: Public
00768 //  Description: Copies the entire data array from the other object.
00769 ////////////////////////////////////////////////////////////////////
00770 void GeomVertexArrayDataHandle::
00771 copy_data_from(const GeomVertexArrayDataHandle *other) {
00772   nassertv(_writable);
00773   mark_used();
00774   other->mark_used();
00775 
00776   _cdata->_buffer.unclean_realloc(other->_cdata->_buffer.get_size());
00777 
00778   unsigned char *dest = _cdata->_buffer.get_write_pointer();
00779   const unsigned char *source = other->_cdata->_buffer.get_read_pointer(true);
00780   size_t size = other->_cdata->_buffer.get_size();
00781   memcpy(dest, source, size);
00782 
00783   _cdata->_modified = Geom::get_next_modified();
00784 
00785   if (get_current_thread()->get_pipeline_stage() == 0) {
00786     _object->set_lru_size(_cdata->_buffer.get_size());
00787   }
00788 }
00789 
00790 ////////////////////////////////////////////////////////////////////
00791 //     Function: GeomVertexArrayDataHandle::copy_subdata_from
00792 //       Access: Public
00793 //  Description: Copies a portion of the data array from the other
00794 //               object into a portion of the data array of this
00795 //               object.  If to_size != from_size, the size of this
00796 //               data array is adjusted accordingly.
00797 ////////////////////////////////////////////////////////////////////
00798 void GeomVertexArrayDataHandle::
00799 copy_subdata_from(size_t to_start, size_t to_size,
00800                   const GeomVertexArrayDataHandle *other,
00801                   size_t from_start, size_t from_size) {
00802   nassertv(_writable);
00803   mark_used();
00804   other->mark_used();
00805 
00806   VertexDataBuffer &to_buffer = _cdata->_buffer;
00807   size_t to_buffer_orig_size = to_buffer.get_size();
00808   to_start = min(to_start, to_buffer_orig_size);
00809   to_size = min(to_size, to_buffer_orig_size - to_start);
00810 
00811   const VertexDataBuffer &from_buffer = other->_cdata->_buffer;
00812   size_t from_buffer_orig_size = from_buffer.get_size();
00813   from_start = min(from_start, from_buffer_orig_size);
00814   from_size = min(from_size, from_buffer_orig_size - from_start);
00815 
00816   if (from_size < to_size) {
00817     // Reduce the array.
00818     unsigned char *pointer = to_buffer.get_write_pointer();
00819     memmove(pointer + to_start + to_size, 
00820             pointer + to_start + from_size,
00821             to_buffer_orig_size - (to_start + to_size));
00822     to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
00823 
00824   } else if (to_size < from_size) {
00825     // Expand the array.
00826     to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
00827     unsigned char *pointer = to_buffer.get_write_pointer();
00828     memmove(pointer + to_start + to_size, 
00829             pointer + to_start + from_size,
00830             to_buffer_orig_size - (to_start + to_size));
00831   }
00832 
00833   // Now copy the data.
00834   memcpy(to_buffer.get_write_pointer() + to_start, 
00835          other->get_read_pointer(true) + from_start, 
00836          from_size);
00837   _cdata->_modified = Geom::get_next_modified();
00838 
00839   if (get_current_thread()->get_pipeline_stage() == 0) {
00840     _object->set_lru_size(_cdata->_buffer.get_size());
00841   }
00842 }
00843 
00844 ////////////////////////////////////////////////////////////////////
00845 //     Function: GeomVertexArrayDataHandle::set_data
00846 //       Access: Public
00847 //  Description: Replaces the entire raw data array with the contents
00848 //               of the indicated string.  This is primarily for the
00849 //               benefit of high-level languages like Python.
00850 ////////////////////////////////////////////////////////////////////
00851 void GeomVertexArrayDataHandle::
00852 set_data(const string &data) {
00853   nassertv(_writable);
00854   mark_used();
00855 
00856   _cdata->_buffer.unclean_realloc(data.size());
00857   memcpy(_cdata->_buffer.get_write_pointer(), data.data(), data.size());
00858 
00859   _cdata->_modified = Geom::get_next_modified();
00860 
00861   if (get_current_thread()->get_pipeline_stage() == 0) {
00862     _object->set_lru_size(_cdata->_buffer.get_size());
00863   }
00864 }
00865 
00866 ////////////////////////////////////////////////////////////////////
00867 //     Function: GeomVertexArrayDataHandle::set_subdata
00868 //       Access: Public
00869 //  Description: Replaces a portion of the data array from the
00870 //               indicated string.  If size != data.size(), the size
00871 //               of this data array is adjusted accordingly.
00872 //
00873 //               This is primarily for the benefit of high-level
00874 //               languages like Python.
00875 ////////////////////////////////////////////////////////////////////
00876 void GeomVertexArrayDataHandle::
00877 set_subdata(size_t start, size_t size, const string &data) {
00878   nassertv(_writable);
00879   mark_used();
00880 
00881   VertexDataBuffer &to_buffer = _cdata->_buffer;
00882   size_t to_buffer_orig_size = to_buffer.get_size();
00883   start = min(start, to_buffer_orig_size);
00884   size = min(size, to_buffer_orig_size - start);
00885   
00886   size_t from_size = data.size();
00887 
00888   if (from_size < size) {
00889     // Reduce the array.
00890     unsigned char *pointer = to_buffer.get_write_pointer();
00891     memmove(pointer + start + from_size, 
00892             pointer + start + size,
00893             to_buffer_orig_size - (start + size));
00894     to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
00895 
00896   } else if (size < from_size) {
00897     // Expand the array.
00898     to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
00899     unsigned char *pointer = to_buffer.get_write_pointer();
00900     memmove(pointer + start + from_size, 
00901             pointer + start + size,
00902             to_buffer_orig_size - (start + size));
00903   }
00904 
00905   // Now copy the data.
00906   memcpy(to_buffer.get_write_pointer() + start, data.data(), from_size);
00907   _cdata->_modified = Geom::get_next_modified();
00908 
00909   if (get_current_thread()->get_pipeline_stage() == 0) {
00910     _object->set_lru_size(_cdata->_buffer.get_size());
00911   }
00912 }
 All Classes Functions Variables Enumerations