00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pandabase.h"
00016 #include "pnotify.h"
00017
00018 #include "typedWritable.h"
00019 #include "config_util.h"
00020 #include "bam.h"
00021 #include "bamWriter.h"
00022 #include "bamReader.h"
00023 #include "lightMutexHolder.h"
00024
00025 #include <algorithm>
00026
00027
00028
00029
00030
00031
00032 BamWriter::
00033 BamWriter(DatagramSink *target) :
00034 _target(target)
00035 {
00036 ++_writing_seq;
00037 _next_boc = BOC_adjunct;
00038 _needs_init = true;
00039
00040
00041
00042 _next_object_id = 1;
00043 _long_object_id = false;
00044 _next_pta_id = 1;
00045 _long_pta_id = false;
00046
00047 _file_endian = bam_endian;
00048 _file_stdfloat_double = bam_stdfloat_double;
00049 _file_texture_mode = bam_texture_mode;
00050 }
00051
00052
00053
00054
00055
00056
00057 BamWriter::
00058 ~BamWriter() {
00059
00060
00061 StateMap::iterator si;
00062 for (si = _state_map.begin(); si != _state_map.end(); ++si) {
00063 TypedWritable *object = (TypedWritable *)(*si).first;
00064 LightMutexHolder holder(TypedWritable::_bam_writers_lock);
00065 nassertv(object->_bam_writers != (TypedWritable::BamWriters *)NULL);
00066 TypedWritable::BamWriters::iterator wi =
00067 find(object->_bam_writers->begin(), object->_bam_writers->end(), this);
00068 nassertv(wi != object->_bam_writers->end());
00069 object->_bam_writers->erase(wi);
00070 }
00071 }
00072
00073
00074
00075
00076
00077
00078
00079
00080 void BamWriter::
00081 set_target(DatagramSink *target) {
00082 if (_target != NULL) {
00083 _target->flush();
00084 }
00085 _target = target;
00086
00087 if (_needs_init && _target != NULL) {
00088 init();
00089 }
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 bool BamWriter::
00103 init() {
00104 nassertr(_target != NULL, false);
00105 nassertr(_needs_init, false);
00106 _needs_init = false;
00107
00108
00109
00110 _next_object_id = 1;
00111 _long_object_id = false;
00112 _next_pta_id = 1;
00113 _long_pta_id = false;
00114
00115 _file_endian = bam_endian;
00116 _file_texture_mode = bam_texture_mode;
00117
00118
00119 Datagram header;
00120
00121 header.add_uint16(_bam_major_ver);
00122 header.add_uint16(_bam_minor_ver);
00123 header.add_uint8(_file_endian);
00124 header.add_bool(_file_stdfloat_double);
00125
00126 if (!_target->put_datagram(header)) {
00127 util_cat.error()
00128 << "Unable to write Bam header.\n";
00129 return false;
00130 }
00131 return true;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 bool BamWriter::
00157 write_object(const TypedWritable *object) {
00158 nassertr(_target != NULL, false);
00159
00160
00161
00162 ++_writing_seq;
00163
00164
00165 if (!_freed_object_ids.empty()) {
00166 Datagram dg;
00167 dg.add_uint8(BOC_remove);
00168
00169 FreedObjectIds::iterator fi;
00170 for (fi = _freed_object_ids.begin(); fi != _freed_object_ids.end(); ++fi) {
00171 write_object_id(dg, (*fi));
00172 }
00173 _freed_object_ids.clear();
00174
00175 if (!_target->put_datagram(dg)) {
00176 util_cat.error()
00177 << "Unable to write data to output.\n";
00178 return false;
00179 }
00180 }
00181
00182 nassertr(_object_queue.empty(), false);
00183 _next_boc = BOC_push;
00184
00185 int object_id = enqueue_object(object);
00186 nassertr(object_id != 0, false);
00187 if (!flush_queue()) {
00188 return false;
00189 }
00190
00191
00192 if (_next_boc != BOC_push) {
00193 Datagram dg;
00194 dg.add_uint8(BOC_pop);
00195 if (!_target->put_datagram(dg)) {
00196 util_cat.error()
00197 << "Unable to write data to output.\n";
00198 return false;
00199 }
00200 }
00201
00202 return true;
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212 bool BamWriter::
00213 has_object(const TypedWritable *object) const {
00214 StateMap::const_iterator si = _state_map.find(object);
00215 return (si != _state_map.end());
00216 }
00217
00218
00219
00220
00221
00222
00223
00224 void BamWriter::
00225 flush() {
00226 nassertv(_target != NULL);
00227 _target->flush();
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 void BamWriter::
00242 consider_update(const TypedWritable *object) {
00243 StateMap::iterator si = _state_map.find(object);
00244 if (si == _state_map.end()) {
00245
00246 enqueue_object(object);
00247
00248 } else if ((*si).second._written_seq.is_initial()) {
00249
00250 enqueue_object(object);
00251
00252 } else if ((*si).second._written_seq == _writing_seq) {
00253
00254
00255
00256 } else if ((*si).second._modified != object->get_bam_modified()) {
00257
00258 enqueue_object(object);
00259
00260 } else {
00261
00262 (*si).second._written_seq = _writing_seq;
00263
00264
00265 ((TypedWritable *)object)->update_bam_nested(this);
00266 }
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 void BamWriter::
00284 write_pointer(Datagram &packet, const TypedWritable *object) {
00285
00286
00287 if (object == (const TypedWritable *)NULL) {
00288 write_object_id(packet, 0);
00289
00290 } else {
00291 StateMap::iterator si = _state_map.find(object);
00292 if (si == _state_map.end()) {
00293
00294
00295 int object_id = enqueue_object(object);
00296 write_object_id(packet, object_id);
00297
00298 } else {
00299
00300
00301
00302 int object_id = (*si).second._object_id;
00303 bool already_written = !(*si).second._written_seq.is_initial();
00304 if ((*si).second._written_seq != _writing_seq &&
00305 (*si).second._modified != object->get_bam_modified()) {
00306
00307
00308 already_written = false;
00309 }
00310
00311 write_object_id(packet, object_id);
00312
00313 if (!already_written) {
00314
00315 enqueue_object(object);
00316 } else {
00317
00318 ((TypedWritable *)object)->update_bam_nested(this);
00319 }
00320 }
00321 }
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 void BamWriter::
00334 write_file_data(SubfileInfo &result, const Filename &filename) {
00335
00336
00337 Datagram dg;
00338 dg.add_uint8(BOC_file_data);
00339 if (!_target->put_datagram(dg)) {
00340 util_cat.error()
00341 << "Unable to write data to output.\n";
00342 return;
00343 }
00344
00345
00346
00347 if (!_target->copy_datagram(result, filename)) {
00348 util_cat.error()
00349 << "Unable to write file data to output.\n";
00350 return;
00351 }
00352
00353
00354
00355
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 void BamWriter::
00368 write_file_data(SubfileInfo &result, const SubfileInfo &source) {
00369
00370
00371 Datagram dg;
00372 dg.add_uint8(BOC_file_data);
00373 if (!_target->put_datagram(dg)) {
00374 util_cat.error()
00375 << "Unable to write data to output.\n";
00376 return;
00377 }
00378
00379
00380
00381 if (!_target->copy_datagram(result, source)) {
00382 util_cat.error()
00383 << "Unable to write file data to output.\n";
00384 return;
00385 }
00386
00387
00388
00389
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 void BamWriter::
00403 write_cdata(Datagram &packet, const PipelineCyclerBase &cycler) {
00404 const CycleData *cdata = cycler.read(Thread::get_current_thread());
00405 cdata->write_datagram(this, packet);
00406 cycler.release_read(cdata);
00407 }
00408
00409
00410
00411
00412
00413
00414
00415 void BamWriter::
00416 write_cdata(Datagram &packet, const PipelineCyclerBase &cycler,
00417 void *extra_data) {
00418 const CycleData *cdata = cycler.read(Thread::get_current_thread());
00419 cdata->write_datagram(this, packet, extra_data);
00420 cycler.release_read(cdata);
00421 }
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 bool BamWriter::
00442 register_pta(Datagram &packet, const void *ptr) {
00443 if (ptr == (const void *)NULL) {
00444
00445
00446 write_pta_id(packet, 0);
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 return false;
00457 }
00458
00459 PTAMap::iterator pi = _pta_map.find(ptr);
00460 if (pi == _pta_map.end()) {
00461
00462 int pta_id = _next_pta_id;
00463 _next_pta_id++;
00464
00465 bool inserted = _pta_map.insert(PTAMap::value_type(ptr, pta_id)).second;
00466 nassertr(inserted, false);
00467
00468 write_pta_id(packet, pta_id);
00469
00470
00471
00472 return false;
00473
00474 } else {
00475
00476 int pta_id = (*pi).second;
00477 write_pta_id(packet, pta_id);
00478
00479
00480 return true;
00481 }
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491 void BamWriter::
00492 write_handle(Datagram &packet, TypeHandle type) {
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 int index = type.get_index();
00503
00504
00505 nassertv(index <= 0xffff);
00506
00507 packet.add_uint16(index);
00508
00509 if (index != 0) {
00510 bool inserted = _types_written.insert(index).second;
00511
00512 if (inserted) {
00513
00514
00515 packet.add_string(type.get_name());
00516
00517
00518
00519
00520 int num_parent_classes = type.get_num_parent_classes();
00521 nassertv(num_parent_classes <= 255);
00522 packet.add_uint8(num_parent_classes);
00523 for (int i = 0; i < num_parent_classes; i++) {
00524 write_handle(packet, type.get_parent_class(i));
00525 }
00526 }
00527 }
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540 void BamWriter::
00541 object_destructs(TypedWritable *object) {
00542 StateMap::iterator si = _state_map.find(object);
00543 if (si != _state_map.end()) {
00544
00545
00546 nassertv(!(*si).second._written_seq.is_initial());
00547
00548 int object_id = (*si).second._object_id;
00549 _freed_object_ids.push_back(object_id);
00550
00551 _state_map.erase(si);
00552 }
00553 }
00554
00555
00556
00557
00558
00559
00560 void BamWriter::
00561 write_object_id(Datagram &dg, int object_id) {
00562 if (_long_object_id) {
00563 dg.add_uint32(object_id);
00564
00565 } else {
00566 dg.add_uint16(object_id);
00567
00568
00569 if (object_id == 0xffff) {
00570 _long_object_id = true;
00571 }
00572 }
00573 }
00574
00575
00576
00577
00578
00579
00580 void BamWriter::
00581 write_pta_id(Datagram &dg, int pta_id) {
00582 if (_long_pta_id) {
00583 dg.add_uint32(pta_id);
00584
00585 } else {
00586 dg.add_uint16(pta_id);
00587
00588
00589 if (pta_id == 0xffff) {
00590 _long_pta_id = true;
00591 }
00592 }
00593 }
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 int BamWriter::
00605 enqueue_object(const TypedWritable *object) {
00606 Datagram dg;
00607
00608 nassertr(object != TypedWritable::Null, 0);
00609
00610
00611
00612
00613 #ifndef NDEBUG
00614 if (!object->is_of_type(TypedWritable::get_class_type())) {
00615 util_cat.error()
00616 << "Type " << object->get_type()
00617 << " does not indicate inheritance from TypedWritable.\n"
00618 << "(this is almost certainly an oversight in " << object->get_type()
00619 << "::init_type().)\n";
00620 }
00621 #endif
00622
00623
00624
00625 int object_id;
00626
00627 StateMap::iterator si = _state_map.find(object);
00628 if (si == _state_map.end()) {
00629
00630
00631 object_id = _next_object_id;
00632
00633 bool inserted =
00634 _state_map.insert(StateMap::value_type(object, StoreState(_next_object_id))).second;
00635 nassertr(inserted, false);
00636 {
00637 LightMutexHolder holder(TypedWritable::_bam_writers_lock);
00638 if (object->_bam_writers == ((TypedWritable::BamWriters *)NULL)) {
00639 ((TypedWritable *)object)->_bam_writers = new TypedWritable::BamWriters;
00640 }
00641 object->_bam_writers->push_back(this);
00642 }
00643 _next_object_id++;
00644
00645 } else {
00646
00647 object_id = (*si).second._object_id;
00648 }
00649
00650 _object_queue.push_back(object);
00651 return object_id;
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 bool BamWriter::
00663 flush_queue() {
00664 nassertr(_target != NULL, false);
00665
00666 while (!_object_queue.empty()) {
00667 const TypedWritable *object = _object_queue.front();
00668 _object_queue.pop_front();
00669
00670
00671 StateMap::iterator si = _state_map.find(object);
00672 nassertr(si != _state_map.end(), false);
00673
00674 if ((*si).second._written_seq == _writing_seq) {
00675
00676 continue;
00677 }
00678
00679 int object_id = (*si).second._object_id;
00680 bool already_written = !(*si).second._written_seq.is_initial();
00681 if ((*si).second._modified != object->get_bam_modified()) {
00682
00683
00684 already_written = false;
00685 }
00686
00687 Datagram dg;
00688 dg.set_stdfloat_double(_file_stdfloat_double);
00689 dg.add_uint8(_next_boc);
00690 _next_boc = BOC_adjunct;
00691
00692 if (!already_written) {
00693
00694
00695
00696
00697
00698
00699 TypeHandle type = object->get_type();
00700 nassertr(type != TypeHandle::none(), false);
00701
00702
00703
00704 TypeHandle registered_type =
00705 BamReader::get_factory()->find_registered_type(type);
00706 if (registered_type == TypeHandle::none()) {
00707
00708 util_cat.warning()
00709 << "Objects of type " << type << " cannot be read; bam file is invalid.\n";
00710 } else if (registered_type != type) {
00711 util_cat.info()
00712 << "Writing " << registered_type << " instead of " << type << "\n";
00713 type = registered_type;
00714
00715 } else if (util_cat.is_debug()) {
00716 util_cat.debug()
00717 << "Writing " << type << " object id " << object_id
00718 << " to bam file\n";
00719 }
00720
00721 write_handle(dg, type);
00722 write_object_id(dg, object_id);
00723
00724
00725
00726
00727
00728
00729
00730 ((TypedWritable *)object)->write_datagram(this, dg);
00731
00732 (*si).second._written_seq = _writing_seq;
00733 (*si).second._modified = object->get_bam_modified();
00734
00735 } else {
00736
00737
00738
00739
00740
00741 write_handle(dg, TypeHandle::none());
00742 write_object_id(dg, object_id);
00743
00744
00745
00746 ((TypedWritable *)object)->update_bam_nested(this);
00747 }
00748
00749 if (!_target->put_datagram(dg)) {
00750 util_cat.error()
00751 << "Unable to write data to output.\n";
00752 return false;
00753 }
00754 }
00755
00756 return true;
00757 }