Panda3D
|
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 ©) : 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 ©) { 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 ¶ms) { 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 }