|
|
@@ -0,0 +1,1556 @@
|
|
|
+// Filename: fltHeader.cxx
|
|
|
+// Created by: drose (24Aug00)
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#include "fltHeader.h"
|
|
|
+#include "fltRecordReader.h"
|
|
|
+#include "fltRecordWriter.h"
|
|
|
+
|
|
|
+TypeHandle FltHeader::_type_handle;
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::Constructor
|
|
|
+// Access: Public
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltHeader::
|
|
|
+FltHeader() : FltBeadID(this) {
|
|
|
+ _format_revision_level = 1520;
|
|
|
+ _edit_revision_level = 1520;
|
|
|
+ _next_group_id = 1;
|
|
|
+ _next_lod_id = 1;
|
|
|
+ _next_object_id = 1;
|
|
|
+ _next_face_id = 1;
|
|
|
+ _unit_multiplier = 1;
|
|
|
+ _vertex_units = U_feet;
|
|
|
+ _texwhite_new = false;
|
|
|
+ _flags = 0;
|
|
|
+ _projection_type = PT_flat_earth;
|
|
|
+ _next_dof_id = 1;
|
|
|
+ _vertex_storage_type = VTS_double;
|
|
|
+ _database_origin = DO_open_flight;
|
|
|
+ _sw_x = 0.0;
|
|
|
+ _sw_y = 0.0;
|
|
|
+ _delta_x = 0.0;
|
|
|
+ _delta_y = 0.0;
|
|
|
+ _next_sound_id = 1;
|
|
|
+ _next_path_id = 1;
|
|
|
+ _next_clip_id = 1;
|
|
|
+ _next_text_id = 1;
|
|
|
+ _next_bsp_id = 1;
|
|
|
+ _next_switch_id = 1;
|
|
|
+ _sw_lat = 0.0;
|
|
|
+ _sw_long = 0.0;
|
|
|
+ _ne_lat = 0.0;
|
|
|
+ _ne_long = 0.0;
|
|
|
+ _origin_lat = 0.0;
|
|
|
+ _origin_long = 0.0;
|
|
|
+ _lambert_upper_lat = 0.0;
|
|
|
+ _lambert_lower_lat = 0.0;
|
|
|
+ _next_light_id = 1;
|
|
|
+ _next_road_id = 1;
|
|
|
+ _next_cat_id = 1;
|
|
|
+ _earth_model = EM_wgs84;
|
|
|
+
|
|
|
+ _vertex_lookups_stale = false;
|
|
|
+ _current_vertex_offset = 0;
|
|
|
+ _got_eyepoint_trackplane_palette = false;
|
|
|
+
|
|
|
+ _auto_attr_update = AU_if_missing;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::read_flt
|
|
|
+// Access: Public
|
|
|
+// Description: Opens the indicated filename for reading and attempts
|
|
|
+// to read the complete Flt file. Returns FE_ok on
|
|
|
+// success, otherwise on failure.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+read_flt(Filename filename) {
|
|
|
+ filename.set_binary();
|
|
|
+
|
|
|
+ ifstream in;
|
|
|
+ if (!filename.open_read(in)) {
|
|
|
+ return FE_could_not_open;
|
|
|
+ }
|
|
|
+
|
|
|
+ // By default, the filename's directory is added to the texture
|
|
|
+ // search path.
|
|
|
+ string dirname = filename.get_dirname();
|
|
|
+ if (!dirname.empty()) {
|
|
|
+ _texture_path.append_directory(dirname);
|
|
|
+ }
|
|
|
+
|
|
|
+ return read_flt(in);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::read_flt
|
|
|
+// Access: Public
|
|
|
+// Description: Attempts to read a complete Flt file from the
|
|
|
+// already-opened stream. Returns FE_ok on success,
|
|
|
+// otherwise on failure.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+read_flt(istream &in) {
|
|
|
+ FltRecordReader reader(in);
|
|
|
+ FltError result = reader.advance();
|
|
|
+ if (result == FE_end_of_file) {
|
|
|
+ return FE_empty_file;
|
|
|
+ } else if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = read_record_and_children(reader);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!reader.eof()) {
|
|
|
+ return FE_extra_data;
|
|
|
+ }
|
|
|
+
|
|
|
+ return FE_ok;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_flt
|
|
|
+// Access: Public
|
|
|
+// Description: Opens the indicated filename for writing and attempts
|
|
|
+// to write the complete Flt file. Returns FE_ok on
|
|
|
+// success, otherwise on failure.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_flt(Filename filename) {
|
|
|
+ filename.set_binary();
|
|
|
+
|
|
|
+ ofstream out;
|
|
|
+ if (!filename.open_write(out)) {
|
|
|
+ return FE_could_not_open;
|
|
|
+ }
|
|
|
+
|
|
|
+ return write_flt(out);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_flt
|
|
|
+// Access: Public
|
|
|
+// Description: Attempts to write a complete Flt file to the
|
|
|
+// already-opened stream. Returns FE_ok on success,
|
|
|
+// otherwise on failure.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_flt(ostream &out) {
|
|
|
+ FltRecordWriter writer(out);
|
|
|
+ FltError result = write_record_and_children(writer);
|
|
|
+
|
|
|
+ if (out.fail()) {
|
|
|
+ return FE_write_error;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::set_auto_attr_update
|
|
|
+// Access: Public
|
|
|
+// Description: Controls whether texture .attr files are written
|
|
|
+// automatically when write_flt() is called. There are
|
|
|
+// three possibilities:
|
|
|
+//
|
|
|
+// AU_none: the .attr files are not written
|
|
|
+// automatically; they must be written explicitly via a
|
|
|
+// call to FltTexture::write_attr_data() if you want
|
|
|
+// them to be written.
|
|
|
+//
|
|
|
+// AU_if_missing: the .attr files are written only if
|
|
|
+// they do not already exist. This will not update any
|
|
|
+// .attr files, even if the data is changed.
|
|
|
+//
|
|
|
+// AU_always: the .attr files are always rewritten, even
|
|
|
+// if they already exist and even if the data has not
|
|
|
+// changed.
|
|
|
+//
|
|
|
+// The default is AU_if_missing.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+set_auto_attr_update(FltHeader::AttrUpdate attr) {
|
|
|
+ _auto_attr_update = attr;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_auto_attr_update
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the current setting of the auto_attr_update
|
|
|
+// flag. See sett_auto_attr_update().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltHeader::AttrUpdate FltHeader::
|
|
|
+get_auto_attr_update() const {
|
|
|
+ return _auto_attr_update;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_flt_version
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the version number of the flt file as
|
|
|
+// reported in the header.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+double FltHeader::
|
|
|
+get_flt_version() const {
|
|
|
+ if (_format_revision_level < 1420) {
|
|
|
+ return _format_revision_level;
|
|
|
+ } else {
|
|
|
+ return _format_revision_level / 100.0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::min_flt_version
|
|
|
+// Access: Public, Static
|
|
|
+// Description: Returns the earliest flt version number that this
|
|
|
+// codebase supports. Earlier versions will probably
|
|
|
+// not work.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+double FltHeader::
|
|
|
+min_flt_version() {
|
|
|
+ return 15.2;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::max_flt_version
|
|
|
+// Access: Public, Static
|
|
|
+// Description: Returns the latest flt version number that this
|
|
|
+// codebase is known to support. Later versions might
|
|
|
+// work, but then again they may not.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+double FltHeader::
|
|
|
+max_flt_version() {
|
|
|
+ return 15.2;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::has_instance
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if a instance subtree with the given
|
|
|
+// index has been defined.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+has_instance(int instance_index) const {
|
|
|
+ return (_instances.count(instance_index) != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_instance
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the instance subtree associated with the
|
|
|
+// given index, or NULL if there is no such instance.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltInstanceDefinition *FltHeader::
|
|
|
+get_instance(int instance_index) const {
|
|
|
+ Instances::const_iterator mi;
|
|
|
+ mi = _instances.find(instance_index);
|
|
|
+ if (mi != _instances.end()) {
|
|
|
+ return (*mi).second;
|
|
|
+ }
|
|
|
+ return (FltInstanceDefinition *)NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::clear_instances
|
|
|
+// Access: Public
|
|
|
+// Description: Removes all instance subtrees from the instance pool.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+clear_instances() {
|
|
|
+ _instances.clear();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::add_instance
|
|
|
+// Access: Public
|
|
|
+// Description: Defines a new instance subtree. This subtree is not
|
|
|
+// itself part of the hierarchy; it marks geometry that
|
|
|
+// may be instanced to various beads elsewhere in the
|
|
|
+// hierarchy by creating a corresponding FltInstanceRef
|
|
|
+// bead.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+add_instance(FltInstanceDefinition *instance) {
|
|
|
+ _instances[instance->_instance_index] = instance;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::remove_instance
|
|
|
+// Access: Public
|
|
|
+// Description: Removes a particular instance subtree from the pool,
|
|
|
+// if it exists.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+remove_instance(int instance_index) {
|
|
|
+ _instances.erase(instance_index);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_vertices
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the number of vertices in the vertex palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_vertices() const {
|
|
|
+ return _vertices.size();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_vertex
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the nth vertex of the vertex palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltVertex *FltHeader::
|
|
|
+get_vertex(int n) const {
|
|
|
+ nassertr(n >= 0 && n < (int)_vertices.size(), 0);
|
|
|
+ return _vertices[n];
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::clear_vertices
|
|
|
+// Access: Public
|
|
|
+// Description: Removes all vertices from the vertex palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+clear_vertices() {
|
|
|
+ _vertices.clear();
|
|
|
+ _unique_vertices.clear();
|
|
|
+ _vertices_by_offset.clear();
|
|
|
+ _offsets_by_vertex.clear();
|
|
|
+ _vertex_lookups_stale = false;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::add_vertex
|
|
|
+// Access: Public
|
|
|
+// Description: Adds a new vertex to the end of the vertex palette.
|
|
|
+// If this particular vertex was already present in the
|
|
|
+// palette, does nothing.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+add_vertex(FltVertex *vertex) {
|
|
|
+ bool inserted = _unique_vertices.insert(vertex).second;
|
|
|
+ if (inserted) {
|
|
|
+ _vertices.push_back(vertex);
|
|
|
+ }
|
|
|
+ _vertex_lookups_stale = true;
|
|
|
+ nassertv(_unique_vertices.size() == _vertices.size());
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_vertex_by_offset
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the particular vertex pointer associated with
|
|
|
+// the given byte offset into the vertex palette. If
|
|
|
+// there is no such vertex in the palette, this
|
|
|
+// generates an error message and returns NULL.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltVertex *FltHeader::
|
|
|
+get_vertex_by_offset(int offset) {
|
|
|
+ if (_vertex_lookups_stale) {
|
|
|
+ update_vertex_lookups();
|
|
|
+ }
|
|
|
+
|
|
|
+ VerticesByOffset::const_iterator vi;
|
|
|
+ vi = _vertices_by_offset.find(offset);
|
|
|
+ if (vi == _vertices_by_offset.end()) {
|
|
|
+ nout << "No vertex with offset " << offset << "\n";
|
|
|
+ return (FltVertex *)NULL;
|
|
|
+ }
|
|
|
+ return (*vi).second;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_offset_by_vertex
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the byte offset into the vertex palette
|
|
|
+// associated with the given vertex pointer. If there
|
|
|
+// is no such vertex in the palette, this generates an
|
|
|
+// error message and returns 0.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_offset_by_vertex(FltVertex *vertex) {
|
|
|
+ if (_vertex_lookups_stale) {
|
|
|
+ update_vertex_lookups();
|
|
|
+ }
|
|
|
+
|
|
|
+ OffsetsByVertex::const_iterator vi;
|
|
|
+ vi = _offsets_by_vertex.find(vertex);
|
|
|
+ if (vi == _offsets_by_vertex.end()) {
|
|
|
+ nout << "Vertex does not appear in palette.\n";
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return (*vi).second;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_colors
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the total number of different colors in the
|
|
|
+// color palette. This includes all different colors,
|
|
|
+// and represents the complete range of alloable color
|
|
|
+// indices. This is different from the actual number of
|
|
|
+// color entries as read directly from the color
|
|
|
+// palette, since each color entry defines a number of
|
|
|
+// different intensity levels--the value returned by
|
|
|
+// get_num_colors() is equal to get_num_color_entries()
|
|
|
+// * get_num_color_shades().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_colors() const {
|
|
|
+ return _colors.size() * get_num_color_shades();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_color
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the four-component color corresponding to the
|
|
|
+// given color index. Each component will be in the
|
|
|
+// range [0, 1].
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+Colorf FltHeader::
|
|
|
+get_color(int color_index) const {
|
|
|
+ nassertr(color_index >= 0 && color_index < get_num_colors(),
|
|
|
+ Colorf(0.0, 0.0, 0.0, 0.0));
|
|
|
+ int num_color_shades = get_num_color_shades();
|
|
|
+
|
|
|
+ int index = (color_index / num_color_shades);
|
|
|
+ int level = (color_index % num_color_shades);
|
|
|
+ nassertr(index >= 0 && index < (int)_colors.size(),
|
|
|
+ Colorf(0.0, 0.0, 0.0, 0.0));
|
|
|
+
|
|
|
+ Colorf color = _colors[index].get_color();
|
|
|
+ return color * ((double)level / (double)(num_color_shades - 1));
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_rgb
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the three-component color corresponding to
|
|
|
+// the given color index, ignoring the alpha component.
|
|
|
+// Each component will be in the range [0, 1].
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+RGBColorf FltHeader::
|
|
|
+get_rgb(int color_index) const {
|
|
|
+ nassertr(color_index >= 0 && color_index < get_num_colors(),
|
|
|
+ RGBColorf(0.0, 0.0, 0.0));
|
|
|
+ int num_color_shades = get_num_color_shades();
|
|
|
+
|
|
|
+ int index = (color_index / num_color_shades);
|
|
|
+ int level = (color_index % num_color_shades);
|
|
|
+ nassertr(index >= 0 && index < (int)_colors.size(),
|
|
|
+ RGBColorf(0.0, 0.0, 0.0));
|
|
|
+
|
|
|
+ RGBColorf color = _colors[index].get_rgb();
|
|
|
+ return color * ((double)level / (double)(num_color_shades - 1));
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::has_color_name
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if the given color is named, false
|
|
|
+// otherwise.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+has_color_name(int color_index) const {
|
|
|
+ return (_color_names.count(color_index) != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_color_name
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the name associated with the given color, if
|
|
|
+// any.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+string FltHeader::
|
|
|
+get_color_name(int color_index) const {
|
|
|
+ ColorNames::const_iterator ni;
|
|
|
+ ni = _color_names.find(color_index);
|
|
|
+ if (ni != _color_names.end()) {
|
|
|
+ return (*ni).second;
|
|
|
+ }
|
|
|
+ return string();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_closest_color
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the color index of the nearest color in the
|
|
|
+// palette that matches the given four-component color,
|
|
|
+// including alpha.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_closest_color(Colorf color) const {
|
|
|
+ // Since the colortable stores the brightest colors, with
|
|
|
+ // num_color_shades scaled versions of each color implicitly
|
|
|
+ // available, we really only care about the relative brightnesses of
|
|
|
+ // the various components. Normalize the color in terms of the
|
|
|
+ // largest of these.
|
|
|
+
|
|
|
+ double scale = 1.0;
|
|
|
+
|
|
|
+ if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
|
|
|
+ // Oh, this is invisible black.
|
|
|
+ scale = 0.0;
|
|
|
+ color.set(1.0, 1.0, 1.0, 1.0);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
|
|
|
+ // color[0] is largest.
|
|
|
+ scale = color[0];
|
|
|
+
|
|
|
+ } else if (color[1] >= color[2] && color[1] >= color[3]) {
|
|
|
+ // color[1] is largest.
|
|
|
+ scale = color[1];
|
|
|
+
|
|
|
+ } else if (color[2] >= color[3]) {
|
|
|
+ // color[2] is largest.
|
|
|
+ scale = color[2];
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // color[3] is largest.
|
|
|
+ scale = color[3];
|
|
|
+ }
|
|
|
+ color /= scale;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now search for the best match.
|
|
|
+ float best_dist = 5.0; // Greater than 4.
|
|
|
+ int best_i = -1;
|
|
|
+
|
|
|
+ int num_color_entries = get_num_color_entries();
|
|
|
+ for (int i = 0; i < num_color_entries; i++) {
|
|
|
+ Colorf consider = _colors[i].get_color();
|
|
|
+ float dist2 = dot(consider - color, consider - color);
|
|
|
+ nassertr(dist2 < 5.0, 0);
|
|
|
+
|
|
|
+ if (dist2 < best_dist) {
|
|
|
+ best_dist = dist2;
|
|
|
+ best_i = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ nassertr(best_i >= 0, 0);
|
|
|
+
|
|
|
+ int num_color_shades = get_num_color_shades();
|
|
|
+ int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
|
|
|
+
|
|
|
+ return (best_i * num_color_shades) + shade_index;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_closest_color
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the color index of the nearest color in the
|
|
|
+// palette that matches the given three-component color,
|
|
|
+// ignoring alpha.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_closest_rgb(RGBColorf color) const {
|
|
|
+ // Since the colortable stores the brightest colors, with
|
|
|
+ // num_color_shades scaled versions of each color implicitly
|
|
|
+ // available, we really only care about the relative brightnesses of
|
|
|
+ // the various components. Normalize the color in terms of the
|
|
|
+ // largest of these.
|
|
|
+
|
|
|
+ double scale = 1.0;
|
|
|
+
|
|
|
+ if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
|
|
|
+ // Oh, this is black.
|
|
|
+ scale = 0.0;
|
|
|
+ color.set(1.0, 1.0, 1.0);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ if (color[0] >= color[1] && color[0] >= color[2]) {
|
|
|
+ // color[0] is largest.
|
|
|
+ scale = color[0];
|
|
|
+
|
|
|
+ } else if (color[1] >= color[2]) {
|
|
|
+ // color[1] is largest.
|
|
|
+ scale = color[1];
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // color[2] is largest.
|
|
|
+ scale = color[2];
|
|
|
+ }
|
|
|
+ color /= scale;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now search for the best match.
|
|
|
+ float best_dist = 5.0; // Greater than 4.
|
|
|
+ int best_i = -1;
|
|
|
+
|
|
|
+ int num_color_entries = get_num_color_entries();
|
|
|
+ for (int i = 0; i < num_color_entries; i++) {
|
|
|
+ RGBColorf consider = _colors[i].get_rgb();
|
|
|
+ float dist2 = dot(consider - color, consider - color);
|
|
|
+ nassertr(dist2 < 5.0, 0);
|
|
|
+
|
|
|
+ if (dist2 < best_dist) {
|
|
|
+ best_dist = dist2;
|
|
|
+ best_i = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ nassertr(best_i >= 0, 0);
|
|
|
+
|
|
|
+ int num_color_shades = get_num_color_shades();
|
|
|
+ int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
|
|
|
+
|
|
|
+ return (best_i * num_color_shades) + shade_index;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_color_entries
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the number of actual entries in the color
|
|
|
+// palette. This is based on the version of the flt
|
|
|
+// file, and is usually either 512 or 1024.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_color_entries() const {
|
|
|
+ return _colors.size();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_color_shades
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the number of shades of brightness of each
|
|
|
+// entry in the color palette. This is a fixed property
|
|
|
+// of MultiGen files: each entry in the palette actually
|
|
|
+// represents a range of this many colors.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_color_shades() const {
|
|
|
+ return 128;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_color
|
|
|
+// Access: Public
|
|
|
+// Description: Decodes a MultiGen color, as stored on a face or
|
|
|
+// vertex, into an actual four-component Colorf.
|
|
|
+// Normally you need not call this directly; there are
|
|
|
+// color accessors defined on faces and vertices that do
|
|
|
+// this.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+Colorf FltHeader::
|
|
|
+get_color(int color_index, bool use_packed_color,
|
|
|
+ const FltPackedColor &packed_color,
|
|
|
+ int transparency) {
|
|
|
+ if (!use_packed_color) {
|
|
|
+ return get_color(color_index);
|
|
|
+ }
|
|
|
+
|
|
|
+ Colorf color;
|
|
|
+ color[0] = packed_color._r / 255.0;
|
|
|
+ color[1] = packed_color._g / 255.0;
|
|
|
+ color[2] = packed_color._b / 255.0;
|
|
|
+ // MultiGen doesn't yet use the A component of RGBA.
|
|
|
+ //color[3] = packed_color._a / 255.0;
|
|
|
+ color[3] = 1.0 - (transparency / 65535.0);
|
|
|
+ return color;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_color
|
|
|
+// Access: Public
|
|
|
+// Description: Decodes a MultiGen color, as stored on a face or
|
|
|
+// vertex, into an actual three-component RGBColorf.
|
|
|
+// Normally you need not call this directly; there are
|
|
|
+// color accessors defined on faces and vertices that do
|
|
|
+// this.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+RGBColorf FltHeader::
|
|
|
+get_rgb(int color_index, bool use_packed_color,
|
|
|
+ const FltPackedColor &packed_color) {
|
|
|
+ if (!use_packed_color) {
|
|
|
+ return get_rgb(color_index);
|
|
|
+ }
|
|
|
+
|
|
|
+ RGBColorf color;
|
|
|
+ color[0] = packed_color._r / 255.0;
|
|
|
+ color[1] = packed_color._g / 255.0;
|
|
|
+ color[2] = packed_color._b / 255.0;
|
|
|
+ return color;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::has_material
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if a material with the given index has
|
|
|
+// been defined.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+has_material(int material_index) const {
|
|
|
+ return (_materials.count(material_index) != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_material
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the material associated with the given index,
|
|
|
+// or NULL if there is no such material.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltMaterial *FltHeader::
|
|
|
+get_material(int material_index) const {
|
|
|
+ Materials::const_iterator mi;
|
|
|
+ mi = _materials.find(material_index);
|
|
|
+ if (mi != _materials.end()) {
|
|
|
+ return (*mi).second;
|
|
|
+ }
|
|
|
+ return (FltMaterial *)NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::clear_materials
|
|
|
+// Access: Public
|
|
|
+// Description: Removes all materials from the palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+clear_materials() {
|
|
|
+ _materials.clear();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::add_material
|
|
|
+// Access: Public
|
|
|
+// Description: Defines a new material. The material is added in the
|
|
|
+// position indicated by the material's index number.
|
|
|
+// If there is already a material defined for that index
|
|
|
+// number, it is replaced.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+add_material(FltMaterial *material) {
|
|
|
+ _materials[material->_material_index] = material;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::remove_material
|
|
|
+// Access: Public
|
|
|
+// Description: Removes a particular material from the material
|
|
|
+// palette, if it exists.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+remove_material(int material_index) {
|
|
|
+ _materials.erase(material_index);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::has_texture
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if a texture with the given index has
|
|
|
+// been defined.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+has_texture(int texture_index) const {
|
|
|
+ return (_textures.count(texture_index) != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_texture
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the texture associated with the given index,
|
|
|
+// or NULL if there is no such texture.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltTexture *FltHeader::
|
|
|
+get_texture(int texture_index) const {
|
|
|
+ Textures::const_iterator mi;
|
|
|
+ mi = _textures.find(texture_index);
|
|
|
+ if (mi != _textures.end()) {
|
|
|
+ return (*mi).second;
|
|
|
+ }
|
|
|
+ return (FltTexture *)NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::clear_textures
|
|
|
+// Access: Public
|
|
|
+// Description: Removes all textures from the palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+clear_textures() {
|
|
|
+ _textures.clear();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::add_texture
|
|
|
+// Access: Public
|
|
|
+// Description: Defines a new texture. The texture is added in the
|
|
|
+// position indicated by the texture's index number.
|
|
|
+// If there is already a texture defined for that index
|
|
|
+// number, it is replaced.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+add_texture(FltTexture *texture) {
|
|
|
+ _textures[texture->_pattern_index] = texture;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::remove_texture
|
|
|
+// Access: Public
|
|
|
+// Description: Removes a particular texture from the texture
|
|
|
+// palette, if it exists.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+remove_texture(int texture_index) {
|
|
|
+ _textures.erase(texture_index);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::set_texture_path
|
|
|
+// Access: Public
|
|
|
+// Description: Sets the search path that relative texture filenames
|
|
|
+// will be looked for along.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+set_texture_path(const DSearchPath &path) {
|
|
|
+ _texture_path = path;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::update_texture_path
|
|
|
+// Access: Public
|
|
|
+// Description: Returns a non-const reference to the texture search
|
|
|
+// path, so that it may be appended to or otherwise
|
|
|
+// modified.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+DSearchPath &FltHeader::
|
|
|
+update_texture_path() {
|
|
|
+ return _texture_path;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_texture_path
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the search path for looking up texture
|
|
|
+// filenames.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+const DSearchPath &FltHeader::
|
|
|
+get_texture_path() const {
|
|
|
+ return _texture_path;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::has_light_source
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if a light source with the given index
|
|
|
+// has been defined.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+has_light_source(int light_index) const {
|
|
|
+ return (_light_sources.count(light_index) != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_light_source
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the light source associated with the given
|
|
|
+// index, or NULL if there is no such light source.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltLightSourceDefinition *FltHeader::
|
|
|
+get_light_source(int light_index) const {
|
|
|
+ LightSources::const_iterator li;
|
|
|
+ li = _light_sources.find(light_index);
|
|
|
+ if (li != _light_sources.end()) {
|
|
|
+ return (*li).second;
|
|
|
+ }
|
|
|
+ return (FltLightSourceDefinition *)NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::clear_light_sources
|
|
|
+// Access: Public
|
|
|
+// Description: Removes all light sources from the palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+clear_light_sources() {
|
|
|
+ _light_sources.clear();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::add_light_source
|
|
|
+// Access: Public
|
|
|
+// Description: Defines a new light source. The light source is
|
|
|
+// added in the position indicated by its light index
|
|
|
+// number. If there is already a light source defined
|
|
|
+// for that index number, it is replaced.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+add_light_source(FltLightSourceDefinition *light_source) {
|
|
|
+ _light_sources[light_source->_light_index] = light_source;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::remove_light_source
|
|
|
+// Access: Public
|
|
|
+// Description: Removes a particular light source from the light
|
|
|
+// source palette, if it exists.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+remove_light_source(int light_index) {
|
|
|
+ _light_sources.erase(light_index);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::got_eyepoint_trackplane_palette
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if we have read an eyepoint/trackplane
|
|
|
+// palette, and at least some of the eyepoints and
|
|
|
+// trackplanes are therefore expected to be meaningful.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+got_eyepoint_trackplane_palette() const {
|
|
|
+ return _got_eyepoint_trackplane_palette;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::set_eyepoint_trackplane_palette
|
|
|
+// Access: Public
|
|
|
+// Description: Sets the state of the eyepoint/trackplane palette
|
|
|
+// flag. When this is false, the palette is believed to
|
|
|
+// be meaningless, and will not be written; when it is
|
|
|
+// true, the palette is believed to contain at least
|
|
|
+// some meaningful data, and will be written.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void FltHeader::
|
|
|
+set_eyepoint_trackplane_palette(bool flag) {
|
|
|
+ _got_eyepoint_trackplane_palette = flag;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_eyepoints
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the number of eyepoints in the
|
|
|
+// eyepoint/trackplane palette. This is presently fixed
|
|
|
+// at 10, according to the MultiGen specs.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_eyepoints() const {
|
|
|
+ return 10;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_eyepoint
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the nth eyepoint in the eyepoint/trackplane
|
|
|
+// palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltEyepoint *FltHeader::
|
|
|
+get_eyepoint(int n) {
|
|
|
+ nassertr(n >= 0 && n < get_num_eyepoints(), (FltEyepoint *)NULL);
|
|
|
+ return &_eyepoints[n];
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_num_trackplanes
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the number of trackplanes in the
|
|
|
+// eyepoint/trackplane palette. This is presently fixed
|
|
|
+// at 10, according to the MultiGen specs.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+get_num_trackplanes() const {
|
|
|
+ return 10;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::get_trackplane
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the nth trackplane in the eyepoint/trackplane
|
|
|
+// palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltTrackplane *FltHeader::
|
|
|
+get_trackplane(int n) {
|
|
|
+ nassertr(n >= 0 && n < get_num_trackplanes(), (FltTrackplane *)NULL);
|
|
|
+ return &_trackplanes[n];
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::update_vertex_lookups
|
|
|
+// Access: Public
|
|
|
+// Description: Recomputes the offsets_by_vertex and
|
|
|
+// vertices_by_offset tables. This reflects the flt
|
|
|
+// file as it will be written out, but not necessarily
|
|
|
+// as it was read in.
|
|
|
+//
|
|
|
+// The return value is the total length of the vertex
|
|
|
+// palette, including the header record.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int FltHeader::
|
|
|
+update_vertex_lookups() {
|
|
|
+ // We start with the length of the vertex palette record itself.
|
|
|
+ int offset = 8;
|
|
|
+
|
|
|
+ Vertices::const_iterator vi;
|
|
|
+ for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
|
|
|
+ FltVertex *vertex = (*vi);
|
|
|
+
|
|
|
+ _offsets_by_vertex[vertex] = offset;
|
|
|
+ _vertices_by_offset[offset] = vertex;
|
|
|
+ offset += vertex->get_record_length();
|
|
|
+ }
|
|
|
+
|
|
|
+ _vertex_lookups_stale = false;
|
|
|
+
|
|
|
+ return offset;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_record
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: Fills in the information in this bead based on the
|
|
|
+// information given in the indicated datagram, whose
|
|
|
+// opcode has already been read. Returns true on
|
|
|
+// success, false if the datagram is invalid.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_record(FltRecordReader &reader) {
|
|
|
+ if (!FltBeadID::extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ nassertr(reader.get_opcode() == FO_header, false);
|
|
|
+ DatagramIterator &iterator = reader.get_iterator();
|
|
|
+
|
|
|
+ _format_revision_level = iterator.get_be_int32();
|
|
|
+ _edit_revision_level = iterator.get_be_int32();
|
|
|
+ _last_revision = iterator.get_fixed_string(32);
|
|
|
+ _next_group_id = iterator.get_be_int16();
|
|
|
+ _next_lod_id = iterator.get_be_int16();
|
|
|
+ _next_object_id = iterator.get_be_int16();
|
|
|
+ _next_face_id = iterator.get_be_int16();
|
|
|
+ _unit_multiplier = iterator.get_be_int16();
|
|
|
+ _vertex_units = (Units)iterator.get_int8();
|
|
|
+ _texwhite_new = (iterator.get_int8() != 0);
|
|
|
+ _flags = iterator.get_be_uint32();
|
|
|
+ iterator.skip_bytes(24);
|
|
|
+ _projection_type = (ProjectionType)iterator.get_be_int32();
|
|
|
+ iterator.skip_bytes(28);
|
|
|
+ _next_dof_id = iterator.get_be_int16();
|
|
|
+ _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
|
|
|
+ _database_origin = (DatabaseOrigin)iterator.get_be_int32();
|
|
|
+ _sw_x = iterator.get_be_float64();
|
|
|
+ _sw_y = iterator.get_be_float64();
|
|
|
+ _delta_x = iterator.get_be_float64();
|
|
|
+ _delta_y = iterator.get_be_float64();
|
|
|
+ _next_sound_id = iterator.get_be_int16();
|
|
|
+ _next_path_id = iterator.get_be_int16();
|
|
|
+ iterator.skip_bytes(8);
|
|
|
+ _next_clip_id = iterator.get_be_int16();
|
|
|
+ _next_text_id = iterator.get_be_int16();
|
|
|
+ _next_bsp_id = iterator.get_be_int16();
|
|
|
+ _next_switch_id = iterator.get_be_int16();
|
|
|
+ iterator.skip_bytes(4);
|
|
|
+ _sw_lat = iterator.get_be_float64();
|
|
|
+ _sw_long = iterator.get_be_float64();
|
|
|
+ _ne_lat = iterator.get_be_float64();
|
|
|
+ _ne_long = iterator.get_be_float64();
|
|
|
+ _origin_lat = iterator.get_be_float64();
|
|
|
+ _origin_long = iterator.get_be_float64();
|
|
|
+ _lambert_upper_lat = iterator.get_be_float64();
|
|
|
+ _lambert_lower_lat = iterator.get_be_float64();
|
|
|
+ _next_light_id = iterator.get_be_int16();
|
|
|
+ iterator.skip_bytes(2);
|
|
|
+ _next_road_id = iterator.get_be_int16();
|
|
|
+ _next_cat_id = iterator.get_be_int16();
|
|
|
+ iterator.skip_bytes(2 + 2 + 2 + 2);
|
|
|
+ _earth_model = (EarthModel)iterator.get_be_int32();
|
|
|
+
|
|
|
+ // Undocumented additional padding.
|
|
|
+ iterator.skip_bytes(4);
|
|
|
+
|
|
|
+ nassertr(iterator.get_remaining_size() == 0, true);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_ancillary
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: Checks whether the given bead, which follows this
|
|
|
+// bead sequentially in the file, is an ancillary record
|
|
|
+// of this bead. If it is, extracts the relevant
|
|
|
+// information and returns true; otherwise, leaves it
|
|
|
+// alone and returns false.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_ancillary(FltRecordReader &reader) {
|
|
|
+ switch (reader.get_opcode()) {
|
|
|
+ case FO_vertex_palette:
|
|
|
+ // We're about to begin the vertex palette!
|
|
|
+ clear_vertices();
|
|
|
+ _current_vertex_offset = reader.get_record_length();
|
|
|
+ return true;
|
|
|
+
|
|
|
+ case FO_vertex_c:
|
|
|
+ case FO_vertex_cn:
|
|
|
+ case FO_vertex_cnu:
|
|
|
+ case FO_vertex_cu:
|
|
|
+ // Here's a new vertex for the palette.
|
|
|
+ return extract_vertex(reader);
|
|
|
+
|
|
|
+ case FO_color_palette:
|
|
|
+ return extract_color_palette(reader);
|
|
|
+
|
|
|
+ case FO_15_material:
|
|
|
+ return extract_material(reader);
|
|
|
+
|
|
|
+ case FO_texture:
|
|
|
+ return extract_texture(reader);
|
|
|
+
|
|
|
+ case FO_light_definition:
|
|
|
+ return extract_light_source(reader);
|
|
|
+
|
|
|
+ case FO_eyepoint_palette:
|
|
|
+ return extract_eyepoint_palette(reader);
|
|
|
+
|
|
|
+ default:
|
|
|
+ return FltBeadID::extract_ancillary(reader);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::build_record
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: Fills up the current record on the FltRecordWriter with
|
|
|
+// data for this record, but does not advance the
|
|
|
+// writer. Returns true on success, false if there is
|
|
|
+// some error.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+build_record(FltRecordWriter &writer) const {
|
|
|
+ if (!FltBeadID::build_record(writer)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ writer.set_opcode(FO_header);
|
|
|
+ Datagram &datagram = writer.update_datagram();
|
|
|
+
|
|
|
+ datagram.add_be_int32(_format_revision_level);
|
|
|
+ datagram.add_be_int32(_edit_revision_level);
|
|
|
+ datagram.add_fixed_string(_last_revision, 32);
|
|
|
+ datagram.add_be_int16(_next_group_id);
|
|
|
+ datagram.add_be_int16(_next_lod_id);
|
|
|
+ datagram.add_be_int16(_next_object_id);
|
|
|
+ datagram.add_be_int16(_next_face_id);
|
|
|
+ datagram.add_be_int16(_unit_multiplier);
|
|
|
+ datagram.add_int8(_vertex_units);
|
|
|
+ datagram.add_int8(_texwhite_new);
|
|
|
+ datagram.add_be_uint32(_flags);
|
|
|
+ datagram.pad_bytes(24);
|
|
|
+ datagram.add_be_int32(_projection_type);
|
|
|
+ datagram.pad_bytes(28);
|
|
|
+ datagram.add_be_int16(_next_dof_id);
|
|
|
+ datagram.add_be_int16(_vertex_storage_type);
|
|
|
+ datagram.add_be_int32(_database_origin);
|
|
|
+ datagram.add_be_float64(_sw_x);
|
|
|
+ datagram.add_be_float64(_sw_y);
|
|
|
+ datagram.add_be_float64(_delta_x);
|
|
|
+ datagram.add_be_float64(_delta_y);
|
|
|
+ datagram.add_be_int16(_next_sound_id);
|
|
|
+ datagram.add_be_int16(_next_path_id);
|
|
|
+ datagram.pad_bytes(8);
|
|
|
+ datagram.add_be_int16(_next_clip_id);
|
|
|
+ datagram.add_be_int16(_next_text_id);
|
|
|
+ datagram.add_be_int16(_next_bsp_id);
|
|
|
+ datagram.add_be_int16(_next_switch_id);
|
|
|
+ datagram.pad_bytes(4);
|
|
|
+ datagram.add_be_float64(_sw_lat);
|
|
|
+ datagram.add_be_float64(_sw_long);
|
|
|
+ datagram.add_be_float64(_ne_lat);
|
|
|
+ datagram.add_be_float64(_ne_long);
|
|
|
+ datagram.add_be_float64(_origin_lat);
|
|
|
+ datagram.add_be_float64(_origin_long);
|
|
|
+ datagram.add_be_float64(_lambert_upper_lat);
|
|
|
+ datagram.add_be_float64(_lambert_lower_lat);
|
|
|
+ datagram.add_be_int16(_next_light_id);
|
|
|
+ datagram.pad_bytes(2);
|
|
|
+ datagram.add_be_int16(_next_road_id);
|
|
|
+ datagram.add_be_int16(_next_cat_id);
|
|
|
+ datagram.pad_bytes(2 + 2 + 2 + 2);
|
|
|
+ datagram.add_be_int32(_earth_model);
|
|
|
+
|
|
|
+ // Undocumented additional padding.
|
|
|
+ datagram.pad_bytes(4);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_ancillary
|
|
|
+// Access: Protected, Virtual
|
|
|
+// Description: Writes whatever ancillary records are required for
|
|
|
+// this bead. Returns FE_ok on success, or something
|
|
|
+// else on error.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_ancillary(FltRecordWriter &writer) const {
|
|
|
+ FltError result;
|
|
|
+
|
|
|
+ result = write_color_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = write_material_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = write_texture_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = write_light_source_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = write_eyepoint_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ result = write_vertex_palette(writer);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ return FltBeadID::write_ancillary(writer);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_vertex
|
|
|
+// Access: Private
|
|
|
+// Description: Reads a single vertex ancillary record. It is
|
|
|
+// assumed that all the vertex records will immediately
|
|
|
+// follow the vertex palette record.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_vertex(FltRecordReader &reader) {
|
|
|
+ FltVertex *vertex = new FltVertex(this);
|
|
|
+ if (!vertex->extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ _vertices.push_back(vertex);
|
|
|
+ _unique_vertices.insert(vertex);
|
|
|
+ _offsets_by_vertex[vertex] = _current_vertex_offset;
|
|
|
+ _vertices_by_offset[_current_vertex_offset] = vertex;
|
|
|
+ _current_vertex_offset += reader.get_record_length();
|
|
|
+
|
|
|
+ // _vertex_lookups_stale remains false.
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_color_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Reads the color palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_color_palette(FltRecordReader &reader) {
|
|
|
+ nassertr(reader.get_opcode() == FO_color_palette, false);
|
|
|
+ DatagramIterator &iterator = reader.get_iterator();
|
|
|
+
|
|
|
+ static const int expected_color_entries = 1024;
|
|
|
+
|
|
|
+ iterator.skip_bytes(128);
|
|
|
+ _colors.clear();
|
|
|
+ for (int i = 0; i < expected_color_entries; i++) {
|
|
|
+ if (iterator.get_remaining_size() == 0) {
|
|
|
+ // An early end to the palette is acceptable.
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ FltPackedColor color;
|
|
|
+ if (!color.extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ _colors.push_back(color);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now pull out the color names.
|
|
|
+ while (iterator.get_remaining_size() > 0) {
|
|
|
+ int entry_length = iterator.get_be_uint16();
|
|
|
+ iterator.skip_bytes(2);
|
|
|
+ int color_index = iterator.get_be_int16();
|
|
|
+ iterator.skip_bytes(2);
|
|
|
+
|
|
|
+ int name_length = entry_length - 8;
|
|
|
+ nassertr(color_index >= 0 && color_index < (int)_colors.size(), false);
|
|
|
+ _color_names[color_index] = iterator.get_fixed_string(name_length);
|
|
|
+ }
|
|
|
+
|
|
|
+ nassertr(iterator.get_remaining_size() == 0, true);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_material
|
|
|
+// Access: Private
|
|
|
+// Description: Reads a single material ancillary record.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_material(FltRecordReader &reader) {
|
|
|
+ FltMaterial *material = new FltMaterial(this);
|
|
|
+ if (!material->extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ add_material(material);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_texture
|
|
|
+// Access: Private
|
|
|
+// Description: Reads a single texture ancillary record.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_texture(FltRecordReader &reader) {
|
|
|
+ FltTexture *texture = new FltTexture(this);
|
|
|
+ if (!texture->extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ add_texture(texture);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_light_source
|
|
|
+// Access: Private
|
|
|
+// Description: Reads a single light source ancillary record.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_light_source(FltRecordReader &reader) {
|
|
|
+ FltLightSourceDefinition *light_source = new FltLightSourceDefinition(this);
|
|
|
+ if (!light_source->extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ add_light_source(light_source);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::extract_eyepoint_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Reads the eyepoint/trackplane palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool FltHeader::
|
|
|
+extract_eyepoint_palette(FltRecordReader &reader) {
|
|
|
+ nassertr(reader.get_opcode() == FO_eyepoint_palette, false);
|
|
|
+ DatagramIterator &iterator = reader.get_iterator();
|
|
|
+
|
|
|
+ iterator.skip_bytes(4);
|
|
|
+
|
|
|
+ int i;
|
|
|
+ int num_eyepoints = get_num_eyepoints();
|
|
|
+ for (i = 0; i < num_eyepoints; i++) {
|
|
|
+ if (!_eyepoints[i].extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int num_trackplanes = get_num_trackplanes();
|
|
|
+ for (i = 0; i < num_trackplanes; i++) {
|
|
|
+ if (!_trackplanes[i].extract_record(reader)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _got_eyepoint_trackplane_palette = true;
|
|
|
+ nassertr(iterator.get_remaining_size() == 0, true);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_vertex_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the vertex palette with all of its
|
|
|
+// vertices.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_vertex_palette(FltRecordWriter &writer) const {
|
|
|
+ FltError result;
|
|
|
+
|
|
|
+ int vertex_palette_length =
|
|
|
+ ((FltHeader *)this)->update_vertex_lookups();
|
|
|
+ Datagram vertex_palette;
|
|
|
+ vertex_palette.add_be_int32(vertex_palette_length);
|
|
|
+ result = writer.write_record(FO_vertex_palette, vertex_palette);
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ // Now write out each vertex in the palette.
|
|
|
+ Vertices::const_iterator vi;
|
|
|
+ for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
|
|
|
+ FltVertex *vertex = (*vi);
|
|
|
+ vertex->build_record(writer);
|
|
|
+ result = writer.advance();
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FE_ok;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_color_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the color palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_color_palette(FltRecordWriter &writer) const {
|
|
|
+ writer.set_opcode(FO_color_palette);
|
|
|
+ Datagram &datagram = writer.update_datagram();
|
|
|
+
|
|
|
+ datagram.pad_bytes(128);
|
|
|
+
|
|
|
+ // How many colors should we write?
|
|
|
+ int num_colors = 1024;
|
|
|
+
|
|
|
+ Colors::const_iterator ci;
|
|
|
+ for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
|
|
|
+ if (!(*ci).build_record(writer)) {
|
|
|
+ return FE_invalid_record;
|
|
|
+ }
|
|
|
+ num_colors--;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now we might need to pad the record to fill up the required
|
|
|
+ // number of colors.
|
|
|
+ if (num_colors > 0) {
|
|
|
+ FltPackedColor empty;
|
|
|
+ while (num_colors > 0) {
|
|
|
+ if (!empty.build_record(writer)) {
|
|
|
+ return FE_invalid_record;
|
|
|
+ }
|
|
|
+ num_colors--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now append all the names at the end.
|
|
|
+ ColorNames::const_iterator ni;
|
|
|
+ for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
|
|
|
+ string name = (*ni).second.substr(0, 80);
|
|
|
+ int entry_length = name.length() + 8;
|
|
|
+ datagram.add_be_uint16(entry_length);
|
|
|
+ datagram.pad_bytes(2);
|
|
|
+ datagram.add_be_uint16((*ni).first);
|
|
|
+ datagram.pad_bytes(2);
|
|
|
+ datagram.add_fixed_string(name, name.length());
|
|
|
+ }
|
|
|
+
|
|
|
+ return writer.advance();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_material_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the material palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_material_palette(FltRecordWriter &writer) const {
|
|
|
+ FltError result;
|
|
|
+
|
|
|
+ Materials::const_iterator mi;
|
|
|
+ for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
|
|
|
+ FltMaterial *material = (*mi).second;
|
|
|
+ material->build_record(writer);
|
|
|
+ result = writer.advance();
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FE_ok;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_texture_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the texture palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_texture_palette(FltRecordWriter &writer) const {
|
|
|
+ FltError result;
|
|
|
+
|
|
|
+ Textures::const_iterator ti;
|
|
|
+ for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
|
|
|
+ FltTexture *texture = (*ti).second;
|
|
|
+ texture->build_record(writer);
|
|
|
+ result = writer.advance();
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FE_ok;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_light_source_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the light source palette.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_light_source_palette(FltRecordWriter &writer) const {
|
|
|
+ FltError result;
|
|
|
+
|
|
|
+ LightSources::const_iterator li;
|
|
|
+ for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
|
|
|
+ FltLightSourceDefinition *light_source = (*li).second;
|
|
|
+ light_source->build_record(writer);
|
|
|
+ result = writer.advance();
|
|
|
+ if (result != FE_ok) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FE_ok;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: FltHeader::write_eyepoint_palette
|
|
|
+// Access: Private
|
|
|
+// Description: Writes out the eyepoint/trackplane palette, if we
|
|
|
+// have one.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+FltError FltHeader::
|
|
|
+write_eyepoint_palette(FltRecordWriter &writer) const {
|
|
|
+ if (!_got_eyepoint_trackplane_palette) {
|
|
|
+ return FE_ok;
|
|
|
+ }
|
|
|
+
|
|
|
+ writer.set_opcode(FO_color_palette);
|
|
|
+ Datagram &datagram = writer.update_datagram();
|
|
|
+ datagram.pad_bytes(4);
|
|
|
+
|
|
|
+ int i;
|
|
|
+ int num_eyepoints = get_num_eyepoints();
|
|
|
+ for (i = 0; i < num_eyepoints; i++) {
|
|
|
+ if (!_eyepoints[i].build_record(writer)) {
|
|
|
+ return FE_bad_data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int num_trackplanes = get_num_trackplanes();
|
|
|
+ for (i = 0; i < num_trackplanes; i++) {
|
|
|
+ if (!_trackplanes[i].build_record(writer)) {
|
|
|
+ return FE_bad_data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return writer.advance();
|
|
|
+}
|