40 if (path_replace ==
nullptr) {
42 _path_replace->_path_store = PS_absolute;
44 _path_replace = path_replace;
47 _format_revision_level = 1570;
48 _edit_revision_level = 1570;
54 _vertex_units = U_feet;
55 _texwhite_new =
false;
57 _projection_type = PT_flat_earth;
59 _vertex_storage_type = VTS_double;
60 _database_origin = DO_open_flight;
77 _lambert_upper_lat = 0.0;
78 _lambert_lower_lat = 0.0;
84 _earth_model = EM_wgs84;
87 _next_adaptive_id = 0;
95 _vertex_lookups_stale =
false;
96 _current_vertex_offset = 0;
97 _next_material_index = 1;
98 _next_pattern_index = 1;
99 _got_color_palette =
false;
100 _got_14_material_palette =
false;
101 _got_eyepoint_trackplane_palette =
false;
103 _auto_attr_update = AU_if_missing;
114 Textures::const_iterator ti;
115 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
129 _path_replace = path_replace;
139 return _path_replace;
149 return _path_replace;
159 if (!_flt_filename.empty()) {
163 return _path_replace->convert_path(orig_filename, file_path);
172 _flt_filename = flt_filename;
180 return _flt_filename;
190 _flt_filename = filename;
195 assert(!flt_error_abort);
196 return FE_could_not_open;
210 FltError result = reader.
advance();
211 if (result == FE_end_of_file) {
212 assert(!flt_error_abort);
213 return FE_empty_file;
214 }
else if (result != FE_ok) {
218 result = read_record_and_children(reader);
219 if (result != FE_ok) {
224 assert(!flt_error_abort);
225 return FE_extra_data;
242 assert(!flt_error_abort);
243 return FE_could_not_open;
250 OCompressStream compressor(&out,
false);
265 FltError result = write_record_and_children(writer);
268 assert(!flt_error_abort);
269 return FE_write_error;
292 _auto_attr_update = attr;
301 return _auto_attr_update;
310 if (_format_revision_level < 1420) {
311 return _format_revision_level * 100;
313 return _format_revision_level;
323 if (version < 14.2) {
324 _format_revision_level = version / 100;
326 _format_revision_level = version;
361 nout <<
"Warning! The version number of this file appears to be " 362 << version / 100.0 <<
", which is older than " <<
min_flt_version() / 100.0
363 <<
", the oldest OpenFlight version understood by this program. " 364 "It is unlikely that this program will be able to read the file " 370 nout <<
"Warning! The version number of this file appears to be " 371 << version / 100.0 <<
", which is newer than " <<
max_flt_version() / 100.0
372 <<
", the newest OpenFlight version understood by this program. " 373 "Chances are good that the program will still be able to read it " 374 "correctly, but any features in the file that are specific to " 375 "the latest version of OpenFlight will not be understood.\n";
388 switch (_vertex_units) {
389 case FltHeader::U_meters:
392 case FltHeader::U_kilometers:
393 return DU_kilometers;
395 case FltHeader::U_feet:
398 case FltHeader::U_inches:
401 case FltHeader::U_nautical_miles:
402 return DU_nautical_miles;
414 return (_instances.count(instance_index) != 0);
423 Instances::const_iterator mi;
424 mi = _instances.find(instance_index);
425 if (mi != _instances.end()) {
446 _instances[instance->_instance_index] = instance;
454 _instances.erase(instance_index);
462 return _vertices.size();
470 nassertr(n >= 0 && n < (
int)_vertices.size(),
nullptr);
480 _unique_vertices.clear();
481 _vertices_by_offset.clear();
482 _offsets_by_vertex.clear();
483 _vertex_lookups_stale =
false;
492 bool inserted = _unique_vertices.insert(vertex).second;
494 _vertices.push_back(vertex);
496 _vertex_lookups_stale =
true;
497 nassertv(_unique_vertices.size() == _vertices.size());
507 if (_vertex_lookups_stale) {
508 update_vertex_lookups();
511 VerticesByOffset::const_iterator vi;
512 vi = _vertices_by_offset.find(offset);
513 if (vi == _vertices_by_offset.end()) {
514 nout <<
"No vertex with offset " << offset <<
"\n";
527 if (_vertex_lookups_stale) {
528 update_vertex_lookups();
531 OffsetsByVertex::const_iterator vi;
532 vi = _offsets_by_vertex.find(vertex);
533 if (vi == _offsets_by_vertex.end()) {
534 nout <<
"Vertex does not appear in palette.\n";
561 LColor(0.0, 0.0, 0.0, 0.0));
564 int index = (color_index / num_color_shades);
565 int level = (color_index % num_color_shades);
566 nassertr(index >= 0 && index < (
int)_colors.size(),
567 LColor(0.0, 0.0, 0.0, 0.0));
569 LColor color = _colors[index].get_color();
570 return color * ((double)level / (
double)(num_color_shades - 1));
580 LRGBColor(0.0, 0.0, 0.0));
583 int index = (color_index / num_color_shades);
584 int level = (color_index % num_color_shades);
585 nassertr(index >= 0 && index < (
int)_colors.size(),
586 LRGBColor(0.0, 0.0, 0.0));
588 LRGBColor color = _colors[index].get_rgb();
589 return color * ((double)level / (
double)(num_color_shades - 1));
597 return (_color_names.count(color_index) != 0);
605 ColorNames::const_iterator ni;
606 ni = _color_names.find(color_index);
607 if (ni != _color_names.end()) {
610 return std::string();
623 LColor color = color0;
627 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
630 color.set(1.0, 1.0, 1.0, 1.0);
633 if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
637 }
else if (color[1] >= color[2] && color[1] >= color[3]) {
641 }
else if (color[2] >= color[3]) {
653 PN_stdfloat best_dist = 5.0;
657 for (
int i = 0; i < num_color_entries; i++) {
658 LColor consider = _colors[i].get_color();
659 PN_stdfloat dist2 = dot(consider - color, consider - color);
660 nassertr(dist2 < 5.0, 0);
662 if (dist2 < best_dist) {
667 nassertr(best_i >= 0, 0);
670 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
672 return (best_i * num_color_shades) + shade_index;
686 LRGBColor color = color0;
689 if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
692 color.set(1.0, 1.0, 1.0);
695 if (color[0] >= color[1] && color[0] >= color[2]) {
699 }
else if (color[1] >= color[2]) {
711 PN_stdfloat best_dist = 5.0;
715 for (
int i = 0; i < num_color_entries; i++) {
716 LRGBColor consider = _colors[i].get_rgb();
717 PN_stdfloat dist2 = dot(consider - color, consider - color);
718 nassertr(dist2 < 5.0, 0);
720 if (dist2 < best_dist) {
725 nassertr(best_i >= 0, 0);
728 int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
730 return (best_i * num_color_shades) + shade_index;
739 return _colors.size();
761 if (!use_packed_color) {
766 color[0] = packed_color._r / 255.0;
767 color[1] = packed_color._g / 255.0;
768 color[2] = packed_color._b / 255.0;
771 color[3] = 1.0 - (transparency / 65535.0);
781 get_rgb(
int color_index,
bool use_packed_color,
783 if (!use_packed_color) {
788 color[0] = packed_color._r / 255.0;
789 color[1] = packed_color._g / 255.0;
790 color[2] = packed_color._b / 255.0;
799 return (_materials.count(material_index) != 0);
808 Materials::const_iterator mi;
809 mi = _materials.find(material_index);
810 if (mi != _materials.end()) {
831 if (material->_material_index < 0) {
833 material->_material_index = _next_material_index;
834 _next_material_index++;
839 _next_material_index = std::max(_next_material_index, material->_material_index + 1);
842 _materials[material->_material_index] = material;
850 _materials.erase(material_index);
858 return (_textures.count(texture_index) != 0);
867 Textures::const_iterator mi;
868 mi = _textures.find(texture_index);
869 if (mi != _textures.end()) {
890 if (texture->_pattern_index < 0) {
892 texture->_pattern_index = _next_pattern_index;
893 _next_pattern_index++;
898 _next_pattern_index = std::max(_next_pattern_index, texture->_pattern_index + 1);
901 _textures[texture->_pattern_index] = texture;
909 _textures.erase(texture_index);
917 return (_light_sources.count(light_index) != 0);
926 LightSources::const_iterator li;
927 li = _light_sources.find(light_index);
928 if (li != _light_sources.end()) {
939 _light_sources.clear();
949 _light_sources[light_source->_light_index] = light_source;
958 _light_sources.erase(light_index);
968 return _got_eyepoint_trackplane_palette;
979 _got_eyepoint_trackplane_palette = flag;
997 return &_eyepoints[n];
1015 return &_trackplanes[n];
1027 update_vertex_lookups() {
1031 Vertices::const_iterator vi;
1032 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1035 _offsets_by_vertex[vertex] = offset;
1036 _vertices_by_offset[offset] = vertex;
1040 _vertex_lookups_stale =
false;
1052 if (!FltBeadID::extract_record(reader)) {
1056 nassertr(reader.
get_opcode() == FO_header,
false);
1059 _format_revision_level = iterator.get_be_int32();
1060 _edit_revision_level = iterator.get_be_int32();
1061 _last_revision = iterator.get_fixed_string(32);
1062 _next_group_id = iterator.get_be_int16();
1063 _next_lod_id = iterator.get_be_int16();
1064 _next_object_id = iterator.get_be_int16();
1065 _next_face_id = iterator.get_be_int16();
1066 _unit_multiplier = iterator.get_be_int16();
1067 _vertex_units = (Units)iterator.get_int8();
1068 _texwhite_new = (iterator.get_int8() != 0);
1069 _flags = iterator.get_be_uint32();
1070 iterator.skip_bytes(24);
1071 _projection_type = (ProjectionType)iterator.get_be_int32();
1072 iterator.skip_bytes(28);
1073 _next_dof_id = iterator.get_be_int16();
1074 _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
1075 _database_origin = (DatabaseOrigin)iterator.get_be_int32();
1076 _sw_x = iterator.get_be_float64();
1077 _sw_y = iterator.get_be_float64();
1078 _delta_x = iterator.get_be_float64();
1079 _delta_y = iterator.get_be_float64();
1080 _next_sound_id = iterator.get_be_int16();
1081 _next_path_id = iterator.get_be_int16();
1082 iterator.skip_bytes(8);
1083 _next_clip_id = iterator.get_be_int16();
1084 _next_text_id = iterator.get_be_int16();
1085 _next_bsp_id = iterator.get_be_int16();
1086 _next_switch_id = iterator.get_be_int16();
1087 iterator.skip_bytes(4);
1088 _sw_lat = iterator.get_be_float64();
1089 _sw_long = iterator.get_be_float64();
1090 _ne_lat = iterator.get_be_float64();
1091 _ne_long = iterator.get_be_float64();
1092 _origin_lat = iterator.get_be_float64();
1093 _origin_long = iterator.get_be_float64();
1094 _lambert_upper_lat = iterator.get_be_float64();
1095 _lambert_lower_lat = iterator.get_be_float64();
1096 _next_light_id = iterator.get_be_int16();
1097 iterator.skip_bytes(2);
1099 _next_road_id = iterator.get_be_int16();
1100 _next_cat_id = iterator.get_be_int16();
1103 iterator.skip_bytes(2 + 2 + 2 + 2);
1104 _earth_model = (EarthModel)iterator.get_be_int32();
1107 iterator.skip_bytes(4);
1110 _next_adaptive_id = iterator.get_be_int16();
1111 _next_curve_id = iterator.get_be_int16();
1112 iterator.skip_bytes(4);
1115 _delta_z = iterator.get_be_float64();
1116 _radius = iterator.get_be_float64();
1117 _next_mesh_id = iterator.get_be_int16();
1118 iterator.skip_bytes(2);
1121 iterator.skip_bytes(4);
1139 case FO_vertex_palette:
1150 return extract_vertex(reader);
1152 case FO_color_palette:
1153 return extract_color_palette(reader);
1155 case FO_15_material:
1156 return extract_material(reader);
1158 case FO_14_material_palette:
1159 return extract_14_material_palette(reader);
1162 return extract_texture(reader);
1164 case FO_texture_map_palette:
1165 return extract_texture_map(reader);
1167 case FO_light_definition:
1168 return extract_light_source(reader);
1170 case FO_eyepoint_palette:
1171 return extract_eyepoint_palette(reader);
1174 return FltBeadID::extract_ancillary(reader);
1185 if (!FltBeadID::build_record(writer)) {
1265 FltError FltHeader::
1269 result = write_color_palette(writer);
1270 if (result != FE_ok) {
1274 result = write_material_palette(writer);
1275 if (result != FE_ok) {
1279 result = write_texture_palette(writer);
1280 if (result != FE_ok) {
1284 result = write_light_source_palette(writer);
1285 if (result != FE_ok) {
1289 result = write_eyepoint_palette(writer);
1290 if (result != FE_ok) {
1294 result = write_vertex_palette(writer);
1295 if (result != FE_ok) {
1299 return FltBeadID::write_ancillary(writer);
1309 if (!vertex->extract_record(reader)) {
1312 _vertices.push_back(vertex);
1313 _unique_vertices.insert(vertex);
1314 _offsets_by_vertex[vertex] = _current_vertex_offset;
1315 _vertices_by_offset[_current_vertex_offset] = vertex;
1328 nassertr(reader.
get_opcode() == FO_color_palette,
false);
1331 if (_got_color_palette) {
1332 nout <<
"Warning: multiple color palettes found.\n";
1334 _got_color_palette =
true;
1336 static const int expected_color_entries = 1024;
1338 iterator.skip_bytes(128);
1340 for (
int i = 0; i < expected_color_entries; i++) {
1341 if (iterator.get_remaining_size() == 0) {
1346 if (!color.extract_record(reader)) {
1349 _colors.push_back(color);
1353 while (iterator.get_remaining_size() > 0) {
1354 int entry_length = iterator.get_be_uint16();
1355 iterator.skip_bytes(2);
1356 if (iterator.get_remaining_size() > 0) {
1357 int color_index = iterator.get_be_int16();
1358 iterator.skip_bytes(2);
1360 int name_length = entry_length - 8;
1361 nassertr(color_index >= 0 && color_index < (
int)_colors.size(),
false);
1362 _color_names[color_index] = iterator.get_fixed_string(name_length);
1376 if (!material->extract_record(reader)) {
1389 nassertr(reader.
get_opcode() == FO_14_material_palette,
false);
1392 if (_got_14_material_palette) {
1393 nout <<
"Warning: multiple material palettes found.\n";
1395 _got_14_material_palette =
true;
1397 static const int expected_material_entries = 64;
1400 for (
int i = 0; i < expected_material_entries; i++) {
1401 if (iterator.get_remaining_size() == 0) {
1406 if (!material->extract_14_record(i, iterator)) {
1422 if (!texture->extract_record(reader)) {
1440 if (!rec->extract_record(reader)) {
1454 if (!light_source->extract_record(reader)) {
1467 nassertr(reader.
get_opcode() == FO_eyepoint_palette,
false);
1474 for (i = 0; i < num_eyepoints; i++) {
1475 if (!_eyepoints[i].extract_record(reader)) {
1481 for (i = 0; i < num_trackplanes; i++) {
1482 if (!_trackplanes[i].extract_record(reader)) {
1487 _got_eyepoint_trackplane_palette =
true;
1501 FltError FltHeader::
1505 int vertex_palette_length =
1506 ((
FltHeader *)
this)->update_vertex_lookups();
1509 result = writer.
write_record(FO_vertex_palette, vertex_palette);
1510 if (result != FE_ok) {
1514 Vertices::const_iterator vi;
1515 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1517 vertex->build_record(writer);
1519 if (result != FE_ok) {
1531 FltError FltHeader::
1539 int num_colors = 1024;
1541 Colors::const_iterator ci;
1542 for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
1543 if (!(*ci).build_record(writer)) {
1544 assert(!flt_error_abort);
1545 return FE_invalid_record;
1552 if (num_colors > 0) {
1554 while (num_colors > 0) {
1555 if (!empty.build_record(writer)) {
1556 assert(!flt_error_abort);
1557 return FE_invalid_record;
1564 ColorNames::const_iterator ni;
1565 for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
1566 std::string name = (*ni).second.substr(0, 80);
1567 int entry_length = name.length() + 8;
1581 FltError FltHeader::
1587 Materials::const_iterator mi;
1588 for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
1590 material->build_record(writer);
1593 if (result != FE_ok) {
1600 if (_materials.empty()) {
1609 Materials::const_iterator mi = _materials.lower_bound(0);
1611 static const int expected_material_entries = 64;
1612 for (index = 0; index < expected_material_entries; index++) {
1613 if (mi == _materials.end() || index < (*mi).first) {
1614 dummy_material->build_14_record(datagram);
1616 nassertr(index == (*mi).first, FE_internal);
1624 if (result != FE_ok) {
1635 FltError FltHeader::
1639 Textures::const_iterator ti;
1640 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
1642 texture->build_record(writer);
1644 if (result != FE_ok) {
1655 FltError FltHeader::
1659 LightSources::const_iterator li;
1660 for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
1662 light_source->build_record(writer);
1664 if (result != FE_ok) {
1675 FltError FltHeader::
1677 if (!_got_eyepoint_trackplane_palette) {
1687 for (i = 0; i < num_eyepoints; i++) {
1688 if (!_eyepoints[i].build_record(writer)) {
1689 assert(!flt_error_abort);
1695 for (i = 0; i < num_trackplanes; i++) {
1696 if (!_trackplanes[i].build_record(writer)) {
1697 assert(!flt_error_abort);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
std::string get_dirname() const
Returns the directory part of the filename.
A single eyepoint entry in the eyepoint/trackplane palette.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly.
A base class for any of a broad family of flt beads that include an ID.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void check_remaining_size(const DatagramIterator &di, const std::string &name=std::string()) const
Checks that the iterator has no bytes left, as it should at the end of a successfully read record.
A hierarchy of directories and files that appears to be one continuous file system,...
std::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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
void pad_bytes(size_t size)
Adds the indicated number of zero bytes to the datagram.
DistanceUnit
This enumerated type lists all the kinds of units we're likely to come across in model conversion pro...
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...
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
A single trackplane entry in the eyepoint/trackplane palette.
void add_int8(int8_t value)
Adds a signed 8-bit integer to the datagram.
Represents a single entry in the light source palette.
void add_be_uint16(uint16_t value)
Adds an unsigned 16-bit big-endian integer to the datagram.
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.
void add_be_int16(int16_t value)
Adds a signed 16-bit big-endian integer to the datagram.
A packed color record, A, B, G, R.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Represents a single vertex in the vertex palette.
void add_be_uint32(uint32_t value)
Adds an unsigned 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.
std::string get_extension() const
Returns the file extension.
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 append_path(const std::string &path, const std::string &separator=std::string())
Adds all of the directories listed in the search path to the end of the search list.
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_fixed_string(const std::string &str, size_t size)
Adds a fixed-length string to the datagram.
void add_be_int32(int32_t value)
Adds a signed 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.
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.