00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "fltHeader.h"
00016 #include "fltRecordReader.h"
00017 #include "fltRecordWriter.h"
00018 #include "fltUnsupportedRecord.h"
00019 #include "config_flt.h"
00020 #include "zStream.h"
00021 #include "nearly_zero.h"
00022 #include "virtualFileSystem.h"
00023
00024 #include <assert.h>
00025 #include <math.h>
00026
00027 TypeHandle FltHeader::_type_handle;
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 FltHeader::
00045 FltHeader(PathReplace *path_replace) : FltBeadID(this) {
00046 if (path_replace == (PathReplace *)NULL) {
00047 _path_replace = new PathReplace;
00048 _path_replace->_path_store = PS_absolute;
00049 } else {
00050 _path_replace = path_replace;
00051 }
00052
00053 _format_revision_level = 1570;
00054 _edit_revision_level = 1570;
00055 _next_group_id = 1;
00056 _next_lod_id = 1;
00057 _next_object_id = 1;
00058 _next_face_id = 1;
00059 _unit_multiplier = 1;
00060 _vertex_units = U_feet;
00061 _texwhite_new = false;
00062 _flags = 0;
00063 _projection_type = PT_flat_earth;
00064 _next_dof_id = 1;
00065 _vertex_storage_type = VTS_double;
00066 _database_origin = DO_open_flight;
00067 _sw_x = 0.0;
00068 _sw_y = 0.0;
00069 _delta_x = 0.0;
00070 _delta_y = 0.0;
00071 _next_sound_id = 1;
00072 _next_path_id = 1;
00073 _next_clip_id = 1;
00074 _next_text_id = 1;
00075 _next_bsp_id = 1;
00076 _next_switch_id = 1;
00077 _sw_lat = 0.0;
00078 _sw_long = 0.0;
00079 _ne_lat = 0.0;
00080 _ne_long = 0.0;
00081 _origin_lat = 0.0;
00082 _origin_long = 0.0;
00083 _lambert_upper_lat = 0.0;
00084 _lambert_lower_lat = 0.0;
00085 _next_light_id = 1;
00086 _next_road_id = 1;
00087 _next_cat_id = 1;
00088
00089
00090 _earth_model = EM_wgs84;
00091
00092
00093 _next_adaptive_id = 0;
00094 _next_curve_id = 0;
00095
00096
00097 _delta_z = 0.0;
00098 _radius = 0.0;
00099 _next_mesh_id = 0;
00100
00101 _vertex_lookups_stale = false;
00102 _current_vertex_offset = 0;
00103 _next_material_index = 1;
00104 _next_pattern_index = 1;
00105 _got_color_palette = false;
00106 _got_14_material_palette = false;
00107 _got_eyepoint_trackplane_palette = false;
00108
00109 _auto_attr_update = AU_if_missing;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 void FltHeader::
00122 apply_converted_filenames() {
00123 Textures::const_iterator ti;
00124 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00125 FltTexture *texture = (*ti).second;
00126 texture->apply_converted_filenames();
00127 }
00128
00129 FltBeadID::apply_converted_filenames();
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139 void FltHeader::
00140 set_path_replace(PathReplace *path_replace) {
00141 _path_replace = path_replace;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 PathReplace *FltHeader::
00153 get_path_replace() {
00154 return _path_replace;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 const PathReplace *FltHeader::
00166 get_path_replace() const {
00167 return _path_replace;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177 Filename FltHeader::
00178 convert_path(const Filename &orig_filename, const DSearchPath &additional_path) {
00179 DSearchPath file_path;
00180 if (!_flt_filename.empty()) {
00181 file_path.append_directory(_flt_filename.get_dirname());
00182 }
00183 file_path.append_path(additional_path);
00184 return _path_replace->convert_path(orig_filename, file_path);
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 void FltHeader::
00195 set_flt_filename(const Filename &flt_filename) {
00196 _flt_filename = flt_filename;
00197 }
00198
00199
00200
00201
00202
00203
00204
00205 const Filename &FltHeader::
00206 get_flt_filename() const {
00207 return _flt_filename;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217 FltError FltHeader::
00218 read_flt(Filename filename) {
00219 filename.set_binary();
00220 _flt_filename = filename;
00221
00222 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00223 istream *in = vfs->open_read_file(filename, true);
00224 if (in == (istream *)NULL) {
00225 assert(!flt_error_abort);
00226 return FE_could_not_open;
00227 }
00228 FltError result = read_flt(*in);
00229 vfs->close_read_file(in);
00230 return result;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240 FltError FltHeader::
00241 read_flt(istream &in) {
00242 FltRecordReader reader(in);
00243 FltError result = reader.advance();
00244 if (result == FE_end_of_file) {
00245 assert(!flt_error_abort);
00246 return FE_empty_file;
00247 } else if (result != FE_ok) {
00248 return result;
00249 }
00250
00251 result = read_record_and_children(reader);
00252 if (result != FE_ok) {
00253 return result;
00254 }
00255
00256 if (!reader.eof()) {
00257 assert(!flt_error_abort);
00258 return FE_extra_data;
00259 }
00260
00261 return FE_ok;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 FltError FltHeader::
00273 write_flt(Filename filename) {
00274 filename.set_binary();
00275
00276 ofstream out;
00277 if (!filename.open_write(out)) {
00278 assert(!flt_error_abort);
00279 return FE_could_not_open;
00280 }
00281
00282 #ifdef HAVE_ZLIB
00283 if (filename.get_extension() == "pz") {
00284
00285
00286 OCompressStream compressor(&out, false);
00287 return write_flt(compressor);
00288 }
00289 #endif // HAVE_ZLIB
00290
00291 return write_flt(out);
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301 FltError FltHeader::
00302 write_flt(ostream &out) {
00303 FltRecordWriter writer(out);
00304 FltError result = write_record_and_children(writer);
00305
00306 if (out.fail()) {
00307 assert(!flt_error_abort);
00308 return FE_write_error;
00309 }
00310 return result;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 void FltHeader::
00336 set_auto_attr_update(FltHeader::AttrUpdate attr) {
00337 _auto_attr_update = attr;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 FltHeader::AttrUpdate FltHeader::
00347 get_auto_attr_update() const {
00348 return _auto_attr_update;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358 int FltHeader::
00359 get_flt_version() const {
00360 if (_format_revision_level < 1420) {
00361 return _format_revision_level * 100;
00362 } else {
00363 return _format_revision_level;
00364 }
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374 void FltHeader::
00375 set_flt_version(int version) {
00376 if (version < 14.2) {
00377 _format_revision_level = version / 100;
00378 } else {
00379 _format_revision_level = version;
00380 }
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390 int FltHeader::
00391 min_flt_version() {
00392 return 1400;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402 int FltHeader::
00403 max_flt_version() {
00404 return 1570;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 bool FltHeader::
00418 check_version() const {
00419 int version = get_flt_version();
00420
00421 if (version < min_flt_version()) {
00422 nout << "Warning! The version number of this file appears to be "
00423 << version / 100.0 << ", which is older than " << min_flt_version() / 100.0
00424 << ", the oldest OpenFlight version understood by this program. "
00425 "It is unlikely that this program will be able to read the file "
00426 "correctly.\n";
00427 return false;
00428 }
00429
00430 if (version > max_flt_version()) {
00431 nout << "Warning! The version number of this file appears to be "
00432 << version / 100.0 << ", which is newer than " << max_flt_version() / 100.0
00433 << ", the newest OpenFlight version understood by this program. "
00434 "Chances are good that the program will still be able to read it "
00435 "correctly, but any features in the file that are specific to "
00436 "the latest version of OpenFlight will not be understood.\n";
00437 return false;
00438 }
00439
00440 return true;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450 DistanceUnit FltHeader::
00451 get_units() const {
00452 switch (_vertex_units) {
00453 case FltHeader::U_meters:
00454 return DU_meters;
00455
00456 case FltHeader::U_kilometers:
00457 return DU_kilometers;
00458
00459 case FltHeader::U_feet:
00460 return DU_feet;
00461
00462 case FltHeader::U_inches:
00463 return DU_inches;
00464
00465 case FltHeader::U_nautical_miles:
00466 return DU_nautical_miles;
00467 }
00468
00469
00470 return DU_invalid;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 bool FltHeader::
00480 has_instance(int instance_index) const {
00481 return (_instances.count(instance_index) != 0);
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 FltInstanceDefinition *FltHeader::
00491 get_instance(int instance_index) const {
00492 Instances::const_iterator mi;
00493 mi = _instances.find(instance_index);
00494 if (mi != _instances.end()) {
00495 return (*mi).second;
00496 }
00497 return (FltInstanceDefinition *)NULL;
00498 }
00499
00500
00501
00502
00503
00504
00505 void FltHeader::
00506 clear_instances() {
00507 _instances.clear();
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 void FltHeader::
00520 add_instance(FltInstanceDefinition *instance) {
00521 _instances[instance->_instance_index] = instance;
00522 }
00523
00524
00525
00526
00527
00528
00529
00530 void FltHeader::
00531 remove_instance(int instance_index) {
00532 _instances.erase(instance_index);
00533 }
00534
00535
00536
00537
00538
00539
00540 int FltHeader::
00541 get_num_vertices() const {
00542 return _vertices.size();
00543 }
00544
00545
00546
00547
00548
00549
00550 FltVertex *FltHeader::
00551 get_vertex(int n) const {
00552 nassertr(n >= 0 && n < (int)_vertices.size(), 0);
00553 return _vertices[n];
00554 }
00555
00556
00557
00558
00559
00560
00561 void FltHeader::
00562 clear_vertices() {
00563 _vertices.clear();
00564 _unique_vertices.clear();
00565 _vertices_by_offset.clear();
00566 _offsets_by_vertex.clear();
00567 _vertex_lookups_stale = false;
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577 void FltHeader::
00578 add_vertex(FltVertex *vertex) {
00579 bool inserted = _unique_vertices.insert(vertex).second;
00580 if (inserted) {
00581 _vertices.push_back(vertex);
00582 }
00583 _vertex_lookups_stale = true;
00584 nassertv(_unique_vertices.size() == _vertices.size());
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 FltVertex *FltHeader::
00596 get_vertex_by_offset(int offset) {
00597 if (_vertex_lookups_stale) {
00598 update_vertex_lookups();
00599 }
00600
00601 VerticesByOffset::const_iterator vi;
00602 vi = _vertices_by_offset.find(offset);
00603 if (vi == _vertices_by_offset.end()) {
00604 nout << "No vertex with offset " << offset << "\n";
00605 return (FltVertex *)NULL;
00606 }
00607 return (*vi).second;
00608 }
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 int FltHeader::
00619 get_offset_by_vertex(FltVertex *vertex) {
00620 if (_vertex_lookups_stale) {
00621 update_vertex_lookups();
00622 }
00623
00624 OffsetsByVertex::const_iterator vi;
00625 vi = _offsets_by_vertex.find(vertex);
00626 if (vi == _offsets_by_vertex.end()) {
00627 nout << "Vertex does not appear in palette.\n";
00628 return 0;
00629 }
00630 return (*vi).second;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 int FltHeader::
00647 get_num_colors() const {
00648 return _colors.size() * get_num_color_shades();
00649 }
00650
00651
00652
00653
00654
00655
00656
00657
00658 LColor FltHeader::
00659 get_color(int color_index) const {
00660 nassertr(color_index >= 0 && color_index < get_num_colors(),
00661 LColor(0.0, 0.0, 0.0, 0.0));
00662 int num_color_shades = get_num_color_shades();
00663
00664 int index = (color_index / num_color_shades);
00665 int level = (color_index % num_color_shades);
00666 nassertr(index >= 0 && index < (int)_colors.size(),
00667 LColor(0.0, 0.0, 0.0, 0.0));
00668
00669 LColor color = _colors[index].get_color();
00670 return color * ((double)level / (double)(num_color_shades - 1));
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680 LRGBColor FltHeader::
00681 get_rgb(int color_index) const {
00682 nassertr(color_index >= 0 && color_index < get_num_colors(),
00683 LRGBColor(0.0, 0.0, 0.0));
00684 int num_color_shades = get_num_color_shades();
00685
00686 int index = (color_index / num_color_shades);
00687 int level = (color_index % num_color_shades);
00688 nassertr(index >= 0 && index < (int)_colors.size(),
00689 LRGBColor(0.0, 0.0, 0.0));
00690
00691 LRGBColor color = _colors[index].get_rgb();
00692 return color * ((double)level / (double)(num_color_shades - 1));
00693 }
00694
00695
00696
00697
00698
00699
00700
00701 bool FltHeader::
00702 has_color_name(int color_index) const {
00703 return (_color_names.count(color_index) != 0);
00704 }
00705
00706
00707
00708
00709
00710
00711
00712 string FltHeader::
00713 get_color_name(int color_index) const {
00714 ColorNames::const_iterator ni;
00715 ni = _color_names.find(color_index);
00716 if (ni != _color_names.end()) {
00717 return (*ni).second;
00718 }
00719 return string();
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729 int FltHeader::
00730 get_closest_color(const LColor &color0) const {
00731
00732
00733
00734
00735
00736 LColor color = color0;
00737
00738 double scale = 1.0;
00739
00740 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
00741
00742 scale = 0.0;
00743 color.set(1.0, 1.0, 1.0, 1.0);
00744
00745 } else {
00746 if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
00747
00748 scale = color[0];
00749
00750 } else if (color[1] >= color[2] && color[1] >= color[3]) {
00751
00752 scale = color[1];
00753
00754 } else if (color[2] >= color[3]) {
00755
00756 scale = color[2];
00757
00758 } else {
00759
00760 scale = color[3];
00761 }
00762 color /= scale;
00763 }
00764
00765
00766 PN_stdfloat best_dist = 5.0;
00767 int best_i = -1;
00768
00769 int num_color_entries = get_num_color_entries();
00770 for (int i = 0; i < num_color_entries; i++) {
00771 LColor consider = _colors[i].get_color();
00772 PN_stdfloat dist2 = dot(consider - color, consider - color);
00773 nassertr(dist2 < 5.0, 0);
00774
00775 if (dist2 < best_dist) {
00776 best_dist = dist2;
00777 best_i = i;
00778 }
00779 }
00780 nassertr(best_i >= 0, 0);
00781
00782 int num_color_shades = get_num_color_shades();
00783 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
00784
00785 return (best_i * num_color_shades) + shade_index;
00786 }
00787
00788
00789
00790
00791
00792
00793
00794
00795 int FltHeader::
00796 get_closest_rgb(const LRGBColor &color0) const {
00797
00798
00799
00800
00801
00802
00803 LRGBColor color = color0;
00804 double scale = 1.0;
00805
00806 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
00807
00808 scale = 0.0;
00809 color.set(1.0, 1.0, 1.0);
00810
00811 } else {
00812 if (color[0] >= color[1] && color[0] >= color[2]) {
00813
00814 scale = color[0];
00815
00816 } else if (color[1] >= color[2]) {
00817
00818 scale = color[1];
00819
00820 } else {
00821
00822 scale = color[2];
00823 }
00824 color /= scale;
00825 }
00826
00827
00828 PN_stdfloat best_dist = 5.0;
00829 int best_i = -1;
00830
00831 int num_color_entries = get_num_color_entries();
00832 for (int i = 0; i < num_color_entries; i++) {
00833 LRGBColor consider = _colors[i].get_rgb();
00834 PN_stdfloat dist2 = dot(consider - color, consider - color);
00835 nassertr(dist2 < 5.0, 0);
00836
00837 if (dist2 < best_dist) {
00838 best_dist = dist2;
00839 best_i = i;
00840 }
00841 }
00842 nassertr(best_i >= 0, 0);
00843
00844 int num_color_shades = get_num_color_shades();
00845 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
00846
00847 return (best_i * num_color_shades) + shade_index;
00848 }
00849
00850
00851
00852
00853
00854
00855
00856
00857 int FltHeader::
00858 get_num_color_entries() const {
00859 return _colors.size();
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 int FltHeader::
00871 get_num_color_shades() const {
00872 return 128;
00873 }
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884 LColor FltHeader::
00885 get_color(int color_index, bool use_packed_color,
00886 const FltPackedColor &packed_color,
00887 int transparency) {
00888 if (!use_packed_color) {
00889 return get_color(color_index);
00890 }
00891
00892 LColor color;
00893 color[0] = packed_color._r / 255.0;
00894 color[1] = packed_color._g / 255.0;
00895 color[2] = packed_color._b / 255.0;
00896
00897
00898 color[3] = 1.0 - (transparency / 65535.0);
00899 return color;
00900 }
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 LRGBColor FltHeader::
00912 get_rgb(int color_index, bool use_packed_color,
00913 const FltPackedColor &packed_color) {
00914 if (!use_packed_color) {
00915 return get_rgb(color_index);
00916 }
00917
00918 LRGBColor color;
00919 color[0] = packed_color._r / 255.0;
00920 color[1] = packed_color._g / 255.0;
00921 color[2] = packed_color._b / 255.0;
00922 return color;
00923 }
00924
00925
00926
00927
00928
00929
00930
00931 bool FltHeader::
00932 has_material(int material_index) const {
00933 return (_materials.count(material_index) != 0);
00934 }
00935
00936
00937
00938
00939
00940
00941
00942 FltMaterial *FltHeader::
00943 get_material(int material_index) const {
00944 Materials::const_iterator mi;
00945 mi = _materials.find(material_index);
00946 if (mi != _materials.end()) {
00947 return (*mi).second;
00948 }
00949 return (FltMaterial *)NULL;
00950 }
00951
00952
00953
00954
00955
00956
00957 void FltHeader::
00958 clear_materials() {
00959 _materials.clear();
00960 }
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970 void FltHeader::
00971 add_material(FltMaterial *material) {
00972 if (material->_material_index < 0) {
00973
00974 material->_material_index = _next_material_index;
00975 _next_material_index++;
00976
00977 } else {
00978
00979
00980 _next_material_index = max(_next_material_index, material->_material_index + 1);
00981 }
00982
00983 _materials[material->_material_index] = material;
00984 }
00985
00986
00987
00988
00989
00990
00991
00992 void FltHeader::
00993 remove_material(int material_index) {
00994 _materials.erase(material_index);
00995 }
00996
00997
00998
00999
01000
01001
01002
01003 bool FltHeader::
01004 has_texture(int texture_index) const {
01005 return (_textures.count(texture_index) != 0);
01006 }
01007
01008
01009
01010
01011
01012
01013
01014 FltTexture *FltHeader::
01015 get_texture(int texture_index) const {
01016 Textures::const_iterator mi;
01017 mi = _textures.find(texture_index);
01018 if (mi != _textures.end()) {
01019 return (*mi).second;
01020 }
01021 return (FltTexture *)NULL;
01022 }
01023
01024
01025
01026
01027
01028
01029 void FltHeader::
01030 clear_textures() {
01031 _textures.clear();
01032 }
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042 void FltHeader::
01043 add_texture(FltTexture *texture) {
01044 if (texture->_pattern_index < 0) {
01045
01046 texture->_pattern_index = _next_pattern_index;
01047 _next_pattern_index++;
01048
01049 } else {
01050
01051
01052 _next_pattern_index = max(_next_pattern_index, texture->_pattern_index + 1);
01053 }
01054
01055 _textures[texture->_pattern_index] = texture;
01056 }
01057
01058
01059
01060
01061
01062
01063
01064 void FltHeader::
01065 remove_texture(int texture_index) {
01066 _textures.erase(texture_index);
01067 }
01068
01069
01070
01071
01072
01073
01074
01075 bool FltHeader::
01076 has_light_source(int light_index) const {
01077 return (_light_sources.count(light_index) != 0);
01078 }
01079
01080
01081
01082
01083
01084
01085
01086 FltLightSourceDefinition *FltHeader::
01087 get_light_source(int light_index) const {
01088 LightSources::const_iterator li;
01089 li = _light_sources.find(light_index);
01090 if (li != _light_sources.end()) {
01091 return (*li).second;
01092 }
01093 return (FltLightSourceDefinition *)NULL;
01094 }
01095
01096
01097
01098
01099
01100
01101 void FltHeader::
01102 clear_light_sources() {
01103 _light_sources.clear();
01104 }
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 void FltHeader::
01115 add_light_source(FltLightSourceDefinition *light_source) {
01116 _light_sources[light_source->_light_index] = light_source;
01117 }
01118
01119
01120
01121
01122
01123
01124
01125 void FltHeader::
01126 remove_light_source(int light_index) {
01127 _light_sources.erase(light_index);
01128 }
01129
01130
01131
01132
01133
01134
01135
01136
01137 bool FltHeader::
01138 got_eyepoint_trackplane_palette() const {
01139 return _got_eyepoint_trackplane_palette;
01140 }
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151 void FltHeader::
01152 set_eyepoint_trackplane_palette(bool flag) {
01153 _got_eyepoint_trackplane_palette = flag;
01154 }
01155
01156
01157
01158
01159
01160
01161
01162
01163 int FltHeader::
01164 get_num_eyepoints() const {
01165 return 10;
01166 }
01167
01168
01169
01170
01171
01172
01173
01174 FltEyepoint *FltHeader::
01175 get_eyepoint(int n) {
01176 nassertr(n >= 0 && n < get_num_eyepoints(), (FltEyepoint *)NULL);
01177 return &_eyepoints[n];
01178 }
01179
01180
01181
01182
01183
01184
01185
01186
01187 int FltHeader::
01188 get_num_trackplanes() const {
01189 return 10;
01190 }
01191
01192
01193
01194
01195
01196
01197
01198 FltTrackplane *FltHeader::
01199 get_trackplane(int n) {
01200 nassertr(n >= 0 && n < get_num_trackplanes(), (FltTrackplane *)NULL);
01201 return &_trackplanes[n];
01202 }
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215 int FltHeader::
01216 update_vertex_lookups() {
01217
01218 int offset = 8;
01219
01220 Vertices::const_iterator vi;
01221 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
01222 FltVertex *vertex = (*vi);
01223
01224 _offsets_by_vertex[vertex] = offset;
01225 _vertices_by_offset[offset] = vertex;
01226 offset += vertex->get_record_length();
01227 }
01228
01229 _vertex_lookups_stale = false;
01230
01231 return offset;
01232 }
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242 bool FltHeader::
01243 extract_record(FltRecordReader &reader) {
01244 if (!FltBeadID::extract_record(reader)) {
01245 return false;
01246 }
01247
01248 nassertr(reader.get_opcode() == FO_header, false);
01249 DatagramIterator &iterator = reader.get_iterator();
01250
01251 _format_revision_level = iterator.get_be_int32();
01252 _edit_revision_level = iterator.get_be_int32();
01253 _last_revision = iterator.get_fixed_string(32);
01254 _next_group_id = iterator.get_be_int16();
01255 _next_lod_id = iterator.get_be_int16();
01256 _next_object_id = iterator.get_be_int16();
01257 _next_face_id = iterator.get_be_int16();
01258 _unit_multiplier = iterator.get_be_int16();
01259 _vertex_units = (Units)iterator.get_int8();
01260 _texwhite_new = (iterator.get_int8() != 0);
01261 _flags = iterator.get_be_uint32();
01262 iterator.skip_bytes(24);
01263 _projection_type = (ProjectionType)iterator.get_be_int32();
01264 iterator.skip_bytes(28);
01265 _next_dof_id = iterator.get_be_int16();
01266 _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
01267 _database_origin = (DatabaseOrigin)iterator.get_be_int32();
01268 _sw_x = iterator.get_be_float64();
01269 _sw_y = iterator.get_be_float64();
01270 _delta_x = iterator.get_be_float64();
01271 _delta_y = iterator.get_be_float64();
01272 _next_sound_id = iterator.get_be_int16();
01273 _next_path_id = iterator.get_be_int16();
01274 iterator.skip_bytes(8);
01275 _next_clip_id = iterator.get_be_int16();
01276 _next_text_id = iterator.get_be_int16();
01277 _next_bsp_id = iterator.get_be_int16();
01278 _next_switch_id = iterator.get_be_int16();
01279 iterator.skip_bytes(4);
01280 _sw_lat = iterator.get_be_float64();
01281 _sw_long = iterator.get_be_float64();
01282 _ne_lat = iterator.get_be_float64();
01283 _ne_long = iterator.get_be_float64();
01284 _origin_lat = iterator.get_be_float64();
01285 _origin_long = iterator.get_be_float64();
01286 _lambert_upper_lat = iterator.get_be_float64();
01287 _lambert_lower_lat = iterator.get_be_float64();
01288 _next_light_id = iterator.get_be_int16();
01289 iterator.skip_bytes(2);
01290 if (get_flt_version() >= 1420 && iterator.get_remaining_size() > 0) {
01291 _next_road_id = iterator.get_be_int16();
01292 _next_cat_id = iterator.get_be_int16();
01293
01294 if (get_flt_version() >= 1520 && iterator.get_remaining_size() > 0) {
01295 iterator.skip_bytes(2 + 2 + 2 + 2);
01296 _earth_model = (EarthModel)iterator.get_be_int32();
01297
01298
01299 iterator.skip_bytes(4);
01300
01301 if (get_flt_version() >= 1560 && iterator.get_remaining_size() > 0) {
01302 _next_adaptive_id = iterator.get_be_int16();
01303 _next_curve_id = iterator.get_be_int16();
01304 iterator.skip_bytes(4);
01305
01306 if (get_flt_version() >= 1570 && iterator.get_remaining_size() > 0) {
01307 _delta_z = iterator.get_be_float64();
01308 _radius = iterator.get_be_float64();
01309 _next_mesh_id = iterator.get_be_int16();
01310 iterator.skip_bytes(2);
01311
01312
01313 iterator.skip_bytes(4);
01314 }
01315 }
01316 }
01317 }
01318
01319 check_remaining_size(iterator);
01320 return true;
01321 }
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332 bool FltHeader::
01333 extract_ancillary(FltRecordReader &reader) {
01334 switch (reader.get_opcode()) {
01335 case FO_vertex_palette:
01336
01337 clear_vertices();
01338 _current_vertex_offset = reader.get_record_length();
01339 return true;
01340
01341 case FO_vertex_c:
01342 case FO_vertex_cn:
01343 case FO_vertex_cnu:
01344 case FO_vertex_cu:
01345
01346 return extract_vertex(reader);
01347
01348 case FO_color_palette:
01349 return extract_color_palette(reader);
01350
01351 case FO_15_material:
01352 return extract_material(reader);
01353
01354 case FO_14_material_palette:
01355 return extract_14_material_palette(reader);
01356
01357 case FO_texture:
01358 return extract_texture(reader);
01359
01360 case FO_texture_map_palette:
01361 return extract_texture_map(reader);
01362
01363 case FO_light_definition:
01364 return extract_light_source(reader);
01365
01366 case FO_eyepoint_palette:
01367 return extract_eyepoint_palette(reader);
01368
01369 default:
01370 return FltBeadID::extract_ancillary(reader);
01371 }
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382 bool FltHeader::
01383 build_record(FltRecordWriter &writer) const {
01384 if (!FltBeadID::build_record(writer)) {
01385 return false;
01386 }
01387
01388 writer.set_opcode(FO_header);
01389 Datagram &datagram = writer.update_datagram();
01390
01391 datagram.add_be_int32(_format_revision_level);
01392 datagram.add_be_int32(_edit_revision_level);
01393 datagram.add_fixed_string(_last_revision, 32);
01394 datagram.add_be_int16(_next_group_id);
01395 datagram.add_be_int16(_next_lod_id);
01396 datagram.add_be_int16(_next_object_id);
01397 datagram.add_be_int16(_next_face_id);
01398 datagram.add_be_int16(_unit_multiplier);
01399 datagram.add_int8(_vertex_units);
01400 datagram.add_int8(_texwhite_new);
01401 datagram.add_be_uint32(_flags);
01402 datagram.pad_bytes(24);
01403 datagram.add_be_int32(_projection_type);
01404 datagram.pad_bytes(28);
01405 datagram.add_be_int16(_next_dof_id);
01406 datagram.add_be_int16(_vertex_storage_type);
01407 datagram.add_be_int32(_database_origin);
01408 datagram.add_be_float64(_sw_x);
01409 datagram.add_be_float64(_sw_y);
01410 datagram.add_be_float64(_delta_x);
01411 datagram.add_be_float64(_delta_y);
01412 datagram.add_be_int16(_next_sound_id);
01413 datagram.add_be_int16(_next_path_id);
01414 datagram.pad_bytes(8);
01415 datagram.add_be_int16(_next_clip_id);
01416 datagram.add_be_int16(_next_text_id);
01417 datagram.add_be_int16(_next_bsp_id);
01418 datagram.add_be_int16(_next_switch_id);
01419 datagram.pad_bytes(4);
01420 datagram.add_be_float64(_sw_lat);
01421 datagram.add_be_float64(_sw_long);
01422 datagram.add_be_float64(_ne_lat);
01423 datagram.add_be_float64(_ne_long);
01424 datagram.add_be_float64(_origin_lat);
01425 datagram.add_be_float64(_origin_long);
01426 datagram.add_be_float64(_lambert_upper_lat);
01427 datagram.add_be_float64(_lambert_lower_lat);
01428 datagram.add_be_int16(_next_light_id);
01429 datagram.pad_bytes(2);
01430 datagram.add_be_int16(_next_road_id);
01431 datagram.add_be_int16(_next_cat_id);
01432
01433 if (get_flt_version() >= 1520) {
01434
01435 datagram.pad_bytes(2 + 2 + 2 + 2);
01436 datagram.add_be_int32(_earth_model);
01437
01438 datagram.pad_bytes(4);
01439
01440 if (get_flt_version() >= 1560) {
01441
01442 datagram.add_be_int16(_next_adaptive_id);
01443 datagram.add_be_int16(_next_curve_id);
01444 datagram.pad_bytes(4);
01445
01446 if (get_flt_version() >= 1570) {
01447
01448 datagram.add_be_float64(_delta_z);
01449 datagram.add_be_float64(_radius);
01450 datagram.add_be_int16(_next_mesh_id);
01451 datagram.pad_bytes(2);
01452 datagram.pad_bytes(4);
01453 }
01454 }
01455 }
01456
01457 return true;
01458 }
01459
01460
01461
01462
01463
01464
01465
01466
01467 FltError FltHeader::
01468 write_ancillary(FltRecordWriter &writer) const {
01469 FltError result;
01470
01471 result = write_color_palette(writer);
01472 if (result != FE_ok) {
01473 return result;
01474 }
01475
01476 result = write_material_palette(writer);
01477 if (result != FE_ok) {
01478 return result;
01479 }
01480
01481 result = write_texture_palette(writer);
01482 if (result != FE_ok) {
01483 return result;
01484 }
01485
01486 result = write_light_source_palette(writer);
01487 if (result != FE_ok) {
01488 return result;
01489 }
01490
01491 result = write_eyepoint_palette(writer);
01492 if (result != FE_ok) {
01493 return result;
01494 }
01495
01496 result = write_vertex_palette(writer);
01497 if (result != FE_ok) {
01498 return result;
01499 }
01500
01501 return FltBeadID::write_ancillary(writer);
01502 }
01503
01504
01505
01506
01507
01508
01509
01510
01511 bool FltHeader::
01512 extract_vertex(FltRecordReader &reader) {
01513 FltVertex *vertex = new FltVertex(this);
01514 if (!vertex->extract_record(reader)) {
01515 return false;
01516 }
01517 _vertices.push_back(vertex);
01518 _unique_vertices.insert(vertex);
01519 _offsets_by_vertex[vertex] = _current_vertex_offset;
01520 _vertices_by_offset[_current_vertex_offset] = vertex;
01521 _current_vertex_offset += reader.get_record_length();
01522
01523
01524
01525 return true;
01526 }
01527
01528
01529
01530
01531
01532
01533 bool FltHeader::
01534 extract_color_palette(FltRecordReader &reader) {
01535 nassertr(reader.get_opcode() == FO_color_palette, false);
01536 DatagramIterator &iterator = reader.get_iterator();
01537
01538 if (_got_color_palette) {
01539 nout << "Warning: multiple color palettes found.\n";
01540 }
01541 _got_color_palette = true;
01542
01543 static const int expected_color_entries = 1024;
01544
01545 iterator.skip_bytes(128);
01546 _colors.clear();
01547 for (int i = 0; i < expected_color_entries; i++) {
01548 if (iterator.get_remaining_size() == 0) {
01549
01550 return true;
01551 }
01552 FltPackedColor color;
01553 if (!color.extract_record(reader)) {
01554 return false;
01555 }
01556 _colors.push_back(color);
01557 }
01558
01559
01560 while (iterator.get_remaining_size() > 0) {
01561 int entry_length = iterator.get_be_uint16();
01562 iterator.skip_bytes(2);
01563 if (iterator.get_remaining_size() > 0) {
01564 int color_index = iterator.get_be_int16();
01565 iterator.skip_bytes(2);
01566
01567 int name_length = entry_length - 8;
01568 nassertr(color_index >= 0 && color_index < (int)_colors.size(), false);
01569 _color_names[color_index] = iterator.get_fixed_string(name_length);
01570 }
01571 }
01572
01573 check_remaining_size(iterator, "color palette");
01574 return true;
01575 }
01576
01577
01578
01579
01580
01581
01582 bool FltHeader::
01583 extract_material(FltRecordReader &reader) {
01584 PT(FltMaterial) material = new FltMaterial(this);
01585 if (!material->extract_record(reader)) {
01586 return false;
01587 }
01588 add_material(material);
01589
01590 return true;
01591 }
01592
01593
01594
01595
01596
01597
01598 bool FltHeader::
01599 extract_14_material_palette(FltRecordReader &reader) {
01600 nassertr(reader.get_opcode() == FO_14_material_palette, false);
01601 DatagramIterator &iterator = reader.get_iterator();
01602
01603 if (_got_14_material_palette) {
01604 nout << "Warning: multiple material palettes found.\n";
01605 }
01606 _got_14_material_palette = true;
01607
01608 static const int expected_material_entries = 64;
01609
01610 _materials.clear();
01611 for (int i = 0; i < expected_material_entries; i++) {
01612 if (iterator.get_remaining_size() == 0) {
01613
01614 return true;
01615 }
01616 PT(FltMaterial) material = new FltMaterial(this);
01617 if (!material->extract_14_record(i, iterator)) {
01618 return false;
01619 }
01620 add_material(material);
01621 }
01622
01623 check_remaining_size(iterator, "material palette");
01624 return true;
01625 }
01626
01627
01628
01629
01630
01631
01632 bool FltHeader::
01633 extract_texture(FltRecordReader &reader) {
01634 FltTexture *texture = new FltTexture(this);
01635 if (!texture->extract_record(reader)) {
01636 return false;
01637 }
01638 add_texture(texture);
01639
01640 return true;
01641 }
01642
01643
01644
01645
01646
01647
01648
01649
01650 bool FltHeader::
01651 extract_texture_map(FltRecordReader &reader) {
01652
01653
01654
01655
01656 FltUnsupportedRecord *rec = new FltUnsupportedRecord(this);
01657 if (!rec->extract_record(reader)) {
01658 return false;
01659 }
01660 add_ancillary(rec);
01661
01662 return true;
01663 }
01664
01665
01666
01667
01668
01669
01670 bool FltHeader::
01671 extract_light_source(FltRecordReader &reader) {
01672 FltLightSourceDefinition *light_source = new FltLightSourceDefinition(this);
01673 if (!light_source->extract_record(reader)) {
01674 return false;
01675 }
01676 add_light_source(light_source);
01677
01678 return true;
01679 }
01680
01681
01682
01683
01684
01685
01686 bool FltHeader::
01687 extract_eyepoint_palette(FltRecordReader &reader) {
01688 nassertr(reader.get_opcode() == FO_eyepoint_palette, false);
01689 DatagramIterator &iterator = reader.get_iterator();
01690
01691 iterator.skip_bytes(4);
01692
01693 int i;
01694 int num_eyepoints = get_num_eyepoints();
01695 for (i = 0; i < num_eyepoints; i++) {
01696 if (!_eyepoints[i].extract_record(reader)) {
01697 return false;
01698 }
01699 }
01700
01701 int num_trackplanes = get_num_trackplanes();
01702 for (i = 0; i < num_trackplanes; i++) {
01703 if (!_trackplanes[i].extract_record(reader)) {
01704 return false;
01705 }
01706 }
01707
01708 _got_eyepoint_trackplane_palette = true;
01709
01710 if (get_flt_version() >= 1420) {
01711
01712
01713
01714 check_remaining_size(iterator, "eyepoint palette");
01715 }
01716 return true;
01717 }
01718
01719
01720
01721
01722
01723
01724
01725 FltError FltHeader::
01726 write_vertex_palette(FltRecordWriter &writer) const {
01727 FltError result;
01728
01729 int vertex_palette_length =
01730 ((FltHeader *)this)->update_vertex_lookups();
01731 Datagram vertex_palette;
01732 vertex_palette.add_be_int32(vertex_palette_length);
01733 result = writer.write_record(FO_vertex_palette, vertex_palette);
01734 if (result != FE_ok) {
01735 return result;
01736 }
01737
01738 Vertices::const_iterator vi;
01739 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
01740 FltVertex *vertex = (*vi);
01741 vertex->build_record(writer);
01742 result = writer.advance();
01743 if (result != FE_ok) {
01744 return result;
01745 }
01746 }
01747
01748 return FE_ok;
01749 }
01750
01751
01752
01753
01754
01755
01756
01757 FltError FltHeader::
01758 write_color_palette(FltRecordWriter &writer) const {
01759 writer.set_opcode(FO_color_palette);
01760 Datagram &datagram = writer.update_datagram();
01761
01762 datagram.pad_bytes(128);
01763
01764
01765 int num_colors = 1024;
01766
01767 Colors::const_iterator ci;
01768 for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
01769 if (!(*ci).build_record(writer)) {
01770 assert(!flt_error_abort);
01771 return FE_invalid_record;
01772 }
01773 num_colors--;
01774 }
01775
01776
01777
01778 if (num_colors > 0) {
01779 FltPackedColor empty;
01780 while (num_colors > 0) {
01781 if (!empty.build_record(writer)) {
01782 assert(!flt_error_abort);
01783 return FE_invalid_record;
01784 }
01785 num_colors--;
01786 }
01787 }
01788
01789
01790 ColorNames::const_iterator ni;
01791 for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
01792 string name = (*ni).second.substr(0, 80);
01793 int entry_length = name.length() + 8;
01794 datagram.add_be_uint16(entry_length);
01795 datagram.pad_bytes(2);
01796 datagram.add_be_uint16((*ni).first);
01797 datagram.pad_bytes(2);
01798 datagram.add_fixed_string(name, name.length());
01799 }
01800
01801 return writer.advance();
01802 }
01803
01804
01805
01806
01807
01808
01809 FltError FltHeader::
01810 write_material_palette(FltRecordWriter &writer) const {
01811 FltError result;
01812
01813 if (get_flt_version() >= 1520) {
01814
01815 Materials::const_iterator mi;
01816 for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
01817 FltMaterial *material = (*mi).second;
01818 material->build_record(writer);
01819
01820 result = writer.advance();
01821 if (result != FE_ok) {
01822 return result;
01823 }
01824 }
01825
01826 } else {
01827
01828 if (_materials.empty()) {
01829
01830 return FE_ok;
01831 }
01832 writer.set_opcode(FO_14_material_palette);
01833 Datagram &datagram = writer.update_datagram();
01834
01835 PT(FltMaterial) dummy_material = new FltMaterial(_header);
01836
01837 Materials::const_iterator mi = _materials.lower_bound(0);
01838 int index;
01839 static const int expected_material_entries = 64;
01840 for (index = 0; index < expected_material_entries; index++) {
01841 if (mi == _materials.end() || index < (*mi).first) {
01842 dummy_material->build_14_record(datagram);
01843 } else {
01844 nassertr(index == (*mi).first, FE_internal);
01845 FltMaterial *material = (*mi).second;
01846 material->build_14_record(datagram);
01847 ++mi;
01848 }
01849 }
01850
01851 result = writer.advance();
01852 if (result != FE_ok) {
01853 return result;
01854 }
01855 }
01856
01857 return FE_ok;
01858 }
01859
01860
01861
01862
01863
01864
01865 FltError FltHeader::
01866 write_texture_palette(FltRecordWriter &writer) const {
01867 FltError result;
01868
01869 Textures::const_iterator ti;
01870 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
01871 FltTexture *texture = (*ti).second;
01872 texture->build_record(writer);
01873 result = writer.advance();
01874 if (result != FE_ok) {
01875 return result;
01876 }
01877 }
01878
01879 return FE_ok;
01880 }
01881
01882
01883
01884
01885
01886
01887 FltError FltHeader::
01888 write_light_source_palette(FltRecordWriter &writer) const {
01889 FltError result;
01890
01891 LightSources::const_iterator li;
01892 for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
01893 FltLightSourceDefinition *light_source = (*li).second;
01894 light_source->build_record(writer);
01895 result = writer.advance();
01896 if (result != FE_ok) {
01897 return result;
01898 }
01899 }
01900
01901 return FE_ok;
01902 }
01903
01904
01905
01906
01907
01908
01909
01910 FltError FltHeader::
01911 write_eyepoint_palette(FltRecordWriter &writer) const {
01912 if (!_got_eyepoint_trackplane_palette) {
01913 return FE_ok;
01914 }
01915
01916 writer.set_opcode(FO_eyepoint_palette);
01917 Datagram &datagram = writer.update_datagram();
01918 datagram.pad_bytes(4);
01919
01920 int i;
01921 int num_eyepoints = get_num_eyepoints();
01922 for (i = 0; i < num_eyepoints; i++) {
01923 if (!_eyepoints[i].build_record(writer)) {
01924 assert(!flt_error_abort);
01925 return FE_bad_data;
01926 }
01927 }
01928
01929 int num_trackplanes = get_num_trackplanes();
01930 for (i = 0; i < num_trackplanes; i++) {
01931 if (!_trackplanes[i].build_record(writer)) {
01932 assert(!flt_error_abort);
01933 return FE_bad_data;
01934 }
01935 }
01936
01937 return writer.advance();
01938 }