15 #include "fltHeader.h" 16 #include "fltRecordReader.h" 17 #include "fltRecordWriter.h" 18 #include "fltUnsupportedRecord.h" 19 #include "config_flt.h" 21 #include "nearly_zero.h" 22 #include "virtualFileSystem.h" 48 _path_replace->_path_store = PS_absolute;
50 _path_replace = path_replace;
53 _format_revision_level = 1570;
54 _edit_revision_level = 1570;
60 _vertex_units = U_feet;
61 _texwhite_new =
false;
63 _projection_type = PT_flat_earth;
65 _vertex_storage_type = VTS_double;
66 _database_origin = DO_open_flight;
83 _lambert_upper_lat = 0.0;
84 _lambert_lower_lat = 0.0;
90 _earth_model = EM_wgs84;
93 _next_adaptive_id = 0;
101 _vertex_lookups_stale =
false;
102 _current_vertex_offset = 0;
103 _next_material_index = 1;
104 _next_pattern_index = 1;
105 _got_color_palette =
false;
106 _got_14_material_palette =
false;
107 _got_eyepoint_trackplane_palette =
false;
109 _auto_attr_update = AU_if_missing;
123 Textures::const_iterator ti;
124 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
141 _path_replace = path_replace;
154 return _path_replace;
167 return _path_replace;
180 if (!_flt_filename.empty()) {
184 return _path_replace->convert_path(orig_filename, file_path);
196 _flt_filename = flt_filename;
207 return _flt_filename;
220 _flt_filename = filename;
224 if (in == (istream *)NULL) {
225 assert(!flt_error_abort);
226 return FE_could_not_open;
243 FltError result = reader.
advance();
244 if (result == FE_end_of_file) {
245 assert(!flt_error_abort);
246 return FE_empty_file;
247 }
else if (result != FE_ok) {
251 result = read_record_and_children(reader);
252 if (result != FE_ok) {
257 assert(!flt_error_abort);
258 return FE_extra_data;
278 assert(!flt_error_abort);
279 return FE_could_not_open;
286 OCompressStream compressor(&out,
false);
304 FltError result = write_record_and_children(writer);
307 assert(!flt_error_abort);
308 return FE_write_error;
337 _auto_attr_update = attr;
348 return _auto_attr_update;
360 if (_format_revision_level < 1420) {
361 return _format_revision_level * 100;
363 return _format_revision_level;
376 if (version < 14.2) {
377 _format_revision_level = version / 100;
379 _format_revision_level = version;
422 nout <<
"Warning! The version number of this file appears to be " 423 << version / 100.0 <<
", which is older than " <<
min_flt_version() / 100.0
424 <<
", the oldest OpenFlight version understood by this program. " 425 "It is unlikely that this program will be able to read the file " 431 nout <<
"Warning! The version number of this file appears to be " 432 << version / 100.0 <<
", which is newer than " <<
max_flt_version() / 100.0
433 <<
", the newest OpenFlight version understood by this program. " 434 "Chances are good that the program will still be able to read it " 435 "correctly, but any features in the file that are specific to " 436 "the latest version of OpenFlight will not be understood.\n";
452 switch (_vertex_units) {
453 case FltHeader::U_meters:
456 case FltHeader::U_kilometers:
457 return DU_kilometers;
459 case FltHeader::U_feet:
462 case FltHeader::U_inches:
465 case FltHeader::U_nautical_miles:
466 return DU_nautical_miles;
481 return (_instances.count(instance_index) != 0);
492 Instances::const_iterator mi;
493 mi = _instances.find(instance_index);
494 if (mi != _instances.end()) {
521 _instances[instance->_instance_index] = instance;
532 _instances.erase(instance_index);
542 return _vertices.size();
552 nassertr(n >= 0 && n < (
int)_vertices.size(), 0);
564 _unique_vertices.clear();
565 _vertices_by_offset.clear();
566 _offsets_by_vertex.clear();
567 _vertex_lookups_stale =
false;
579 bool inserted = _unique_vertices.insert(vertex).second;
581 _vertices.push_back(vertex);
583 _vertex_lookups_stale =
true;
584 nassertv(_unique_vertices.size() == _vertices.size());
597 if (_vertex_lookups_stale) {
598 update_vertex_lookups();
601 VerticesByOffset::const_iterator vi;
602 vi = _vertices_by_offset.find(offset);
603 if (vi == _vertices_by_offset.end()) {
604 nout <<
"No vertex with offset " << offset <<
"\n";
620 if (_vertex_lookups_stale) {
621 update_vertex_lookups();
624 OffsetsByVertex::const_iterator vi;
625 vi = _offsets_by_vertex.find(vertex);
626 if (vi == _offsets_by_vertex.end()) {
627 nout <<
"Vertex does not appear in palette.\n";
661 LColor(0.0, 0.0, 0.0, 0.0));
664 int index = (color_index / num_color_shades);
665 int level = (color_index % num_color_shades);
666 nassertr(index >= 0 && index < (
int)_colors.size(),
667 LColor(0.0, 0.0, 0.0, 0.0));
670 return color * ((double)level / (
double)(num_color_shades - 1));
686 int index = (color_index / num_color_shades);
687 int level = (color_index % num_color_shades);
688 nassertr(index >= 0 && index < (
int)_colors.size(),
692 return color * ((double)level / (
double)(num_color_shades - 1));
703 return (_color_names.count(color_index) != 0);
714 ColorNames::const_iterator ni;
715 ni = _color_names.find(color_index);
716 if (ni != _color_names.end()) {
740 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
743 color.set(1.0, 1.0, 1.0, 1.0);
746 if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
750 }
else if (color[1] >= color[2] && color[1] >= color[3]) {
754 }
else if (color[2] >= color[3]) {
766 PN_stdfloat best_dist = 5.0;
770 for (
int i = 0; i < num_color_entries; i++) {
771 LColor consider = _colors[i].get_color();
772 PN_stdfloat dist2 = dot(consider - color, consider - color);
773 nassertr(dist2 < 5.0, 0);
775 if (dist2 < best_dist) {
780 nassertr(best_i >= 0, 0);
783 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
785 return (best_i * num_color_shades) + shade_index;
806 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
809 color.set(1.0, 1.0, 1.0);
812 if (color[0] >= color[1] && color[0] >= color[2]) {
816 }
else if (color[1] >= color[2]) {
828 PN_stdfloat best_dist = 5.0;
832 for (
int i = 0; i < num_color_entries; i++) {
833 LRGBColor consider = _colors[i].get_rgb();
834 PN_stdfloat dist2 = dot(consider - color, consider - color);
835 nassertr(dist2 < 5.0, 0);
837 if (dist2 < best_dist) {
842 nassertr(best_i >= 0, 0);
845 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
847 return (best_i * num_color_shades) + shade_index;
859 return _colors.size();
888 if (!use_packed_color) {
893 color[0] = packed_color._r / 255.0;
894 color[1] = packed_color._g / 255.0;
895 color[2] = packed_color._b / 255.0;
898 color[3] = 1.0 - (transparency / 65535.0);
912 get_rgb(
int color_index,
bool use_packed_color,
914 if (!use_packed_color) {
919 color[0] = packed_color._r / 255.0;
920 color[1] = packed_color._g / 255.0;
921 color[2] = packed_color._b / 255.0;
933 return (_materials.count(material_index) != 0);
944 Materials::const_iterator mi;
945 mi = _materials.find(material_index);
946 if (mi != _materials.end()) {
972 if (material->_material_index < 0) {
974 material->_material_index = _next_material_index;
975 _next_material_index++;
980 _next_material_index = max(_next_material_index, material->_material_index + 1);
983 _materials[material->_material_index] = material;
994 _materials.erase(material_index);
1005 return (_textures.count(texture_index) != 0);
1016 Textures::const_iterator mi;
1017 mi = _textures.find(texture_index);
1018 if (mi != _textures.end()) {
1019 return (*mi).second;
1044 if (texture->_pattern_index < 0) {
1046 texture->_pattern_index = _next_pattern_index;
1047 _next_pattern_index++;
1052 _next_pattern_index = max(_next_pattern_index, texture->_pattern_index + 1);
1055 _textures[texture->_pattern_index] = texture;
1066 _textures.erase(texture_index);
1077 return (_light_sources.count(light_index) != 0);
1088 LightSources::const_iterator li;
1089 li = _light_sources.find(light_index);
1090 if (li != _light_sources.end()) {
1091 return (*li).second;
1103 _light_sources.clear();
1116 _light_sources[light_source->_light_index] = light_source;
1127 _light_sources.erase(light_index);
1139 return _got_eyepoint_trackplane_palette;
1153 _got_eyepoint_trackplane_palette = flag;
1177 return &_eyepoints[n];
1201 return &_trackplanes[n];
1216 update_vertex_lookups() {
1220 Vertices::const_iterator vi;
1221 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1224 _offsets_by_vertex[vertex] = offset;
1225 _vertices_by_offset[offset] = vertex;
1229 _vertex_lookups_stale =
false;
1244 if (!FltBeadID::extract_record(reader)) {
1248 nassertr(reader.
get_opcode() == FO_header,
false);
1251 _format_revision_level = iterator.get_be_int32();
1252 _edit_revision_level = iterator.get_be_int32();
1253 _last_revision = iterator.get_fixed_string(32);
1254 _next_group_id = iterator.get_be_int16();
1255 _next_lod_id = iterator.get_be_int16();
1256 _next_object_id = iterator.get_be_int16();
1257 _next_face_id = iterator.get_be_int16();
1258 _unit_multiplier = iterator.get_be_int16();
1259 _vertex_units = (Units)iterator.get_int8();
1260 _texwhite_new = (iterator.get_int8() != 0);
1261 _flags = iterator.get_be_uint32();
1262 iterator.skip_bytes(24);
1263 _projection_type = (ProjectionType)iterator.get_be_int32();
1264 iterator.skip_bytes(28);
1265 _next_dof_id = iterator.get_be_int16();
1266 _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
1267 _database_origin = (DatabaseOrigin)iterator.get_be_int32();
1268 _sw_x = iterator.get_be_float64();
1269 _sw_y = iterator.get_be_float64();
1270 _delta_x = iterator.get_be_float64();
1271 _delta_y = iterator.get_be_float64();
1272 _next_sound_id = iterator.get_be_int16();
1273 _next_path_id = iterator.get_be_int16();
1274 iterator.skip_bytes(8);
1275 _next_clip_id = iterator.get_be_int16();
1276 _next_text_id = iterator.get_be_int16();
1277 _next_bsp_id = iterator.get_be_int16();
1278 _next_switch_id = iterator.get_be_int16();
1279 iterator.skip_bytes(4);
1280 _sw_lat = iterator.get_be_float64();
1281 _sw_long = iterator.get_be_float64();
1282 _ne_lat = iterator.get_be_float64();
1283 _ne_long = iterator.get_be_float64();
1284 _origin_lat = iterator.get_be_float64();
1285 _origin_long = iterator.get_be_float64();
1286 _lambert_upper_lat = iterator.get_be_float64();
1287 _lambert_lower_lat = iterator.get_be_float64();
1288 _next_light_id = iterator.get_be_int16();
1289 iterator.skip_bytes(2);
1291 _next_road_id = iterator.get_be_int16();
1292 _next_cat_id = iterator.get_be_int16();
1295 iterator.skip_bytes(2 + 2 + 2 + 2);
1296 _earth_model = (EarthModel)iterator.get_be_int32();
1299 iterator.skip_bytes(4);
1302 _next_adaptive_id = iterator.get_be_int16();
1303 _next_curve_id = iterator.get_be_int16();
1304 iterator.skip_bytes(4);
1307 _delta_z = iterator.get_be_float64();
1308 _radius = iterator.get_be_float64();
1309 _next_mesh_id = iterator.get_be_int16();
1310 iterator.skip_bytes(2);
1313 iterator.skip_bytes(4);
1335 case FO_vertex_palette:
1346 return extract_vertex(reader);
1348 case FO_color_palette:
1349 return extract_color_palette(reader);
1351 case FO_15_material:
1352 return extract_material(reader);
1354 case FO_14_material_palette:
1355 return extract_14_material_palette(reader);
1358 return extract_texture(reader);
1360 case FO_texture_map_palette:
1361 return extract_texture_map(reader);
1363 case FO_light_definition:
1364 return extract_light_source(reader);
1366 case FO_eyepoint_palette:
1367 return extract_eyepoint_palette(reader);
1370 return FltBeadID::extract_ancillary(reader);
1384 if (!FltBeadID::build_record(writer)) {
1467 FltError FltHeader::
1471 result = write_color_palette(writer);
1472 if (result != FE_ok) {
1476 result = write_material_palette(writer);
1477 if (result != FE_ok) {
1481 result = write_texture_palette(writer);
1482 if (result != FE_ok) {
1486 result = write_light_source_palette(writer);
1487 if (result != FE_ok) {
1491 result = write_eyepoint_palette(writer);
1492 if (result != FE_ok) {
1496 result = write_vertex_palette(writer);
1497 if (result != FE_ok) {
1501 return FltBeadID::write_ancillary(writer);
1514 if (!vertex->extract_record(reader)) {
1517 _vertices.push_back(vertex);
1518 _unique_vertices.insert(vertex);
1519 _offsets_by_vertex[vertex] = _current_vertex_offset;
1520 _vertices_by_offset[_current_vertex_offset] = vertex;
1535 nassertr(reader.
get_opcode() == FO_color_palette,
false);
1538 if (_got_color_palette) {
1539 nout <<
"Warning: multiple color palettes found.\n";
1541 _got_color_palette =
true;
1543 static const int expected_color_entries = 1024;
1545 iterator.skip_bytes(128);
1547 for (
int i = 0; i < expected_color_entries; i++) {
1548 if (iterator.get_remaining_size() == 0) {
1553 if (!color.extract_record(reader)) {
1556 _colors.push_back(color);
1560 while (iterator.get_remaining_size() > 0) {
1561 int entry_length = iterator.get_be_uint16();
1562 iterator.skip_bytes(2);
1563 if (iterator.get_remaining_size() > 0) {
1564 int color_index = iterator.get_be_int16();
1565 iterator.skip_bytes(2);
1567 int name_length = entry_length - 8;
1568 nassertr(color_index >= 0 && color_index < (
int)_colors.size(),
false);
1569 _color_names[color_index] = iterator.get_fixed_string(name_length);
1585 if (!material->extract_record(reader)) {
1600 nassertr(reader.
get_opcode() == FO_14_material_palette,
false);
1603 if (_got_14_material_palette) {
1604 nout <<
"Warning: multiple material palettes found.\n";
1606 _got_14_material_palette =
true;
1608 static const int expected_material_entries = 64;
1611 for (
int i = 0; i < expected_material_entries; i++) {
1612 if (iterator.get_remaining_size() == 0) {
1617 if (!material->extract_14_record(i, iterator)) {
1635 if (!texture->extract_record(reader)) {
1657 if (!rec->extract_record(reader)) {
1673 if (!light_source->extract_record(reader)) {
1688 nassertr(reader.
get_opcode() == FO_eyepoint_palette,
false);
1695 for (i = 0; i < num_eyepoints; i++) {
1696 if (!_eyepoints[i].extract_record(reader)) {
1702 for (i = 0; i < num_trackplanes; i++) {
1703 if (!_trackplanes[i].extract_record(reader)) {
1708 _got_eyepoint_trackplane_palette =
true;
1725 FltError FltHeader::
1729 int vertex_palette_length =
1730 ((
FltHeader *)
this)->update_vertex_lookups();
1733 result = writer.
write_record(FO_vertex_palette, vertex_palette);
1734 if (result != FE_ok) {
1738 Vertices::const_iterator vi;
1739 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1741 vertex->build_record(writer);
1743 if (result != FE_ok) {
1757 FltError FltHeader::
1765 int num_colors = 1024;
1767 Colors::const_iterator ci;
1768 for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
1769 if (!(*ci).build_record(writer)) {
1770 assert(!flt_error_abort);
1771 return FE_invalid_record;
1778 if (num_colors > 0) {
1780 while (num_colors > 0) {
1781 if (!empty.build_record(writer)) {
1782 assert(!flt_error_abort);
1783 return FE_invalid_record;
1790 ColorNames::const_iterator ni;
1791 for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
1792 string name = (*ni).second.substr(0, 80);
1793 int entry_length = name.length() + 8;
1809 FltError FltHeader::
1815 Materials::const_iterator mi;
1816 for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
1818 material->build_record(writer);
1821 if (result != FE_ok) {
1828 if (_materials.empty()) {
1837 Materials::const_iterator mi = _materials.lower_bound(0);
1839 static const int expected_material_entries = 64;
1840 for (index = 0; index < expected_material_entries; index++) {
1841 if (mi == _materials.end() || index < (*mi).first) {
1842 dummy_material->build_14_record(datagram);
1844 nassertr(index == (*mi).first, FE_internal);
1852 if (result != FE_ok) {
1865 FltError FltHeader::
1869 Textures::const_iterator ti;
1870 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
1872 texture->build_record(writer);
1874 if (result != FE_ok) {
1887 FltError FltHeader::
1891 LightSources::const_iterator li;
1892 for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
1894 light_source->build_record(writer);
1896 if (result != FE_ok) {
1910 FltError FltHeader::
1912 if (!_got_eyepoint_trackplane_palette) {
1922 for (i = 0; i < num_eyepoints; i++) {
1923 if (!_eyepoints[i].build_record(writer)) {
1924 assert(!flt_error_abort);
1930 for (i = 0; i < num_trackplanes; i++) {
1931 if (!_trackplanes[i].build_record(writer)) {
1932 assert(!flt_error_abort);
string get_dirname() const
Returns the directory part of the filename.
A single eyepoint entry in the eyepoint/trackplane palette.
This is the base class for all three-component vectors and points.
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly...
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
A base class for any of a broad family of flt beads that include an ID.
This class turns an istream into a sequence of FltRecords by reading a sequence of Datagrams and extr...
bool build_14_record(Datagram &datagram)
Fills up the current record on the FltRecordWriter with data for this record, formatted as a part of ...
int get_record_length() const
Returns the length of this record in bytes as it will be written to the flt file. ...
void add_int8(PN_int8 value)
Adds a signed 8-bit integer to the datagram.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read...
void set_binary()
Indicates that the filename represents a binary file.
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
Represents a single material in the material palette.
void check_remaining_size(const DatagramIterator &di, const string &name=string()) const
Checks that the iterator has no bytes left, as it should at the end of a successfully read record...
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
string get_extension() const
Returns the file extension.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
void pad_bytes(size_t size)
Adds the indicated number of zero bytes to the datagram.
void append_path(const string &path, const string &separator=string())
Adds all of the directories listed in the search path to the end of the search list.
void add_be_float64(PN_float64 value)
Adds a 64-bit big-endian floating-point number to the datagram.
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
A single trackplane entry in the eyepoint/trackplane palette.
Represents a single entry in the light source palette.
Represents a single texture in the texture palette.
The name of a file, such as a texture file or an Egg file.
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
A packed color record, A, B, G, R.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Represents a single vertex in the vertex palette.
void add_be_int32(PN_int32 value)
Adds a signed 32-bit big-endian integer to the datagram.
FltError advance()
Writes the current record to the flt file, and resets the current record to receive new data...
This is the base class for all three-component vectors and points.
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
This class stores a list of directories that can be searched, in order, to locate a particular file...
void add_fixed_string(const string &str, size_t size)
Adds a fixed-length string to the datagram.
void add_be_uint16(PN_uint16 value)
Adds an unsigned 16-bit big-endian integer to the datagram.
A class to retrieve the individual data elements previously stored in a Datagram. ...
void add_ancillary(FltRecord *ancillary)
Adds a new unsupported ancillary record to the end of the list of ancillary records for this record...
void add_be_uint32(PN_uint32 value)
Adds an unsigned 32-bit big-endian integer to the datagram.
TypeHandle is the identifier used to differentiate C++ class types.
void set_opcode(FltOpcode opcode)
Sets the opcode associated with the current record.
Datagram & update_datagram()
Returns a modifiable reference to the datagram associated with the current record.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
This special kind of record marks the top node of an instance subtree.
void add_be_int16(PN_int16 value)
Adds a signed 16-bit big-endian integer to the datagram.
bool eof() const
Returns true if end-of-file has been reached without error.
FltError write_record(FltOpcode opcode, const Datagram &datagram=Datagram())
A convenience function to quickly write a simple record that consists of an opcode and possibly a dat...
int get_record_length() const
Returns the entire length of the record, including the four-byte header.