Panda3D

fltHeader.cxx

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