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 LColor FltHeader::
00659 get_color(int color_index) const {
00660   nassertr(color_index >= 0 && color_index < get_num_colors(),
00661            LColor(0.0, 0.0, 0.0, 0.0));
00662   int num_color_shades = get_num_color_shades();
00663 
00664   int index = (color_index / num_color_shades);
00665   int level = (color_index % num_color_shades);
00666   nassertr(index >= 0 && index < (int)_colors.size(),
00667            LColor(0.0, 0.0, 0.0, 0.0));
00668 
00669   LColor color = _colors[index].get_color();
00670   return color * ((double)level / (double)(num_color_shades - 1));
00671 }
00672 
00673 ////////////////////////////////////////////////////////////////////
00674 //     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 LRGBColor FltHeader::
00681 get_rgb(int color_index) const {
00682   nassertr(color_index >= 0 && color_index < get_num_colors(),
00683            LRGBColor(0.0, 0.0, 0.0));
00684   int num_color_shades = get_num_color_shades();
00685 
00686   int index = (color_index / num_color_shades);
00687   int level = (color_index % num_color_shades);
00688   nassertr(index >= 0 && index < (int)_colors.size(),
00689            LRGBColor(0.0, 0.0, 0.0));
00690 
00691   LRGBColor color = _colors[index].get_rgb();
00692   return color * ((double)level / (double)(num_color_shades - 1));
00693 }
00694 
00695 ////////////////////////////////////////////////////////////////////
00696 //     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(const LColor &color0) 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   LColor color = color0;
00737 
00738   double scale = 1.0;
00739 
00740   if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
00741     // Oh, this is invisible black.
00742     scale = 0.0;
00743     color.set(1.0, 1.0, 1.0, 1.0);
00744 
00745   } else {
00746     if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
00747       // color[0] is largest.
00748       scale = color[0];
00749 
00750     } else if (color[1] >= color[2] && color[1] >= color[3]) {
00751       // color[1] is largest.
00752       scale = color[1];
00753 
00754     } else if (color[2] >= color[3]) {
00755       // color[2] is largest.
00756       scale = color[2];
00757 
00758     } else {
00759       // color[3] is largest.
00760       scale = color[3];
00761     }
00762     color /= scale;
00763   }
00764 
00765   // Now search for the best match.
00766   PN_stdfloat best_dist = 5.0;  // Greater than 4.
00767   int best_i = -1;
00768 
00769   int num_color_entries = get_num_color_entries();
00770   for (int i = 0; i < num_color_entries; i++) {
00771     LColor consider = _colors[i].get_color();
00772     PN_stdfloat dist2 = dot(consider - color, consider - color);
00773     nassertr(dist2 < 5.0, 0);
00774 
00775     if (dist2 < best_dist) {
00776       best_dist = dist2;
00777       best_i = i;
00778     }
00779   }
00780   nassertr(best_i >= 0, 0);
00781 
00782   int num_color_shades = get_num_color_shades();
00783   int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
00784 
00785   return (best_i * num_color_shades) + shade_index;
00786 }
00787 
00788 ////////////////////////////////////////////////////////////////////
00789 //     Function: FltHeader::get_closest_rgb
00790 //       Access: Public
00791 //  Description: Returns the color index of the nearest color in the
00792 //               palette that matches the given three-component color,
00793 //               ignoring alpha.
00794 ////////////////////////////////////////////////////////////////////
00795 int FltHeader::
00796 get_closest_rgb(const LRGBColor &color0) const {
00797   // Since the colortable stores the brightest colors, with
00798   // num_color_shades scaled versions of each color implicitly
00799   // available, we really only care about the relative brightnesses of
00800   // the various components.  Normalize the color in terms of the
00801   // largest of these.
00802 
00803   LRGBColor color = color0;
00804   double scale = 1.0;
00805 
00806   if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
00807     // Oh, this is black.
00808     scale = 0.0;
00809     color.set(1.0, 1.0, 1.0);
00810 
00811   } else {
00812     if (color[0] >= color[1] && color[0] >= color[2]) {
00813       // color[0] is largest.
00814       scale = color[0];
00815 
00816     } else if (color[1] >= color[2]) {
00817       // color[1] is largest.
00818       scale = color[1];
00819 
00820     } else {
00821       // color[2] is largest.
00822       scale = color[2];
00823     }
00824     color /= scale;
00825   }
00826 
00827   // Now search for the best match.
00828   PN_stdfloat best_dist = 5.0;  // Greater than 4.
00829   int best_i = -1;
00830 
00831   int num_color_entries = get_num_color_entries();
00832   for (int i = 0; i < num_color_entries; i++) {
00833     LRGBColor consider = _colors[i].get_rgb();
00834     PN_stdfloat dist2 = dot(consider - color, consider - color);
00835     nassertr(dist2 < 5.0, 0);
00836 
00837     if (dist2 < best_dist) {
00838       best_dist = dist2;
00839       best_i = i;
00840     }
00841   }
00842   nassertr(best_i >= 0, 0);
00843 
00844   int num_color_shades = get_num_color_shades();
00845   int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
00846 
00847   return (best_i * num_color_shades) + shade_index;
00848 }
00849 
00850 ////////////////////////////////////////////////////////////////////
00851 //     Function: FltHeader::get_num_color_entries
00852 //       Access: Public
00853 //  Description: Returns the number of actual entries in the color
00854 //               palette.  This is based on the version of the flt
00855 //               file, and is usually either 512 or 1024.
00856 ////////////////////////////////////////////////////////////////////
00857 int FltHeader::
00858 get_num_color_entries() const {
00859   return _colors.size();
00860 }
00861 
00862 ////////////////////////////////////////////////////////////////////
00863 //     Function: FltHeader::get_num_color_shades
00864 //       Access: Public
00865 //  Description: Returns the number of shades of brightness of each
00866 //               entry in the color palette.  This is a fixed property
00867 //               of MultiGen files: each entry in the palette actually
00868 //               represents a range of this many colors.
00869 ////////////////////////////////////////////////////////////////////
00870 int FltHeader::
00871 get_num_color_shades() const {
00872   return 128;
00873 }
00874 
00875 ////////////////////////////////////////////////////////////////////
00876 //     Function: FltHeader::get_color
00877 //       Access: Public
00878 //  Description: Decodes a MultiGen color, as stored on a face or
00879 //               vertex, into an actual four-component LColor.
00880 //               Normally you need not call this directly; there are
00881 //               color accessors defined on faces and vertices that do
00882 //               this.
00883 ////////////////////////////////////////////////////////////////////
00884 LColor FltHeader::
00885 get_color(int color_index, bool use_packed_color,
00886           const FltPackedColor &packed_color,
00887           int transparency) {
00888   if (!use_packed_color) {
00889     return get_color(color_index);
00890   }
00891 
00892   LColor color;
00893   color[0] = packed_color._r / 255.0;
00894   color[1] = packed_color._g / 255.0;
00895   color[2] = packed_color._b / 255.0;
00896   // MultiGen doesn't yet use the A component of RGBA.
00897   //color[3] = packed_color._a / 255.0;
00898   color[3] = 1.0 - (transparency / 65535.0);
00899   return color;
00900 }
00901 
00902 ////////////////////////////////////////////////////////////////////
00903 //     Function: FltHeader::get_color
00904 //       Access: Public
00905 //  Description: Decodes a MultiGen color, as stored on a face or
00906 //               vertex, into an actual three-component LRGBColor.
00907 //               Normally you need not call this directly; there are
00908 //               color accessors defined on faces and vertices that do
00909 //               this.
00910 ////////////////////////////////////////////////////////////////////
00911 LRGBColor FltHeader::
00912 get_rgb(int color_index, bool use_packed_color,
00913         const FltPackedColor &packed_color) {
00914   if (!use_packed_color) {
00915     return get_rgb(color_index);
00916   }
00917 
00918   LRGBColor color;
00919   color[0] = packed_color._r / 255.0;
00920   color[1] = packed_color._g / 255.0;
00921   color[2] = packed_color._b / 255.0;
00922   return color;
00923 }
00924 
00925 ////////////////////////////////////////////////////////////////////
00926 //     Function: FltHeader::has_material
00927 //       Access: Public
00928 //  Description: Returns true if a material with the given index has
00929 //               been defined.
00930 ////////////////////////////////////////////////////////////////////
00931 bool FltHeader::
00932 has_material(int material_index) const {
00933   return (_materials.count(material_index) != 0);
00934 }
00935 
00936 ////////////////////////////////////////////////////////////////////
00937 //     Function: FltHeader::get_material
00938 //       Access: Public
00939 //  Description: Returns the material associated with the given index,
00940 //               or NULL if there is no such material.
00941 ////////////////////////////////////////////////////////////////////
00942 FltMaterial *FltHeader::
00943 get_material(int material_index) const {
00944   Materials::const_iterator mi;
00945   mi = _materials.find(material_index);
00946   if (mi != _materials.end()) {
00947     return (*mi).second;
00948   }
00949   return (FltMaterial *)NULL;
00950 }
00951 
00952 ////////////////////////////////////////////////////////////////////
00953 //     Function: FltHeader::clear_materials
00954 //       Access: Public
00955 //  Description: Removes all materials from the palette.
00956 ////////////////////////////////////////////////////////////////////
00957 void FltHeader::
00958 clear_materials() {
00959   _materials.clear();
00960 }
00961 
00962 ////////////////////////////////////////////////////////////////////
00963 //     Function: FltHeader::add_material
00964 //       Access: Public
00965 //  Description: Defines a new material.  The material is added in the
00966 //               position indicated by the material's index number.
00967 //               If there is already a material defined for that index
00968 //               number, it is replaced.
00969 ////////////////////////////////////////////////////////////////////
00970 void FltHeader::
00971 add_material(FltMaterial *material) {
00972   if (material->_material_index < 0) {
00973     // We need to make up a new material index for the material.
00974     material->_material_index = _next_material_index;
00975     _next_material_index++;
00976 
00977   } else {
00978     // Make sure our next generated material index will be different
00979     // from any existing material indices.
00980     _next_material_index = max(_next_material_index, material->_material_index + 1);
00981   }
00982 
00983   _materials[material->_material_index] = material;
00984 }
00985 
00986 ////////////////////////////////////////////////////////////////////
00987 //     Function: FltHeader::remove_material
00988 //       Access: Public
00989 //  Description: Removes a particular material from the material
00990 //               palette, if it exists.
00991 ////////////////////////////////////////////////////////////////////
00992 void FltHeader::
00993 remove_material(int material_index) {
00994   _materials.erase(material_index);
00995 }
00996 
00997 ////////////////////////////////////////////////////////////////////
00998 //     Function: FltHeader::has_texture
00999 //       Access: Public
01000 //  Description: Returns true if a texture with the given index has
01001 //               been defined.
01002 ////////////////////////////////////////////////////////////////////
01003 bool FltHeader::
01004 has_texture(int texture_index) const {
01005   return (_textures.count(texture_index) != 0);
01006 }
01007 
01008 ////////////////////////////////////////////////////////////////////
01009 //     Function: FltHeader::get_texture
01010 //       Access: Public
01011 //  Description: Returns the texture associated with the given index,
01012 //               or NULL if there is no such texture.
01013 ////////////////////////////////////////////////////////////////////
01014 FltTexture *FltHeader::
01015 get_texture(int texture_index) const {
01016   Textures::const_iterator mi;
01017   mi = _textures.find(texture_index);
01018   if (mi != _textures.end()) {
01019     return (*mi).second;
01020   }
01021   return (FltTexture *)NULL;
01022 }
01023 
01024 ////////////////////////////////////////////////////////////////////
01025 //     Function: FltHeader::clear_textures
01026 //       Access: Public
01027 //  Description: Removes all textures from the palette.
01028 ////////////////////////////////////////////////////////////////////
01029 void FltHeader::
01030 clear_textures() {
01031   _textures.clear();
01032 }
01033 
01034 ////////////////////////////////////////////////////////////////////
01035 //     Function: FltHeader::add_texture
01036 //       Access: Public
01037 //  Description: Defines a new texture.  The texture is added in the
01038 //               position indicated by the texture's index number.
01039 //               If there is already a texture defined for that index
01040 //               number, it is replaced.
01041 ////////////////////////////////////////////////////////////////////
01042 void FltHeader::
01043 add_texture(FltTexture *texture) {
01044   if (texture->_pattern_index < 0) {
01045     // We need to make up a new pattern index for the texture.
01046     texture->_pattern_index = _next_pattern_index;
01047     _next_pattern_index++;
01048 
01049   } else {
01050     // Make sure our next generated pattern index will be different
01051     // from any existing texture indices.
01052     _next_pattern_index = max(_next_pattern_index, texture->_pattern_index + 1);
01053   }
01054 
01055   _textures[texture->_pattern_index] = texture;
01056 }
01057 
01058 ////////////////////////////////////////////////////////////////////
01059 //     Function: FltHeader::remove_texture
01060 //       Access: Public
01061 //  Description: Removes a particular texture from the texture
01062 //               palette, if it exists.
01063 ////////////////////////////////////////////////////////////////////
01064 void FltHeader::
01065 remove_texture(int texture_index) {
01066   _textures.erase(texture_index);
01067 }
01068 
01069 ////////////////////////////////////////////////////////////////////
01070 //     Function: FltHeader::has_light_source
01071 //       Access: Public
01072 //  Description: Returns true if a light source with the given index
01073 //               has been defined.
01074 ////////////////////////////////////////////////////////////////////
01075 bool FltHeader::
01076 has_light_source(int light_index) const {
01077   return (_light_sources.count(light_index) != 0);
01078 }
01079 
01080 ////////////////////////////////////////////////////////////////////
01081 //     Function: FltHeader::get_light_source
01082 //       Access: Public
01083 //  Description: Returns the light source associated with the given
01084 //               index, or NULL if there is no such light source.
01085 ////////////////////////////////////////////////////////////////////
01086 FltLightSourceDefinition *FltHeader::
01087 get_light_source(int light_index) const {
01088   LightSources::const_iterator li;
01089   li = _light_sources.find(light_index);
01090   if (li != _light_sources.end()) {
01091     return (*li).second;
01092   }
01093   return (FltLightSourceDefinition *)NULL;
01094 }
01095 
01096 ////////////////////////////////////////////////////////////////////
01097 //     Function: FltHeader::clear_light_sources
01098 //       Access: Public
01099 //  Description: Removes all light sources from the palette.
01100 ////////////////////////////////////////////////////////////////////
01101 void FltHeader::
01102 clear_light_sources() {
01103   _light_sources.clear();
01104 }
01105 
01106 ////////////////////////////////////////////////////////////////////
01107 //     Function: FltHeader::add_light_source
01108 //       Access: Public
01109 //  Description: Defines a new light source.  The light source is
01110 //               added in the position indicated by its light index
01111 //               number.  If there is already a light source defined
01112 //               for that index number, it is replaced.
01113 ////////////////////////////////////////////////////////////////////
01114 void FltHeader::
01115 add_light_source(FltLightSourceDefinition *light_source) {
01116   _light_sources[light_source->_light_index] = light_source;
01117 }
01118 
01119 ////////////////////////////////////////////////////////////////////
01120 //     Function: FltHeader::remove_light_source
01121 //       Access: Public
01122 //  Description: Removes a particular light source from the light
01123 //               source palette, if it exists.
01124 ////////////////////////////////////////////////////////////////////
01125 void FltHeader::
01126 remove_light_source(int light_index) {
01127   _light_sources.erase(light_index);
01128 }
01129 
01130 ////////////////////////////////////////////////////////////////////
01131 //     Function: FltHeader::got_eyepoint_trackplane_palette
01132 //       Access: Public
01133 //  Description: Returns true if we have read an eyepoint/trackplane
01134 //               palette, and at least some of the eyepoints and
01135 //               trackplanes are therefore expected to be meaningful.
01136 ////////////////////////////////////////////////////////////////////
01137 bool FltHeader::
01138 got_eyepoint_trackplane_palette() const {
01139   return _got_eyepoint_trackplane_palette;
01140 }
01141 
01142 ////////////////////////////////////////////////////////////////////
01143 //     Function: FltHeader::set_eyepoint_trackplane_palette
01144 //       Access: Public
01145 //  Description: Sets the state of the eyepoint/trackplane palette
01146 //               flag.  When this is false, the palette is believed to
01147 //               be meaningless, and will not be written; when it is
01148 //               true, the palette is believed to contain at least
01149 //               some meaningful data, and will be written.
01150 ////////////////////////////////////////////////////////////////////
01151 void FltHeader::
01152 set_eyepoint_trackplane_palette(bool flag) {
01153   _got_eyepoint_trackplane_palette = flag;
01154 }
01155 
01156 ////////////////////////////////////////////////////////////////////
01157 //     Function: FltHeader::get_num_eyepoints
01158 //       Access: Public
01159 //  Description: Returns the number of eyepoints in the
01160 //               eyepoint/trackplane palette.  This is presently fixed
01161 //               at 10, according to the MultiGen specs.
01162 ////////////////////////////////////////////////////////////////////
01163 int FltHeader::
01164 get_num_eyepoints() const {
01165   return 10;
01166 }
01167 
01168 ////////////////////////////////////////////////////////////////////
01169 //     Function: FltHeader::get_eyepoint
01170 //       Access: Public
01171 //  Description: Returns the nth eyepoint in the eyepoint/trackplane
01172 //               palette.
01173 ////////////////////////////////////////////////////////////////////
01174 FltEyepoint *FltHeader::
01175 get_eyepoint(int n) {
01176   nassertr(n >= 0 && n < get_num_eyepoints(), (FltEyepoint *)NULL);
01177   return &_eyepoints[n];
01178 }
01179 
01180 ////////////////////////////////////////////////////////////////////
01181 //     Function: FltHeader::get_num_trackplanes
01182 //       Access: Public
01183 //  Description: Returns the number of trackplanes in the
01184 //               eyepoint/trackplane palette.  This is presently fixed
01185 //               at 10, according to the MultiGen specs.
01186 ////////////////////////////////////////////////////////////////////
01187 int FltHeader::
01188 get_num_trackplanes() const {
01189   return 10;
01190 }
01191 
01192 ////////////////////////////////////////////////////////////////////
01193 //     Function: FltHeader::get_trackplane
01194 //       Access: Public
01195 //  Description: Returns the nth trackplane in the eyepoint/trackplane
01196 //               palette.
01197 ////////////////////////////////////////////////////////////////////
01198 FltTrackplane *FltHeader::
01199 get_trackplane(int n) {
01200   nassertr(n >= 0 && n < get_num_trackplanes(), (FltTrackplane *)NULL);
01201   return &_trackplanes[n];
01202 }
01203 
01204 ////////////////////////////////////////////////////////////////////
01205 //     Function: FltHeader::update_vertex_lookups
01206 //       Access: Public
01207 //  Description: Recomputes the offsets_by_vertex and
01208 //               vertices_by_offset tables.  This reflects the flt
01209 //               file as it will be written out, but not necessarily
01210 //               as it was read in.
01211 //
01212 //               The return value is the total length of the vertex
01213 //               palette, including the header record.
01214 ////////////////////////////////////////////////////////////////////
01215 int FltHeader::
01216 update_vertex_lookups() {
01217   // We start with the length of the vertex palette record itself.
01218   int offset = 8;
01219 
01220   Vertices::const_iterator vi;
01221   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
01222     FltVertex *vertex = (*vi);
01223 
01224     _offsets_by_vertex[vertex] = offset;
01225     _vertices_by_offset[offset] = vertex;
01226     offset += vertex->get_record_length();
01227   }
01228 
01229   _vertex_lookups_stale = false;
01230 
01231   return offset;
01232 }
01233 
01234 ////////////////////////////////////////////////////////////////////
01235 //     Function: FltHeader::extract_record
01236 //       Access: Protected, Virtual
01237 //  Description: Fills in the information in this bead based on the
01238 //               information given in the indicated datagram, whose
01239 //               opcode has already been read.  Returns true on
01240 //               success, false if the datagram is invalid.
01241 ////////////////////////////////////////////////////////////////////
01242 bool FltHeader::
01243 extract_record(FltRecordReader &reader) {
01244   if (!FltBeadID::extract_record(reader)) {
01245     return false;
01246   }
01247 
01248   nassertr(reader.get_opcode() == FO_header, false);
01249   DatagramIterator &iterator = reader.get_iterator();
01250 
01251   _format_revision_level = iterator.get_be_int32();
01252   _edit_revision_level = iterator.get_be_int32();
01253   _last_revision = iterator.get_fixed_string(32);
01254   _next_group_id = iterator.get_be_int16();
01255   _next_lod_id = iterator.get_be_int16();
01256   _next_object_id = iterator.get_be_int16();
01257   _next_face_id = iterator.get_be_int16();
01258   _unit_multiplier = iterator.get_be_int16();
01259   _vertex_units = (Units)iterator.get_int8();
01260   _texwhite_new = (iterator.get_int8() != 0);
01261   _flags = iterator.get_be_uint32();
01262   iterator.skip_bytes(24);
01263   _projection_type = (ProjectionType)iterator.get_be_int32();
01264   iterator.skip_bytes(28);
01265   _next_dof_id = iterator.get_be_int16();
01266   _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
01267   _database_origin = (DatabaseOrigin)iterator.get_be_int32();
01268   _sw_x = iterator.get_be_float64();
01269   _sw_y = iterator.get_be_float64();
01270   _delta_x = iterator.get_be_float64();
01271   _delta_y = iterator.get_be_float64();
01272   _next_sound_id = iterator.get_be_int16();
01273   _next_path_id = iterator.get_be_int16();
01274   iterator.skip_bytes(8);
01275   _next_clip_id = iterator.get_be_int16();
01276   _next_text_id = iterator.get_be_int16();
01277   _next_bsp_id = iterator.get_be_int16();
01278   _next_switch_id = iterator.get_be_int16();
01279   iterator.skip_bytes(4);
01280   _sw_lat = iterator.get_be_float64();
01281   _sw_long = iterator.get_be_float64();
01282   _ne_lat = iterator.get_be_float64();
01283   _ne_long = iterator.get_be_float64();
01284   _origin_lat = iterator.get_be_float64();
01285   _origin_long = iterator.get_be_float64();
01286   _lambert_upper_lat = iterator.get_be_float64();
01287   _lambert_lower_lat = iterator.get_be_float64();
01288   _next_light_id = iterator.get_be_int16();
01289   iterator.skip_bytes(2);
01290   if (get_flt_version() >= 1420 && iterator.get_remaining_size() > 0) {
01291     _next_road_id = iterator.get_be_int16();
01292     _next_cat_id = iterator.get_be_int16();
01293 
01294     if (get_flt_version() >= 1520 && iterator.get_remaining_size() > 0) {
01295       iterator.skip_bytes(2 + 2 + 2 + 2);
01296       _earth_model = (EarthModel)iterator.get_be_int32();
01297       
01298       // Undocumented padding.
01299       iterator.skip_bytes(4);
01300       
01301       if (get_flt_version() >= 1560 && iterator.get_remaining_size() > 0) {
01302         _next_adaptive_id = iterator.get_be_int16();
01303         _next_curve_id = iterator.get_be_int16();
01304         iterator.skip_bytes(4);
01305         
01306         if (get_flt_version() >= 1570 && iterator.get_remaining_size() > 0) {
01307           _delta_z = iterator.get_be_float64();
01308           _radius = iterator.get_be_float64();
01309           _next_mesh_id = iterator.get_be_int16();
01310           iterator.skip_bytes(2);
01311           
01312           // Undocumented padding.
01313           iterator.skip_bytes(4);
01314         }
01315       }
01316     }
01317   }
01318 
01319   check_remaining_size(iterator);
01320   return true;
01321 }
01322 
01323 ////////////////////////////////////////////////////////////////////
01324 //     Function: FltHeader::extract_ancillary
01325 //       Access: Protected, Virtual
01326 //  Description: Checks whether the given bead, which follows this
01327 //               bead sequentially in the file, is an ancillary record
01328 //               of this bead.  If it is, extracts the relevant
01329 //               information and returns true; otherwise, leaves it
01330 //               alone and returns false.
01331 ////////////////////////////////////////////////////////////////////
01332 bool FltHeader::
01333 extract_ancillary(FltRecordReader &reader) {
01334   switch (reader.get_opcode()) {
01335   case FO_vertex_palette:
01336     // We're about to begin the vertex palette!
01337     clear_vertices();
01338     _current_vertex_offset = reader.get_record_length();
01339     return true;
01340 
01341   case FO_vertex_c:
01342   case FO_vertex_cn:
01343   case FO_vertex_cnu:
01344   case FO_vertex_cu:
01345     // Here's a new vertex for the palette.
01346     return extract_vertex(reader);
01347 
01348   case FO_color_palette:
01349     return extract_color_palette(reader);
01350 
01351   case FO_15_material:
01352     return extract_material(reader);
01353 
01354   case FO_14_material_palette:
01355     return extract_14_material_palette(reader);
01356 
01357   case FO_texture:
01358     return extract_texture(reader);
01359 
01360   case FO_texture_map_palette:
01361     return extract_texture_map(reader);
01362 
01363   case FO_light_definition:
01364     return extract_light_source(reader);
01365 
01366   case FO_eyepoint_palette:
01367     return extract_eyepoint_palette(reader);
01368 
01369   default:
01370     return FltBeadID::extract_ancillary(reader);
01371   }
01372 }
01373 
01374 ////////////////////////////////////////////////////////////////////
01375 //     Function: FltHeader::build_record
01376 //       Access: Protected, Virtual
01377 //  Description: Fills up the current record on the FltRecordWriter with
01378 //               data for this record, but does not advance the
01379 //               writer.  Returns true on success, false if there is
01380 //               some error.
01381 ////////////////////////////////////////////////////////////////////
01382 bool FltHeader::
01383 build_record(FltRecordWriter &writer) const {
01384   if (!FltBeadID::build_record(writer)) {
01385     return false;
01386   }
01387 
01388   writer.set_opcode(FO_header);
01389   Datagram &datagram = writer.update_datagram();
01390 
01391   datagram.add_be_int32(_format_revision_level);
01392   datagram.add_be_int32(_edit_revision_level);
01393   datagram.add_fixed_string(_last_revision, 32);
01394   datagram.add_be_int16(_next_group_id);
01395   datagram.add_be_int16(_next_lod_id);
01396   datagram.add_be_int16(_next_object_id);
01397   datagram.add_be_int16(_next_face_id);
01398   datagram.add_be_int16(_unit_multiplier);
01399   datagram.add_int8(_vertex_units);
01400   datagram.add_int8(_texwhite_new);
01401   datagram.add_be_uint32(_flags);
01402   datagram.pad_bytes(24);
01403   datagram.add_be_int32(_projection_type);
01404   datagram.pad_bytes(28);
01405   datagram.add_be_int16(_next_dof_id);
01406   datagram.add_be_int16(_vertex_storage_type);
01407   datagram.add_be_int32(_database_origin);
01408   datagram.add_be_float64(_sw_x);
01409   datagram.add_be_float64(_sw_y);
01410   datagram.add_be_float64(_delta_x);
01411   datagram.add_be_float64(_delta_y);
01412   datagram.add_be_int16(_next_sound_id);
01413   datagram.add_be_int16(_next_path_id);
01414   datagram.pad_bytes(8);
01415   datagram.add_be_int16(_next_clip_id);
01416   datagram.add_be_int16(_next_text_id);
01417   datagram.add_be_int16(_next_bsp_id);
01418   datagram.add_be_int16(_next_switch_id);
01419   datagram.pad_bytes(4);
01420   datagram.add_be_float64(_sw_lat);
01421   datagram.add_be_float64(_sw_long);
01422   datagram.add_be_float64(_ne_lat);
01423   datagram.add_be_float64(_ne_long);
01424   datagram.add_be_float64(_origin_lat);
01425   datagram.add_be_float64(_origin_long);
01426   datagram.add_be_float64(_lambert_upper_lat);
01427   datagram.add_be_float64(_lambert_lower_lat);
01428   datagram.add_be_int16(_next_light_id);
01429   datagram.pad_bytes(2);
01430   datagram.add_be_int16(_next_road_id);
01431   datagram.add_be_int16(_next_cat_id);
01432 
01433   if (get_flt_version() >= 1520) {
01434     // New with 15.2
01435     datagram.pad_bytes(2 + 2 + 2 + 2);
01436     datagram.add_be_int32(_earth_model);
01437 
01438     datagram.pad_bytes(4);
01439 
01440     if (get_flt_version() >= 1560) {
01441       // New with 15.6
01442       datagram.add_be_int16(_next_adaptive_id);
01443       datagram.add_be_int16(_next_curve_id);
01444       datagram.pad_bytes(4);
01445 
01446       if (get_flt_version() >= 1570) {
01447         // New with 15.7
01448         datagram.add_be_float64(_delta_z);
01449         datagram.add_be_float64(_radius);
01450         datagram.add_be_int16(_next_mesh_id);
01451         datagram.pad_bytes(2);
01452         datagram.pad_bytes(4);
01453       }
01454     }
01455   }
01456 
01457   return true;
01458 }
01459 
01460 ////////////////////////////////////////////////////////////////////
01461 //     Function: FltHeader::write_ancillary
01462 //       Access: Protected, Virtual
01463 //  Description: Writes whatever ancillary records are required for
01464 //               this bead.  Returns FE_ok on success, or something
01465 //               else on error.
01466 ////////////////////////////////////////////////////////////////////
01467 FltError FltHeader::
01468 write_ancillary(FltRecordWriter &writer) const {
01469   FltError result;
01470 
01471   result = write_color_palette(writer);
01472   if (result != FE_ok) {
01473     return result;
01474   }
01475 
01476   result = write_material_palette(writer);
01477   if (result != FE_ok) {
01478     return result;
01479   }
01480 
01481   result = write_texture_palette(writer);
01482   if (result != FE_ok) {
01483     return result;
01484   }
01485 
01486   result = write_light_source_palette(writer);
01487   if (result != FE_ok) {
01488     return result;
01489   }
01490 
01491   result = write_eyepoint_palette(writer);
01492   if (result != FE_ok) {
01493     return result;
01494   }
01495 
01496   result = write_vertex_palette(writer);
01497   if (result != FE_ok) {
01498     return result;
01499   }
01500 
01501   return FltBeadID::write_ancillary(writer);
01502 }
01503 
01504 ////////////////////////////////////////////////////////////////////
01505 //     Function: FltHeader::extract_vertex
01506 //       Access: Private
01507 //  Description: Reads a single vertex ancillary record.  It is
01508 //               assumed that all the vertex records will immediately
01509 //               follow the vertex palette record.
01510 ////////////////////////////////////////////////////////////////////
01511 bool FltHeader::
01512 extract_vertex(FltRecordReader &reader) {
01513   FltVertex *vertex = new FltVertex(this);
01514   if (!vertex->extract_record(reader)) {
01515     return false;
01516   }
01517   _vertices.push_back(vertex);
01518   _unique_vertices.insert(vertex);
01519   _offsets_by_vertex[vertex] = _current_vertex_offset;
01520   _vertices_by_offset[_current_vertex_offset] = vertex;
01521   _current_vertex_offset += reader.get_record_length();
01522 
01523   // _vertex_lookups_stale remains false.
01524 
01525   return true;
01526 }
01527 
01528 ////////////////////////////////////////////////////////////////////
01529 //     Function: FltHeader::extract_color_palette
01530 //       Access: Private
01531 //  Description: Reads the color palette.
01532 ////////////////////////////////////////////////////////////////////
01533 bool FltHeader::
01534 extract_color_palette(FltRecordReader &reader) {
01535   nassertr(reader.get_opcode() == FO_color_palette, false);
01536   DatagramIterator &iterator = reader.get_iterator();
01537 
01538   if (_got_color_palette) {
01539     nout << "Warning: multiple color palettes found.\n";
01540   }
01541   _got_color_palette = true;
01542 
01543   static const int expected_color_entries = 1024;
01544 
01545   iterator.skip_bytes(128);
01546   _colors.clear();
01547   for (int i = 0; i < expected_color_entries; i++) {
01548     if (iterator.get_remaining_size() == 0) {
01549       // An early end to the palette is acceptable.
01550       return true;
01551     }
01552     FltPackedColor color;
01553     if (!color.extract_record(reader)) {
01554       return false;
01555     }
01556     _colors.push_back(color);
01557   }
01558 
01559   // Now pull out the color names.
01560   while (iterator.get_remaining_size() > 0) {
01561     int entry_length = iterator.get_be_uint16();
01562     iterator.skip_bytes(2);
01563     if (iterator.get_remaining_size() > 0) {
01564       int color_index = iterator.get_be_int16();
01565       iterator.skip_bytes(2);
01566 
01567       int name_length = entry_length - 8;
01568       nassertr(color_index >= 0 && color_index < (int)_colors.size(), false);
01569       _color_names[color_index] = iterator.get_fixed_string(name_length);
01570     }
01571   }
01572 
01573   check_remaining_size(iterator, "color palette");
01574   return true;
01575 }
01576 
01577 ////////////////////////////////////////////////////////////////////
01578 //     Function: FltHeader::extract_material
01579 //       Access: Private
01580 //  Description: Reads a single material ancillary record.
01581 ////////////////////////////////////////////////////////////////////
01582 bool FltHeader::
01583 extract_material(FltRecordReader &reader) {
01584   PT(FltMaterial) material = new FltMaterial(this);
01585   if (!material->extract_record(reader)) {
01586     return false;
01587   }
01588   add_material(material);
01589 
01590   return true;
01591 }
01592 
01593 ////////////////////////////////////////////////////////////////////
01594 //     Function: FltHeader::extract_14_material_palette
01595 //       Access: Private
01596 //  Description: Reads the v14.2 material palette.
01597 ////////////////////////////////////////////////////////////////////
01598 bool FltHeader::
01599 extract_14_material_palette(FltRecordReader &reader) {
01600   nassertr(reader.get_opcode() == FO_14_material_palette, false);
01601   DatagramIterator &iterator = reader.get_iterator();
01602 
01603   if (_got_14_material_palette) {
01604     nout << "Warning: multiple material palettes found.\n";
01605   }
01606   _got_14_material_palette = true;
01607 
01608   static const int expected_material_entries = 64;
01609 
01610   _materials.clear();
01611   for (int i = 0; i < expected_material_entries; i++) {
01612     if (iterator.get_remaining_size() == 0) {
01613       // An early end to the palette is acceptable.
01614       return true;
01615     }
01616     PT(FltMaterial) material = new FltMaterial(this);
01617     if (!material->extract_14_record(i, iterator)) {
01618       return false;
01619     }
01620     add_material(material);
01621   }
01622 
01623   check_remaining_size(iterator, "material palette");
01624   return true;
01625 }
01626 
01627 ////////////////////////////////////////////////////////////////////
01628 //     Function: FltHeader::extract_texture
01629 //       Access: Private
01630 //  Description: Reads a single texture ancillary record.
01631 ////////////////////////////////////////////////////////////////////
01632 bool FltHeader::
01633 extract_texture(FltRecordReader &reader) {
01634   FltTexture *texture = new FltTexture(this);
01635   if (!texture->extract_record(reader)) {
01636     return false;
01637   }
01638   add_texture(texture);
01639 
01640   return true;
01641 }
01642 
01643 ////////////////////////////////////////////////////////////////////
01644 //     Function: FltHeader::extract_texture_map
01645 //       Access: Private
01646 //  Description: Reads the a single texture mapping ancillary record.
01647 //               This describes a kind of texture mapping in the
01648 //               texture mapping palette.
01649 ////////////////////////////////////////////////////////////////////
01650 bool FltHeader::
01651 extract_texture_map(FltRecordReader &reader) {
01652   // At the moment, we ignore this, since it's not needed for
01653   // meaningful extraction of data: we can get this information from
01654   // the UV's for a particular model.  We just add an
01655   // UnsupportedRecord for it.
01656   FltUnsupportedRecord *rec = new FltUnsupportedRecord(this);
01657   if (!rec->extract_record(reader)) {
01658     return false;
01659   }
01660   add_ancillary(rec);
01661 
01662   return true;
01663 }
01664 
01665 ////////////////////////////////////////////////////////////////////
01666 //     Function: FltHeader::extract_light_source
01667 //       Access: Private
01668 //  Description: Reads a single light source ancillary record.
01669 ////////////////////////////////////////////////////////////////////
01670 bool FltHeader::
01671 extract_light_source(FltRecordReader &reader) {
01672   FltLightSourceDefinition *light_source = new FltLightSourceDefinition(this);
01673   if (!light_source->extract_record(reader)) {
01674     return false;
01675   }
01676   add_light_source(light_source);
01677 
01678   return true;
01679 }
01680 
01681 ////////////////////////////////////////////////////////////////////
01682 //     Function: FltHeader::extract_eyepoint_palette
01683 //       Access: Private
01684 //  Description: Reads the eyepoint/trackplane palette.
01685 ////////////////////////////////////////////////////////////////////
01686 bool FltHeader::
01687 extract_eyepoint_palette(FltRecordReader &reader) {
01688   nassertr(reader.get_opcode() == FO_eyepoint_palette, false);
01689   DatagramIterator &iterator = reader.get_iterator();
01690 
01691   iterator.skip_bytes(4);
01692 
01693   int i;
01694   int num_eyepoints = get_num_eyepoints();
01695   for (i = 0; i < num_eyepoints; i++) {
01696     if (!_eyepoints[i].extract_record(reader)) {
01697       return false;
01698     }
01699   }
01700 
01701   int num_trackplanes = get_num_trackplanes();
01702   for (i = 0; i < num_trackplanes; i++) {
01703     if (!_trackplanes[i].extract_record(reader)) {
01704       return false;
01705     }
01706   }
01707 
01708   _got_eyepoint_trackplane_palette = true;
01709 
01710   if (get_flt_version() >= 1420) {
01711     // I have no idea what bytes are supposed to be here in earlier
01712     // versions that 14.2, but who really cares?  Don't bother
01713     // reporting it if there are too many bytes in old versions.
01714     check_remaining_size(iterator, "eyepoint palette");
01715   }
01716   return true;
01717 }
01718 
01719 ////////////////////////////////////////////////////////////////////
01720 //     Function: FltHeader::write_vertex_palette
01721 //       Access: Private
01722 //  Description: Writes out the vertex palette with all of its
01723 //               vertices.
01724 ////////////////////////////////////////////////////////////////////
01725 FltError FltHeader::
01726 write_vertex_palette(FltRecordWriter &writer) const {
01727   FltError result;
01728 
01729   int vertex_palette_length =
01730     ((FltHeader *)this)->update_vertex_lookups();
01731   Datagram vertex_palette;
01732   vertex_palette.add_be_int32(vertex_palette_length);
01733   result = writer.write_record(FO_vertex_palette, vertex_palette);
01734   if (result != FE_ok) {
01735     return result;
01736   }
01737   // Now write out each vertex in the palette.
01738   Vertices::const_iterator vi;
01739   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
01740     FltVertex *vertex = (*vi);
01741     vertex->build_record(writer);
01742     result = writer.advance();
01743     if (result != FE_ok) {
01744       return result;
01745     }
01746   }
01747 
01748   return FE_ok;
01749 }
01750 
01751 
01752 ////////////////////////////////////////////////////////////////////
01753 //     Function: FltHeader::write_color_palette
01754 //       Access: Private
01755 //  Description: Writes out the color palette.
01756 ////////////////////////////////////////////////////////////////////
01757 FltError FltHeader::
01758 write_color_palette(FltRecordWriter &writer) const {
01759   writer.set_opcode(FO_color_palette);
01760   Datagram &datagram = writer.update_datagram();
01761 
01762   datagram.pad_bytes(128);
01763 
01764   // How many colors should we write?
01765   int num_colors = 1024;
01766 
01767   Colors::const_iterator ci;
01768   for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
01769     if (!(*ci).build_record(writer)) {
01770       assert(!flt_error_abort);
01771       return FE_invalid_record;
01772     }
01773     num_colors--;
01774   }
01775 
01776   // Now we might need to pad the record to fill up the required
01777   // number of colors.
01778   if (num_colors > 0) {
01779     FltPackedColor empty;
01780     while (num_colors > 0) {
01781       if (!empty.build_record(writer)) {
01782         assert(!flt_error_abort);
01783         return FE_invalid_record;
01784       }
01785       num_colors--;
01786     }
01787   }
01788 
01789   // Now append all the names at the end.
01790   ColorNames::const_iterator ni;
01791   for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
01792     string name = (*ni).second.substr(0, 80);
01793     int entry_length = name.length() + 8;
01794     datagram.add_be_uint16(entry_length);
01795     datagram.pad_bytes(2);
01796     datagram.add_be_uint16((*ni).first);
01797     datagram.pad_bytes(2);
01798     datagram.add_fixed_string(name, name.length());
01799   }
01800 
01801   return writer.advance();
01802 }
01803 
01804 ////////////////////////////////////////////////////////////////////
01805 //     Function: FltHeader::write_material_palette
01806 //       Access: Private
01807 //  Description: Writes out the material palette.
01808 ////////////////////////////////////////////////////////////////////
01809 FltError FltHeader::
01810 write_material_palette(FltRecordWriter &writer) const {
01811   FltError result;
01812 
01813   if (get_flt_version() >= 1520) {
01814     // Write a version 15 material palette.
01815     Materials::const_iterator mi;
01816     for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
01817       FltMaterial *material = (*mi).second;
01818       material->build_record(writer);
01819 
01820       result = writer.advance();
01821       if (result != FE_ok) {
01822         return result;
01823       }
01824     }
01825 
01826   } else {
01827     // Write a version 14 material palette.
01828     if (_materials.empty()) {
01829       // No palette is OK.
01830       return FE_ok;
01831     }
01832     writer.set_opcode(FO_14_material_palette);
01833     Datagram &datagram = writer.update_datagram();
01834 
01835     PT(FltMaterial) dummy_material = new FltMaterial(_header);
01836 
01837     Materials::const_iterator mi = _materials.lower_bound(0);
01838     int index;
01839     static const int expected_material_entries = 64;
01840     for (index = 0; index < expected_material_entries; index++) {
01841       if (mi == _materials.end() || index < (*mi).first) {
01842         dummy_material->build_14_record(datagram);
01843       } else {
01844         nassertr(index == (*mi).first, FE_internal);
01845         FltMaterial *material = (*mi).second;
01846         material->build_14_record(datagram);
01847         ++mi;
01848       }
01849     }
01850 
01851     result = writer.advance();
01852     if (result != FE_ok) {
01853       return result;
01854     }
01855   }
01856 
01857   return FE_ok;
01858 }
01859 
01860 ////////////////////////////////////////////////////////////////////
01861 //     Function: FltHeader::write_texture_palette
01862 //       Access: Private
01863 //  Description: Writes out the texture palette.
01864 ////////////////////////////////////////////////////////////////////
01865 FltError FltHeader::
01866 write_texture_palette(FltRecordWriter &writer) const {
01867   FltError result;
01868 
01869   Textures::const_iterator ti;
01870   for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
01871     FltTexture *texture = (*ti).second;
01872     texture->build_record(writer);
01873     result = writer.advance();
01874     if (result != FE_ok) {
01875       return result;
01876     }
01877   }
01878 
01879   return FE_ok;
01880 }
01881 
01882 ////////////////////////////////////////////////////////////////////
01883 //     Function: FltHeader::write_light_source_palette
01884 //       Access: Private
01885 //  Description: Writes out the light source palette.
01886 ////////////////////////////////////////////////////////////////////
01887 FltError FltHeader::
01888 write_light_source_palette(FltRecordWriter &writer) const {
01889   FltError result;
01890 
01891   LightSources::const_iterator li;
01892   for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
01893     FltLightSourceDefinition *light_source = (*li).second;
01894     light_source->build_record(writer);
01895     result = writer.advance();
01896     if (result != FE_ok) {
01897       return result;
01898     }
01899   }
01900 
01901   return FE_ok;
01902 }
01903 
01904 ////////////////////////////////////////////////////////////////////
01905 //     Function: FltHeader::write_eyepoint_palette
01906 //       Access: Private
01907 //  Description: Writes out the eyepoint/trackplane palette, if we
01908 //               have one.
01909 ////////////////////////////////////////////////////////////////////
01910 FltError FltHeader::
01911 write_eyepoint_palette(FltRecordWriter &writer) const {
01912   if (!_got_eyepoint_trackplane_palette) {
01913     return FE_ok;
01914   }
01915 
01916   writer.set_opcode(FO_eyepoint_palette);
01917   Datagram &datagram = writer.update_datagram();
01918   datagram.pad_bytes(4);
01919 
01920   int i;
01921   int num_eyepoints = get_num_eyepoints();
01922   for (i = 0; i < num_eyepoints; i++) {
01923     if (!_eyepoints[i].build_record(writer)) {
01924       assert(!flt_error_abort);
01925       return FE_bad_data;
01926     }
01927   }
01928 
01929   int num_trackplanes = get_num_trackplanes();
01930   for (i = 0; i < num_trackplanes; i++) {
01931     if (!_trackplanes[i].build_record(writer)) {
01932       assert(!flt_error_abort);
01933       return FE_bad_data;
01934     }
01935   }
01936 
01937   return writer.advance();
01938 }
 All Classes Functions Variables Enumerations