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