Panda3D
|
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 }