Panda3D
 All Classes Functions Variables Enumerations
fltHeader.cxx
1 // Filename: fltHeader.cxx
2 // Created by: drose (24Aug00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "fltHeader.h"
16 #include "fltRecordReader.h"
17 #include "fltRecordWriter.h"
18 #include "fltUnsupportedRecord.h"
19 #include "config_flt.h"
20 #include "zStream.h"
21 #include "nearly_zero.h"
22 #include "virtualFileSystem.h"
23 
24 #include <assert.h>
25 #include <math.h>
26 
27 TypeHandle FltHeader::_type_handle;
28 
29 ////////////////////////////////////////////////////////////////////
30 // Function: FltHeader::Constructor
31 // Access: Public
32 // Description: The FltHeader constructor accepts a PathReplace
33 // pointer; it uses this object to automatically convert
34 // all external filename and texture references. (This
35 // is necessary because the FltHeader has to look in the
36 // same directory as the texture to find the .attr file,
37 // so it must pre-convert at least the texture
38 // references.)
39 //
40 // Most of the other file converters do not have this
41 // requirement, so they do not need to pre-convert any
42 // pathname references.
43 ////////////////////////////////////////////////////////////////////
45 FltHeader(PathReplace *path_replace) : FltBeadID(this) {
46  if (path_replace == (PathReplace *)NULL) {
47  _path_replace = new PathReplace;
48  _path_replace->_path_store = PS_absolute;
49  } else {
50  _path_replace = path_replace;
51  }
52 
53  _format_revision_level = 1570;
54  _edit_revision_level = 1570;
55  _next_group_id = 1;
56  _next_lod_id = 1;
57  _next_object_id = 1;
58  _next_face_id = 1;
59  _unit_multiplier = 1;
60  _vertex_units = U_feet;
61  _texwhite_new = false;
62  _flags = 0;
63  _projection_type = PT_flat_earth;
64  _next_dof_id = 1;
65  _vertex_storage_type = VTS_double;
66  _database_origin = DO_open_flight;
67  _sw_x = 0.0;
68  _sw_y = 0.0;
69  _delta_x = 0.0;
70  _delta_y = 0.0;
71  _next_sound_id = 1;
72  _next_path_id = 1;
73  _next_clip_id = 1;
74  _next_text_id = 1;
75  _next_bsp_id = 1;
76  _next_switch_id = 1;
77  _sw_lat = 0.0;
78  _sw_long = 0.0;
79  _ne_lat = 0.0;
80  _ne_long = 0.0;
81  _origin_lat = 0.0;
82  _origin_long = 0.0;
83  _lambert_upper_lat = 0.0;
84  _lambert_lower_lat = 0.0;
85  _next_light_id = 1;
86  _next_road_id = 1;
87  _next_cat_id = 1;
88 
89  // New with 15.2
90  _earth_model = EM_wgs84;
91 
92  // New with 15.6
93  _next_adaptive_id = 0;
94  _next_curve_id = 0;
95 
96  // New with 15.7
97  _delta_z = 0.0;
98  _radius = 0.0;
99  _next_mesh_id = 0;
100 
101  _vertex_lookups_stale = false;
102  _current_vertex_offset = 0;
103  _next_material_index = 1;
104  _next_pattern_index = 1;
105  _got_color_palette = false;
106  _got_14_material_palette = false;
107  _got_eyepoint_trackplane_palette = false;
108 
109  _auto_attr_update = AU_if_missing;
110 }
111 
112 ////////////////////////////////////////////////////////////////////
113 // Function: FltHeader::apply_converted_filenames
114 // Access: Public, Virtual
115 // Description: Walks the hierarchy at this record and below and
116 // copies the _converted_filename record into the
117 // _orig_filename record, so the flt file will be
118 // written out with the converted filename instead of
119 // what was originally read in.
120 ////////////////////////////////////////////////////////////////////
121 void FltHeader::
123  Textures::const_iterator ti;
124  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
125  FltTexture *texture = (*ti).second;
126  texture->apply_converted_filenames();
127  }
128 
130 }
131 
132 ////////////////////////////////////////////////////////////////////
133 // Function: FltHeader::set_path_replace
134 // Access: Public
135 // Description: Replaces the PathReplace object (which specifies how
136 // to mangle paths from the source to the destination
137 // file) with a new one.
138 ////////////////////////////////////////////////////////////////////
139 void FltHeader::
141  _path_replace = path_replace;
142 }
143 
144 ////////////////////////////////////////////////////////////////////
145 // Function: FltHeader::get_path_replace
146 // Access: Public
147 // Description: Returns a pointer to the PathReplace object
148 // associated with this converter. If the converter is
149 // non-const, this returns a non-const pointer, which
150 // can be adjusted.
151 ////////////////////////////////////////////////////////////////////
154  return _path_replace;
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: FltHeader::get_path_replace
159 // Access: Public
160 // Description: Returns a pointer to the PathReplace object
161 // associated with this converter. If the converter is
162 // non-const, this returns a non-const pointer, which
163 // can be adjusted.
164 ////////////////////////////////////////////////////////////////////
167  return _path_replace;
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: FltHeader::convert_path
172 // Access: Public
173 // Description: Uses the PathReplace object to convert the named
174 // filename as read from the flt record to its actual
175 // name.
176 ////////////////////////////////////////////////////////////////////
178 convert_path(const Filename &orig_filename, const DSearchPath &additional_path) {
179  DSearchPath file_path;
180  if (!_flt_filename.empty()) {
181  file_path.append_directory(_flt_filename.get_dirname());
182  }
183  file_path.append_path(additional_path);
184  return _path_replace->convert_path(orig_filename, file_path);
185 }
186 
187 ////////////////////////////////////////////////////////////////////
188 // Function: FltHeader::set_flt_filename
189 // Access: Public
190 // Description: Sets the filename--especially the directory part--in
191 // which the flt file is considered to reside. This is
192 // also implicitly set by read_flt().
193 ////////////////////////////////////////////////////////////////////
194 void FltHeader::
195 set_flt_filename(const Filename &flt_filename) {
196  _flt_filename = flt_filename;
197 }
198 
199 ////////////////////////////////////////////////////////////////////
200 // Function: FltHeader::get_flt_filename
201 // Access: Public
202 // Description: Returns the directory in which the flt file is
203 // considered to reside.
204 ////////////////////////////////////////////////////////////////////
205 const Filename &FltHeader::
207  return _flt_filename;
208 }
209 
210 ////////////////////////////////////////////////////////////////////
211 // Function: FltHeader::read_flt
212 // Access: Public
213 // Description: Opens the indicated filename for reading and attempts
214 // to read the complete Flt file. Returns FE_ok on
215 // success, otherwise on failure.
216 ////////////////////////////////////////////////////////////////////
217 FltError FltHeader::
218 read_flt(Filename filename) {
219  filename.set_binary();
220  _flt_filename = filename;
221 
223  istream *in = vfs->open_read_file(filename, true);
224  if (in == (istream *)NULL) {
225  assert(!flt_error_abort);
226  return FE_could_not_open;
227  }
228  FltError result = read_flt(*in);
229  vfs->close_read_file(in);
230  return result;
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: FltHeader::read_flt
235 // Access: Public
236 // Description: Attempts to read a complete Flt file from the
237 // already-opened stream. Returns FE_ok on success,
238 // otherwise on failure.
239 ////////////////////////////////////////////////////////////////////
240 FltError FltHeader::
241 read_flt(istream &in) {
242  FltRecordReader reader(in);
243  FltError result = reader.advance();
244  if (result == FE_end_of_file) {
245  assert(!flt_error_abort);
246  return FE_empty_file;
247  } else if (result != FE_ok) {
248  return result;
249  }
250 
251  result = read_record_and_children(reader);
252  if (result != FE_ok) {
253  return result;
254  }
255 
256  if (!reader.eof()) {
257  assert(!flt_error_abort);
258  return FE_extra_data;
259  }
260 
261  return FE_ok;
262 }
263 
264 
265 ////////////////////////////////////////////////////////////////////
266 // Function: FltHeader::write_flt
267 // Access: Public
268 // Description: Opens the indicated filename for writing and attempts
269 // to write the complete Flt file. Returns FE_ok on
270 // success, otherwise on failure.
271 ////////////////////////////////////////////////////////////////////
272 FltError FltHeader::
273 write_flt(Filename filename) {
274  filename.set_binary();
275 
276  ofstream out;
277  if (!filename.open_write(out)) {
278  assert(!flt_error_abort);
279  return FE_could_not_open;
280  }
281 
282 #ifdef HAVE_ZLIB
283  if (filename.get_extension() == "pz") {
284  // The filename ends in .pz, which means to automatically compress
285  // the flt file that we write.
286  OCompressStream compressor(&out, false);
287  return write_flt(compressor);
288  }
289 #endif // HAVE_ZLIB
290 
291  return write_flt(out);
292 }
293 
294 ////////////////////////////////////////////////////////////////////
295 // Function: FltHeader::write_flt
296 // Access: Public
297 // Description: Attempts to write a complete Flt file to the
298 // already-opened stream. Returns FE_ok on success,
299 // otherwise on failure.
300 ////////////////////////////////////////////////////////////////////
301 FltError FltHeader::
302 write_flt(ostream &out) {
303  FltRecordWriter writer(out);
304  FltError result = write_record_and_children(writer);
305 
306  if (out.fail()) {
307  assert(!flt_error_abort);
308  return FE_write_error;
309  }
310  return result;
311 }
312 
313 ////////////////////////////////////////////////////////////////////
314 // Function: FltHeader::set_auto_attr_update
315 // Access: Public
316 // Description: Controls whether texture .attr files are written
317 // automatically when write_flt() is called. There are
318 // three possibilities:
319 //
320 // AU_none: the .attr files are not written
321 // automatically; they must be written explicitly via a
322 // call to FltTexture::write_attr_data() if you want
323 // them to be written.
324 //
325 // AU_if_missing: the .attr files are written only if
326 // they do not already exist. This will not update any
327 // .attr files, even if the data is changed.
328 //
329 // AU_always: the .attr files are always rewritten, even
330 // if they already exist and even if the data has not
331 // changed.
332 //
333 // The default is AU_if_missing.
334 ////////////////////////////////////////////////////////////////////
335 void FltHeader::
336 set_auto_attr_update(FltHeader::AttrUpdate attr) {
337  _auto_attr_update = attr;
338 }
339 
340 ////////////////////////////////////////////////////////////////////
341 // Function: FltHeader::get_auto_attr_update
342 // Access: Public
343 // Description: Returns the current setting of the auto_attr_update
344 // flag. See sett_auto_attr_update().
345 ////////////////////////////////////////////////////////////////////
346 FltHeader::AttrUpdate FltHeader::
348  return _auto_attr_update;
349 }
350 
351 ////////////////////////////////////////////////////////////////////
352 // Function: FltHeader::get_flt_version
353 // Access: Public
354 // Description: Returns the version number of the flt file as
355 // reported in the header, times 100. Divide by 100 to
356 // get the floating-point version number.
357 ////////////////////////////////////////////////////////////////////
358 int FltHeader::
360  if (_format_revision_level < 1420) {
361  return _format_revision_level * 100;
362  } else {
363  return _format_revision_level;
364  }
365 }
366 
367 ////////////////////////////////////////////////////////////////////
368 // Function: FltHeader::set_flt_version
369 // Access: Public
370 // Description: Changes the version number of the flt file that will
371 // be reported in the header. Pass in the
372 // floating-point version number times 100.
373 ////////////////////////////////////////////////////////////////////
374 void FltHeader::
375 set_flt_version(int version) {
376  if (version < 14.2) {
377  _format_revision_level = version / 100;
378  } else {
379  _format_revision_level = version;
380  }
381 }
382 
383 ////////////////////////////////////////////////////////////////////
384 // Function: FltHeader::min_flt_version
385 // Access: Public, Static
386 // Description: Returns the earliest flt version number that this
387 // codebase supports (times 100). Earlier versions will
388 // probably not work.
389 ////////////////////////////////////////////////////////////////////
390 int FltHeader::
392  return 1400;
393 }
394 
395 ////////////////////////////////////////////////////////////////////
396 // Function: FltHeader::max_flt_version
397 // Access: Public, Static
398 // Description: Returns the latest flt version number that this
399 // codebase is known to support (times 100). Later
400 // versions might work, but then again they may not.
401 ////////////////////////////////////////////////////////////////////
402 int FltHeader::
404  return 1570;
405 }
406 
407 ////////////////////////////////////////////////////////////////////
408 // Function: FltHeader::check_version
409 // Access: Public
410 // Description: Verifies that the version number read from the header
411 // is an understood version number, and prints a warning
412 // to the user if this is not so--the read may or may
413 // not succeed. Returns true if the version number is
414 // acceptable (and no warning is printed), or false if
415 // it is questionable (and a warning is printed).
416 ////////////////////////////////////////////////////////////////////
417 bool FltHeader::
418 check_version() const {
419  int version = get_flt_version();
420 
421  if (version < min_flt_version()) {
422  nout << "Warning! The version number of this file appears to be "
423  << version / 100.0 << ", which is older than " << min_flt_version() / 100.0
424  << ", the oldest OpenFlight version understood by this program. "
425  "It is unlikely that this program will be able to read the file "
426  "correctly.\n";
427  return false;
428  }
429 
430  if (version > max_flt_version()) {
431  nout << "Warning! The version number of this file appears to be "
432  << version / 100.0 << ", which is newer than " << max_flt_version() / 100.0
433  << ", the newest OpenFlight version understood by this program. "
434  "Chances are good that the program will still be able to read it "
435  "correctly, but any features in the file that are specific to "
436  "the latest version of OpenFlight will not be understood.\n";
437  return false;
438  }
439 
440  return true;
441 }
442 
443 ////////////////////////////////////////////////////////////////////
444 // Function: FltHeader::get_units
445 // Access: Public
446 // Description: Returns the units indicated by the flt header, or
447 // DU_invalid if the units in the header are not
448 // understood.
449 ////////////////////////////////////////////////////////////////////
450 DistanceUnit FltHeader::
451 get_units() const {
452  switch (_vertex_units) {
453  case FltHeader::U_meters:
454  return DU_meters;
455 
456  case FltHeader::U_kilometers:
457  return DU_kilometers;
458 
459  case FltHeader::U_feet:
460  return DU_feet;
461 
462  case FltHeader::U_inches:
463  return DU_inches;
464 
465  case FltHeader::U_nautical_miles:
466  return DU_nautical_miles;
467  }
468 
469  // Unknown units.
470  return DU_invalid;
471 }
472 
473 ////////////////////////////////////////////////////////////////////
474 // Function: FltHeader::has_instance
475 // Access: Public
476 // Description: Returns true if a instance subtree with the given
477 // index has been defined.
478 ////////////////////////////////////////////////////////////////////
479 bool FltHeader::
480 has_instance(int instance_index) const {
481  return (_instances.count(instance_index) != 0);
482 }
483 
484 ////////////////////////////////////////////////////////////////////
485 // Function: FltHeader::get_instance
486 // Access: Public
487 // Description: Returns the instance subtree associated with the
488 // given index, or NULL if there is no such instance.
489 ////////////////////////////////////////////////////////////////////
491 get_instance(int instance_index) const {
492  Instances::const_iterator mi;
493  mi = _instances.find(instance_index);
494  if (mi != _instances.end()) {
495  return (*mi).second;
496  }
497  return (FltInstanceDefinition *)NULL;
498 }
499 
500 ////////////////////////////////////////////////////////////////////
501 // Function: FltHeader::clear_instances
502 // Access: Public
503 // Description: Removes all instance subtrees from the instance pool.
504 ////////////////////////////////////////////////////////////////////
505 void FltHeader::
507  _instances.clear();
508 }
509 
510 ////////////////////////////////////////////////////////////////////
511 // Function: FltHeader::add_instance
512 // Access: Public
513 // Description: Defines a new instance subtree. This subtree is not
514 // itself part of the hierarchy; it marks geometry that
515 // may be instanced to various beads elsewhere in the
516 // hierarchy by creating a corresponding FltInstanceRef
517 // bead.
518 ////////////////////////////////////////////////////////////////////
519 void FltHeader::
521  _instances[instance->_instance_index] = instance;
522 }
523 
524 ////////////////////////////////////////////////////////////////////
525 // Function: FltHeader::remove_instance
526 // Access: Public
527 // Description: Removes a particular instance subtree from the pool,
528 // if it exists.
529 ////////////////////////////////////////////////////////////////////
530 void FltHeader::
531 remove_instance(int instance_index) {
532  _instances.erase(instance_index);
533 }
534 
535 ////////////////////////////////////////////////////////////////////
536 // Function: FltHeader::get_num_vertices
537 // Access: Public
538 // Description: Returns the number of vertices in the vertex palette.
539 ////////////////////////////////////////////////////////////////////
540 int FltHeader::
542  return _vertices.size();
543 }
544 
545 ////////////////////////////////////////////////////////////////////
546 // Function: FltHeader::get_vertex
547 // Access: Public
548 // Description: Returns the nth vertex of the vertex palette.
549 ////////////////////////////////////////////////////////////////////
551 get_vertex(int n) const {
552  nassertr(n >= 0 && n < (int)_vertices.size(), 0);
553  return _vertices[n];
554 }
555 
556 ////////////////////////////////////////////////////////////////////
557 // Function: FltHeader::clear_vertices
558 // Access: Public
559 // Description: Removes all vertices from the vertex palette.
560 ////////////////////////////////////////////////////////////////////
561 void FltHeader::
563  _vertices.clear();
564  _unique_vertices.clear();
565  _vertices_by_offset.clear();
566  _offsets_by_vertex.clear();
567  _vertex_lookups_stale = false;
568 }
569 
570 ////////////////////////////////////////////////////////////////////
571 // Function: FltHeader::add_vertex
572 // Access: Public
573 // Description: Adds a new vertex to the end of the vertex palette.
574 // If this particular vertex was already present in the
575 // palette, does nothing.
576 ////////////////////////////////////////////////////////////////////
577 void FltHeader::
579  bool inserted = _unique_vertices.insert(vertex).second;
580  if (inserted) {
581  _vertices.push_back(vertex);
582  }
583  _vertex_lookups_stale = true;
584  nassertv(_unique_vertices.size() == _vertices.size());
585 }
586 
587 ////////////////////////////////////////////////////////////////////
588 // Function: FltHeader::get_vertex_by_offset
589 // Access: Public
590 // Description: Returns the particular vertex pointer associated with
591 // the given byte offset into the vertex palette. If
592 // there is no such vertex in the palette, this
593 // generates an error message and returns NULL.
594 ////////////////////////////////////////////////////////////////////
596 get_vertex_by_offset(int offset) {
597  if (_vertex_lookups_stale) {
598  update_vertex_lookups();
599  }
600 
601  VerticesByOffset::const_iterator vi;
602  vi = _vertices_by_offset.find(offset);
603  if (vi == _vertices_by_offset.end()) {
604  nout << "No vertex with offset " << offset << "\n";
605  return (FltVertex *)NULL;
606  }
607  return (*vi).second;
608 }
609 
610 ////////////////////////////////////////////////////////////////////
611 // Function: FltHeader::get_offset_by_vertex
612 // Access: Public
613 // Description: Returns the byte offset into the vertex palette
614 // associated with the given vertex pointer. If there
615 // is no such vertex in the palette, this generates an
616 // error message and returns 0.
617 ////////////////////////////////////////////////////////////////////
618 int FltHeader::
620  if (_vertex_lookups_stale) {
621  update_vertex_lookups();
622  }
623 
624  OffsetsByVertex::const_iterator vi;
625  vi = _offsets_by_vertex.find(vertex);
626  if (vi == _offsets_by_vertex.end()) {
627  nout << "Vertex does not appear in palette.\n";
628  return 0;
629  }
630  return (*vi).second;
631 }
632 
633 ////////////////////////////////////////////////////////////////////
634 // Function: FltHeader::get_num_colors
635 // Access: Public
636 // Description: Returns the total number of different colors in the
637 // color palette. This includes all different colors,
638 // and represents the complete range of alloable color
639 // indices. This is different from the actual number of
640 // color entries as read directly from the color
641 // palette, since each color entry defines a number of
642 // different intensity levels--the value returned by
643 // get_num_colors() is equal to get_num_color_entries()
644 // * get_num_color_shades().
645 ////////////////////////////////////////////////////////////////////
646 int FltHeader::
647 get_num_colors() const {
648  return _colors.size() * get_num_color_shades();
649 }
650 
651 ////////////////////////////////////////////////////////////////////
652 // Function: FltHeader::get_color
653 // Access: Public
654 // Description: Returns the four-component color corresponding to the
655 // given color index. Each component will be in the
656 // range [0, 1].
657 ////////////////////////////////////////////////////////////////////
659 get_color(int color_index) const {
660  nassertr(color_index >= 0 && color_index < get_num_colors(),
661  LColor(0.0, 0.0, 0.0, 0.0));
662  int num_color_shades = get_num_color_shades();
663 
664  int index = (color_index / num_color_shades);
665  int level = (color_index % num_color_shades);
666  nassertr(index >= 0 && index < (int)_colors.size(),
667  LColor(0.0, 0.0, 0.0, 0.0));
668 
669  LColor color = _colors[index].get_color();
670  return color * ((double)level / (double)(num_color_shades - 1));
671 }
672 
673 ////////////////////////////////////////////////////////////////////
674 // Function: FltHeader::get_rgb
675 // Access: Public
676 // Description: Returns the three-component color corresponding to
677 // the given color index, ignoring the alpha component.
678 // Each component will be in the range [0, 1].
679 ////////////////////////////////////////////////////////////////////
681 get_rgb(int color_index) const {
682  nassertr(color_index >= 0 && color_index < get_num_colors(),
683  LRGBColor(0.0, 0.0, 0.0));
684  int num_color_shades = get_num_color_shades();
685 
686  int index = (color_index / num_color_shades);
687  int level = (color_index % num_color_shades);
688  nassertr(index >= 0 && index < (int)_colors.size(),
689  LRGBColor(0.0, 0.0, 0.0));
690 
691  LRGBColor color = _colors[index].get_rgb();
692  return color * ((double)level / (double)(num_color_shades - 1));
693 }
694 
695 ////////////////////////////////////////////////////////////////////
696 // Function: FltHeader::has_color_name
697 // Access: Public
698 // Description: Returns true if the given color is named, false
699 // otherwise.
700 ////////////////////////////////////////////////////////////////////
701 bool FltHeader::
702 has_color_name(int color_index) const {
703  return (_color_names.count(color_index) != 0);
704 }
705 
706 ////////////////////////////////////////////////////////////////////
707 // Function: FltHeader::get_color_name
708 // Access: Public
709 // Description: Returns the name associated with the given color, if
710 // any.
711 ////////////////////////////////////////////////////////////////////
712 string FltHeader::
713 get_color_name(int color_index) const {
714  ColorNames::const_iterator ni;
715  ni = _color_names.find(color_index);
716  if (ni != _color_names.end()) {
717  return (*ni).second;
718  }
719  return string();
720 }
721 
722 ////////////////////////////////////////////////////////////////////
723 // Function: FltHeader::get_closest_color
724 // Access: Public
725 // Description: Returns the color index of the nearest color in the
726 // palette that matches the given four-component color,
727 // including alpha.
728 ////////////////////////////////////////////////////////////////////
729 int FltHeader::
730 get_closest_color(const LColor &color0) const {
731  // Since the colortable stores the brightest colors, with
732  // num_color_shades scaled versions of each color implicitly
733  // available, we really only care about the relative brightnesses of
734  // the various components. Normalize the color in terms of the
735  // largest of these.
736  LColor color = color0;
737 
738  double scale = 1.0;
739 
740  if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0 && color[3] == 0.0) {
741  // Oh, this is invisible black.
742  scale = 0.0;
743  color.set(1.0, 1.0, 1.0, 1.0);
744 
745  } else {
746  if (color[0] >= color[1] && color[0] >= color[2] && color[0] >= color[3]) {
747  // color[0] is largest.
748  scale = color[0];
749 
750  } else if (color[1] >= color[2] && color[1] >= color[3]) {
751  // color[1] is largest.
752  scale = color[1];
753 
754  } else if (color[2] >= color[3]) {
755  // color[2] is largest.
756  scale = color[2];
757 
758  } else {
759  // color[3] is largest.
760  scale = color[3];
761  }
762  color /= scale;
763  }
764 
765  // Now search for the best match.
766  PN_stdfloat best_dist = 5.0; // Greater than 4.
767  int best_i = -1;
768 
769  int num_color_entries = get_num_color_entries();
770  for (int i = 0; i < num_color_entries; i++) {
771  LColor consider = _colors[i].get_color();
772  PN_stdfloat dist2 = dot(consider - color, consider - color);
773  nassertr(dist2 < 5.0, 0);
774 
775  if (dist2 < best_dist) {
776  best_dist = dist2;
777  best_i = i;
778  }
779  }
780  nassertr(best_i >= 0, 0);
781 
782  int num_color_shades = get_num_color_shades();
783  int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
784 
785  return (best_i * num_color_shades) + shade_index;
786 }
787 
788 ////////////////////////////////////////////////////////////////////
789 // Function: FltHeader::get_closest_rgb
790 // Access: Public
791 // Description: Returns the color index of the nearest color in the
792 // palette that matches the given three-component color,
793 // ignoring alpha.
794 ////////////////////////////////////////////////////////////////////
795 int FltHeader::
796 get_closest_rgb(const LRGBColor &color0) const {
797  // Since the colortable stores the brightest colors, with
798  // num_color_shades scaled versions of each color implicitly
799  // available, we really only care about the relative brightnesses of
800  // the various components. Normalize the color in terms of the
801  // largest of these.
802 
803  LRGBColor color = color0;
804  double scale = 1.0;
805 
806  if (color[0] == 0.0 && color[1] == 0.0 && color[2] == 0.0) {
807  // Oh, this is black.
808  scale = 0.0;
809  color.set(1.0, 1.0, 1.0);
810 
811  } else {
812  if (color[0] >= color[1] && color[0] >= color[2]) {
813  // color[0] is largest.
814  scale = color[0];
815 
816  } else if (color[1] >= color[2]) {
817  // color[1] is largest.
818  scale = color[1];
819 
820  } else {
821  // color[2] is largest.
822  scale = color[2];
823  }
824  color /= scale;
825  }
826 
827  // Now search for the best match.
828  PN_stdfloat best_dist = 5.0; // Greater than 4.
829  int best_i = -1;
830 
831  int num_color_entries = get_num_color_entries();
832  for (int i = 0; i < num_color_entries; i++) {
833  LRGBColor consider = _colors[i].get_rgb();
834  PN_stdfloat dist2 = dot(consider - color, consider - color);
835  nassertr(dist2 < 5.0, 0);
836 
837  if (dist2 < best_dist) {
838  best_dist = dist2;
839  best_i = i;
840  }
841  }
842  nassertr(best_i >= 0, 0);
843 
844  int num_color_shades = get_num_color_shades();
845  int shade_index = (int)floor((num_color_shades-1) * scale + 0.5);
846 
847  return (best_i * num_color_shades) + shade_index;
848 }
849 
850 ////////////////////////////////////////////////////////////////////
851 // Function: FltHeader::get_num_color_entries
852 // Access: Public
853 // Description: Returns the number of actual entries in the color
854 // palette. This is based on the version of the flt
855 // file, and is usually either 512 or 1024.
856 ////////////////////////////////////////////////////////////////////
857 int FltHeader::
859  return _colors.size();
860 }
861 
862 ////////////////////////////////////////////////////////////////////
863 // Function: FltHeader::get_num_color_shades
864 // Access: Public
865 // Description: Returns the number of shades of brightness of each
866 // entry in the color palette. This is a fixed property
867 // of MultiGen files: each entry in the palette actually
868 // represents a range of this many colors.
869 ////////////////////////////////////////////////////////////////////
870 int FltHeader::
872  return 128;
873 }
874 
875 ////////////////////////////////////////////////////////////////////
876 // Function: FltHeader::get_color
877 // Access: Public
878 // Description: Decodes a MultiGen color, as stored on a face or
879 // vertex, into an actual four-component LColor.
880 // Normally you need not call this directly; there are
881 // color accessors defined on faces and vertices that do
882 // this.
883 ////////////////////////////////////////////////////////////////////
885 get_color(int color_index, bool use_packed_color,
886  const FltPackedColor &packed_color,
887  int transparency) {
888  if (!use_packed_color) {
889  return get_color(color_index);
890  }
891 
892  LColor color;
893  color[0] = packed_color._r / 255.0;
894  color[1] = packed_color._g / 255.0;
895  color[2] = packed_color._b / 255.0;
896  // MultiGen doesn't yet use the A component of RGBA.
897  //color[3] = packed_color._a / 255.0;
898  color[3] = 1.0 - (transparency / 65535.0);
899  return color;
900 }
901 
902 ////////////////////////////////////////////////////////////////////
903 // Function: FltHeader::get_color
904 // Access: Public
905 // Description: Decodes a MultiGen color, as stored on a face or
906 // vertex, into an actual three-component LRGBColor.
907 // Normally you need not call this directly; there are
908 // color accessors defined on faces and vertices that do
909 // this.
910 ////////////////////////////////////////////////////////////////////
912 get_rgb(int color_index, bool use_packed_color,
913  const FltPackedColor &packed_color) {
914  if (!use_packed_color) {
915  return get_rgb(color_index);
916  }
917 
919  color[0] = packed_color._r / 255.0;
920  color[1] = packed_color._g / 255.0;
921  color[2] = packed_color._b / 255.0;
922  return color;
923 }
924 
925 ////////////////////////////////////////////////////////////////////
926 // Function: FltHeader::has_material
927 // Access: Public
928 // Description: Returns true if a material with the given index has
929 // been defined.
930 ////////////////////////////////////////////////////////////////////
931 bool FltHeader::
932 has_material(int material_index) const {
933  return (_materials.count(material_index) != 0);
934 }
935 
936 ////////////////////////////////////////////////////////////////////
937 // Function: FltHeader::get_material
938 // Access: Public
939 // Description: Returns the material associated with the given index,
940 // or NULL if there is no such material.
941 ////////////////////////////////////////////////////////////////////
943 get_material(int material_index) const {
944  Materials::const_iterator mi;
945  mi = _materials.find(material_index);
946  if (mi != _materials.end()) {
947  return (*mi).second;
948  }
949  return (FltMaterial *)NULL;
950 }
951 
952 ////////////////////////////////////////////////////////////////////
953 // Function: FltHeader::clear_materials
954 // Access: Public
955 // Description: Removes all materials from the palette.
956 ////////////////////////////////////////////////////////////////////
957 void FltHeader::
959  _materials.clear();
960 }
961 
962 ////////////////////////////////////////////////////////////////////
963 // Function: FltHeader::add_material
964 // Access: Public
965 // Description: Defines a new material. The material is added in the
966 // position indicated by the material's index number.
967 // If there is already a material defined for that index
968 // number, it is replaced.
969 ////////////////////////////////////////////////////////////////////
970 void FltHeader::
972  if (material->_material_index < 0) {
973  // We need to make up a new material index for the material.
974  material->_material_index = _next_material_index;
975  _next_material_index++;
976 
977  } else {
978  // Make sure our next generated material index will be different
979  // from any existing material indices.
980  _next_material_index = max(_next_material_index, material->_material_index + 1);
981  }
982 
983  _materials[material->_material_index] = material;
984 }
985 
986 ////////////////////////////////////////////////////////////////////
987 // Function: FltHeader::remove_material
988 // Access: Public
989 // Description: Removes a particular material from the material
990 // palette, if it exists.
991 ////////////////////////////////////////////////////////////////////
992 void FltHeader::
993 remove_material(int material_index) {
994  _materials.erase(material_index);
995 }
996 
997 ////////////////////////////////////////////////////////////////////
998 // Function: FltHeader::has_texture
999 // Access: Public
1000 // Description: Returns true if a texture with the given index has
1001 // been defined.
1002 ////////////////////////////////////////////////////////////////////
1003 bool FltHeader::
1004 has_texture(int texture_index) const {
1005  return (_textures.count(texture_index) != 0);
1006 }
1007 
1008 ////////////////////////////////////////////////////////////////////
1009 // Function: FltHeader::get_texture
1010 // Access: Public
1011 // Description: Returns the texture associated with the given index,
1012 // or NULL if there is no such texture.
1013 ////////////////////////////////////////////////////////////////////
1015 get_texture(int texture_index) const {
1016  Textures::const_iterator mi;
1017  mi = _textures.find(texture_index);
1018  if (mi != _textures.end()) {
1019  return (*mi).second;
1020  }
1021  return (FltTexture *)NULL;
1022 }
1023 
1024 ////////////////////////////////////////////////////////////////////
1025 // Function: FltHeader::clear_textures
1026 // Access: Public
1027 // Description: Removes all textures from the palette.
1028 ////////////////////////////////////////////////////////////////////
1029 void FltHeader::
1031  _textures.clear();
1032 }
1033 
1034 ////////////////////////////////////////////////////////////////////
1035 // Function: FltHeader::add_texture
1036 // Access: Public
1037 // Description: Defines a new texture. The texture is added in the
1038 // position indicated by the texture's index number.
1039 // If there is already a texture defined for that index
1040 // number, it is replaced.
1041 ////////////////////////////////////////////////////////////////////
1042 void FltHeader::
1044  if (texture->_pattern_index < 0) {
1045  // We need to make up a new pattern index for the texture.
1046  texture->_pattern_index = _next_pattern_index;
1047  _next_pattern_index++;
1048 
1049  } else {
1050  // Make sure our next generated pattern index will be different
1051  // from any existing texture indices.
1052  _next_pattern_index = max(_next_pattern_index, texture->_pattern_index + 1);
1053  }
1054 
1055  _textures[texture->_pattern_index] = texture;
1056 }
1057 
1058 ////////////////////////////////////////////////////////////////////
1059 // Function: FltHeader::remove_texture
1060 // Access: Public
1061 // Description: Removes a particular texture from the texture
1062 // palette, if it exists.
1063 ////////////////////////////////////////////////////////////////////
1064 void FltHeader::
1065 remove_texture(int texture_index) {
1066  _textures.erase(texture_index);
1067 }
1068 
1069 ////////////////////////////////////////////////////////////////////
1070 // Function: FltHeader::has_light_source
1071 // Access: Public
1072 // Description: Returns true if a light source with the given index
1073 // has been defined.
1074 ////////////////////////////////////////////////////////////////////
1075 bool FltHeader::
1076 has_light_source(int light_index) const {
1077  return (_light_sources.count(light_index) != 0);
1078 }
1079 
1080 ////////////////////////////////////////////////////////////////////
1081 // Function: FltHeader::get_light_source
1082 // Access: Public
1083 // Description: Returns the light source associated with the given
1084 // index, or NULL if there is no such light source.
1085 ////////////////////////////////////////////////////////////////////
1087 get_light_source(int light_index) const {
1088  LightSources::const_iterator li;
1089  li = _light_sources.find(light_index);
1090  if (li != _light_sources.end()) {
1091  return (*li).second;
1092  }
1093  return (FltLightSourceDefinition *)NULL;
1094 }
1095 
1096 ////////////////////////////////////////////////////////////////////
1097 // Function: FltHeader::clear_light_sources
1098 // Access: Public
1099 // Description: Removes all light sources from the palette.
1100 ////////////////////////////////////////////////////////////////////
1101 void FltHeader::
1103  _light_sources.clear();
1104 }
1105 
1106 ////////////////////////////////////////////////////////////////////
1107 // Function: FltHeader::add_light_source
1108 // Access: Public
1109 // Description: Defines a new light source. The light source is
1110 // added in the position indicated by its light index
1111 // number. If there is already a light source defined
1112 // for that index number, it is replaced.
1113 ////////////////////////////////////////////////////////////////////
1114 void FltHeader::
1116  _light_sources[light_source->_light_index] = light_source;
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////
1120 // Function: FltHeader::remove_light_source
1121 // Access: Public
1122 // Description: Removes a particular light source from the light
1123 // source palette, if it exists.
1124 ////////////////////////////////////////////////////////////////////
1125 void FltHeader::
1126 remove_light_source(int light_index) {
1127  _light_sources.erase(light_index);
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////
1131 // Function: FltHeader::got_eyepoint_trackplane_palette
1132 // Access: Public
1133 // Description: Returns true if we have read an eyepoint/trackplane
1134 // palette, and at least some of the eyepoints and
1135 // trackplanes are therefore expected to be meaningful.
1136 ////////////////////////////////////////////////////////////////////
1137 bool FltHeader::
1139  return _got_eyepoint_trackplane_palette;
1140 }
1141 
1142 ////////////////////////////////////////////////////////////////////
1143 // Function: FltHeader::set_eyepoint_trackplane_palette
1144 // Access: Public
1145 // Description: Sets the state of the eyepoint/trackplane palette
1146 // flag. When this is false, the palette is believed to
1147 // be meaningless, and will not be written; when it is
1148 // true, the palette is believed to contain at least
1149 // some meaningful data, and will be written.
1150 ////////////////////////////////////////////////////////////////////
1151 void FltHeader::
1153  _got_eyepoint_trackplane_palette = flag;
1154 }
1155 
1156 ////////////////////////////////////////////////////////////////////
1157 // Function: FltHeader::get_num_eyepoints
1158 // Access: Public
1159 // Description: Returns the number of eyepoints in the
1160 // eyepoint/trackplane palette. This is presently fixed
1161 // at 10, according to the MultiGen specs.
1162 ////////////////////////////////////////////////////////////////////
1163 int FltHeader::
1165  return 10;
1166 }
1167 
1168 ////////////////////////////////////////////////////////////////////
1169 // Function: FltHeader::get_eyepoint
1170 // Access: Public
1171 // Description: Returns the nth eyepoint in the eyepoint/trackplane
1172 // palette.
1173 ////////////////////////////////////////////////////////////////////
1176  nassertr(n >= 0 && n < get_num_eyepoints(), (FltEyepoint *)NULL);
1177  return &_eyepoints[n];
1178 }
1179 
1180 ////////////////////////////////////////////////////////////////////
1181 // Function: FltHeader::get_num_trackplanes
1182 // Access: Public
1183 // Description: Returns the number of trackplanes in the
1184 // eyepoint/trackplane palette. This is presently fixed
1185 // at 10, according to the MultiGen specs.
1186 ////////////////////////////////////////////////////////////////////
1187 int FltHeader::
1189  return 10;
1190 }
1191 
1192 ////////////////////////////////////////////////////////////////////
1193 // Function: FltHeader::get_trackplane
1194 // Access: Public
1195 // Description: Returns the nth trackplane in the eyepoint/trackplane
1196 // palette.
1197 ////////////////////////////////////////////////////////////////////
1200  nassertr(n >= 0 && n < get_num_trackplanes(), (FltTrackplane *)NULL);
1201  return &_trackplanes[n];
1202 }
1203 
1204 ////////////////////////////////////////////////////////////////////
1205 // Function: FltHeader::update_vertex_lookups
1206 // Access: Public
1207 // Description: Recomputes the offsets_by_vertex and
1208 // vertices_by_offset tables. This reflects the flt
1209 // file as it will be written out, but not necessarily
1210 // as it was read in.
1211 //
1212 // The return value is the total length of the vertex
1213 // palette, including the header record.
1214 ////////////////////////////////////////////////////////////////////
1215 int FltHeader::
1216 update_vertex_lookups() {
1217  // We start with the length of the vertex palette record itself.
1218  int offset = 8;
1219 
1220  Vertices::const_iterator vi;
1221  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1222  FltVertex *vertex = (*vi);
1223 
1224  _offsets_by_vertex[vertex] = offset;
1225  _vertices_by_offset[offset] = vertex;
1226  offset += vertex->get_record_length();
1227  }
1228 
1229  _vertex_lookups_stale = false;
1230 
1231  return offset;
1232 }
1233 
1234 ////////////////////////////////////////////////////////////////////
1235 // Function: FltHeader::extract_record
1236 // Access: Protected, Virtual
1237 // Description: Fills in the information in this bead based on the
1238 // information given in the indicated datagram, whose
1239 // opcode has already been read. Returns true on
1240 // success, false if the datagram is invalid.
1241 ////////////////////////////////////////////////////////////////////
1242 bool FltHeader::
1243 extract_record(FltRecordReader &reader) {
1244  if (!FltBeadID::extract_record(reader)) {
1245  return false;
1246  }
1247 
1248  nassertr(reader.get_opcode() == FO_header, false);
1249  DatagramIterator &iterator = reader.get_iterator();
1250 
1251  _format_revision_level = iterator.get_be_int32();
1252  _edit_revision_level = iterator.get_be_int32();
1253  _last_revision = iterator.get_fixed_string(32);
1254  _next_group_id = iterator.get_be_int16();
1255  _next_lod_id = iterator.get_be_int16();
1256  _next_object_id = iterator.get_be_int16();
1257  _next_face_id = iterator.get_be_int16();
1258  _unit_multiplier = iterator.get_be_int16();
1259  _vertex_units = (Units)iterator.get_int8();
1260  _texwhite_new = (iterator.get_int8() != 0);
1261  _flags = iterator.get_be_uint32();
1262  iterator.skip_bytes(24);
1263  _projection_type = (ProjectionType)iterator.get_be_int32();
1264  iterator.skip_bytes(28);
1265  _next_dof_id = iterator.get_be_int16();
1266  _vertex_storage_type = (VertexStorageType)iterator.get_be_int16();
1267  _database_origin = (DatabaseOrigin)iterator.get_be_int32();
1268  _sw_x = iterator.get_be_float64();
1269  _sw_y = iterator.get_be_float64();
1270  _delta_x = iterator.get_be_float64();
1271  _delta_y = iterator.get_be_float64();
1272  _next_sound_id = iterator.get_be_int16();
1273  _next_path_id = iterator.get_be_int16();
1274  iterator.skip_bytes(8);
1275  _next_clip_id = iterator.get_be_int16();
1276  _next_text_id = iterator.get_be_int16();
1277  _next_bsp_id = iterator.get_be_int16();
1278  _next_switch_id = iterator.get_be_int16();
1279  iterator.skip_bytes(4);
1280  _sw_lat = iterator.get_be_float64();
1281  _sw_long = iterator.get_be_float64();
1282  _ne_lat = iterator.get_be_float64();
1283  _ne_long = iterator.get_be_float64();
1284  _origin_lat = iterator.get_be_float64();
1285  _origin_long = iterator.get_be_float64();
1286  _lambert_upper_lat = iterator.get_be_float64();
1287  _lambert_lower_lat = iterator.get_be_float64();
1288  _next_light_id = iterator.get_be_int16();
1289  iterator.skip_bytes(2);
1290  if (get_flt_version() >= 1420 && iterator.get_remaining_size() > 0) {
1291  _next_road_id = iterator.get_be_int16();
1292  _next_cat_id = iterator.get_be_int16();
1293 
1294  if (get_flt_version() >= 1520 && iterator.get_remaining_size() > 0) {
1295  iterator.skip_bytes(2 + 2 + 2 + 2);
1296  _earth_model = (EarthModel)iterator.get_be_int32();
1297 
1298  // Undocumented padding.
1299  iterator.skip_bytes(4);
1300 
1301  if (get_flt_version() >= 1560 && iterator.get_remaining_size() > 0) {
1302  _next_adaptive_id = iterator.get_be_int16();
1303  _next_curve_id = iterator.get_be_int16();
1304  iterator.skip_bytes(4);
1305 
1306  if (get_flt_version() >= 1570 && iterator.get_remaining_size() > 0) {
1307  _delta_z = iterator.get_be_float64();
1308  _radius = iterator.get_be_float64();
1309  _next_mesh_id = iterator.get_be_int16();
1310  iterator.skip_bytes(2);
1311 
1312  // Undocumented padding.
1313  iterator.skip_bytes(4);
1314  }
1315  }
1316  }
1317  }
1318 
1319  check_remaining_size(iterator);
1320  return true;
1321 }
1322 
1323 ////////////////////////////////////////////////////////////////////
1324 // Function: FltHeader::extract_ancillary
1325 // Access: Protected, Virtual
1326 // Description: Checks whether the given bead, which follows this
1327 // bead sequentially in the file, is an ancillary record
1328 // of this bead. If it is, extracts the relevant
1329 // information and returns true; otherwise, leaves it
1330 // alone and returns false.
1331 ////////////////////////////////////////////////////////////////////
1332 bool FltHeader::
1333 extract_ancillary(FltRecordReader &reader) {
1334  switch (reader.get_opcode()) {
1335  case FO_vertex_palette:
1336  // We're about to begin the vertex palette!
1337  clear_vertices();
1338  _current_vertex_offset = reader.get_record_length();
1339  return true;
1340 
1341  case FO_vertex_c:
1342  case FO_vertex_cn:
1343  case FO_vertex_cnu:
1344  case FO_vertex_cu:
1345  // Here's a new vertex for the palette.
1346  return extract_vertex(reader);
1347 
1348  case FO_color_palette:
1349  return extract_color_palette(reader);
1350 
1351  case FO_15_material:
1352  return extract_material(reader);
1353 
1354  case FO_14_material_palette:
1355  return extract_14_material_palette(reader);
1356 
1357  case FO_texture:
1358  return extract_texture(reader);
1359 
1360  case FO_texture_map_palette:
1361  return extract_texture_map(reader);
1362 
1363  case FO_light_definition:
1364  return extract_light_source(reader);
1365 
1366  case FO_eyepoint_palette:
1367  return extract_eyepoint_palette(reader);
1368 
1369  default:
1370  return FltBeadID::extract_ancillary(reader);
1371  }
1372 }
1373 
1374 ////////////////////////////////////////////////////////////////////
1375 // Function: FltHeader::build_record
1376 // Access: Protected, Virtual
1377 // Description: Fills up the current record on the FltRecordWriter with
1378 // data for this record, but does not advance the
1379 // writer. Returns true on success, false if there is
1380 // some error.
1381 ////////////////////////////////////////////////////////////////////
1382 bool FltHeader::
1383 build_record(FltRecordWriter &writer) const {
1384  if (!FltBeadID::build_record(writer)) {
1385  return false;
1386  }
1387 
1388  writer.set_opcode(FO_header);
1389  Datagram &datagram = writer.update_datagram();
1390 
1391  datagram.add_be_int32(_format_revision_level);
1392  datagram.add_be_int32(_edit_revision_level);
1393  datagram.add_fixed_string(_last_revision, 32);
1394  datagram.add_be_int16(_next_group_id);
1395  datagram.add_be_int16(_next_lod_id);
1396  datagram.add_be_int16(_next_object_id);
1397  datagram.add_be_int16(_next_face_id);
1398  datagram.add_be_int16(_unit_multiplier);
1399  datagram.add_int8(_vertex_units);
1400  datagram.add_int8(_texwhite_new);
1401  datagram.add_be_uint32(_flags);
1402  datagram.pad_bytes(24);
1403  datagram.add_be_int32(_projection_type);
1404  datagram.pad_bytes(28);
1405  datagram.add_be_int16(_next_dof_id);
1406  datagram.add_be_int16(_vertex_storage_type);
1407  datagram.add_be_int32(_database_origin);
1408  datagram.add_be_float64(_sw_x);
1409  datagram.add_be_float64(_sw_y);
1410  datagram.add_be_float64(_delta_x);
1411  datagram.add_be_float64(_delta_y);
1412  datagram.add_be_int16(_next_sound_id);
1413  datagram.add_be_int16(_next_path_id);
1414  datagram.pad_bytes(8);
1415  datagram.add_be_int16(_next_clip_id);
1416  datagram.add_be_int16(_next_text_id);
1417  datagram.add_be_int16(_next_bsp_id);
1418  datagram.add_be_int16(_next_switch_id);
1419  datagram.pad_bytes(4);
1420  datagram.add_be_float64(_sw_lat);
1421  datagram.add_be_float64(_sw_long);
1422  datagram.add_be_float64(_ne_lat);
1423  datagram.add_be_float64(_ne_long);
1424  datagram.add_be_float64(_origin_lat);
1425  datagram.add_be_float64(_origin_long);
1426  datagram.add_be_float64(_lambert_upper_lat);
1427  datagram.add_be_float64(_lambert_lower_lat);
1428  datagram.add_be_int16(_next_light_id);
1429  datagram.pad_bytes(2);
1430  datagram.add_be_int16(_next_road_id);
1431  datagram.add_be_int16(_next_cat_id);
1432 
1433  if (get_flt_version() >= 1520) {
1434  // New with 15.2
1435  datagram.pad_bytes(2 + 2 + 2 + 2);
1436  datagram.add_be_int32(_earth_model);
1437 
1438  datagram.pad_bytes(4);
1439 
1440  if (get_flt_version() >= 1560) {
1441  // New with 15.6
1442  datagram.add_be_int16(_next_adaptive_id);
1443  datagram.add_be_int16(_next_curve_id);
1444  datagram.pad_bytes(4);
1445 
1446  if (get_flt_version() >= 1570) {
1447  // New with 15.7
1448  datagram.add_be_float64(_delta_z);
1449  datagram.add_be_float64(_radius);
1450  datagram.add_be_int16(_next_mesh_id);
1451  datagram.pad_bytes(2);
1452  datagram.pad_bytes(4);
1453  }
1454  }
1455  }
1456 
1457  return true;
1458 }
1459 
1460 ////////////////////////////////////////////////////////////////////
1461 // Function: FltHeader::write_ancillary
1462 // Access: Protected, Virtual
1463 // Description: Writes whatever ancillary records are required for
1464 // this bead. Returns FE_ok on success, or something
1465 // else on error.
1466 ////////////////////////////////////////////////////////////////////
1467 FltError FltHeader::
1468 write_ancillary(FltRecordWriter &writer) const {
1469  FltError result;
1470 
1471  result = write_color_palette(writer);
1472  if (result != FE_ok) {
1473  return result;
1474  }
1475 
1476  result = write_material_palette(writer);
1477  if (result != FE_ok) {
1478  return result;
1479  }
1480 
1481  result = write_texture_palette(writer);
1482  if (result != FE_ok) {
1483  return result;
1484  }
1485 
1486  result = write_light_source_palette(writer);
1487  if (result != FE_ok) {
1488  return result;
1489  }
1490 
1491  result = write_eyepoint_palette(writer);
1492  if (result != FE_ok) {
1493  return result;
1494  }
1495 
1496  result = write_vertex_palette(writer);
1497  if (result != FE_ok) {
1498  return result;
1499  }
1500 
1501  return FltBeadID::write_ancillary(writer);
1502 }
1503 
1504 ////////////////////////////////////////////////////////////////////
1505 // Function: FltHeader::extract_vertex
1506 // Access: Private
1507 // Description: Reads a single vertex ancillary record. It is
1508 // assumed that all the vertex records will immediately
1509 // follow the vertex palette record.
1510 ////////////////////////////////////////////////////////////////////
1511 bool FltHeader::
1512 extract_vertex(FltRecordReader &reader) {
1513  FltVertex *vertex = new FltVertex(this);
1514  if (!vertex->extract_record(reader)) {
1515  return false;
1516  }
1517  _vertices.push_back(vertex);
1518  _unique_vertices.insert(vertex);
1519  _offsets_by_vertex[vertex] = _current_vertex_offset;
1520  _vertices_by_offset[_current_vertex_offset] = vertex;
1521  _current_vertex_offset += reader.get_record_length();
1522 
1523  // _vertex_lookups_stale remains false.
1524 
1525  return true;
1526 }
1527 
1528 ////////////////////////////////////////////////////////////////////
1529 // Function: FltHeader::extract_color_palette
1530 // Access: Private
1531 // Description: Reads the color palette.
1532 ////////////////////////////////////////////////////////////////////
1533 bool FltHeader::
1534 extract_color_palette(FltRecordReader &reader) {
1535  nassertr(reader.get_opcode() == FO_color_palette, false);
1536  DatagramIterator &iterator = reader.get_iterator();
1537 
1538  if (_got_color_palette) {
1539  nout << "Warning: multiple color palettes found.\n";
1540  }
1541  _got_color_palette = true;
1542 
1543  static const int expected_color_entries = 1024;
1544 
1545  iterator.skip_bytes(128);
1546  _colors.clear();
1547  for (int i = 0; i < expected_color_entries; i++) {
1548  if (iterator.get_remaining_size() == 0) {
1549  // An early end to the palette is acceptable.
1550  return true;
1551  }
1553  if (!color.extract_record(reader)) {
1554  return false;
1555  }
1556  _colors.push_back(color);
1557  }
1558 
1559  // Now pull out the color names.
1560  while (iterator.get_remaining_size() > 0) {
1561  int entry_length = iterator.get_be_uint16();
1562  iterator.skip_bytes(2);
1563  if (iterator.get_remaining_size() > 0) {
1564  int color_index = iterator.get_be_int16();
1565  iterator.skip_bytes(2);
1566 
1567  int name_length = entry_length - 8;
1568  nassertr(color_index >= 0 && color_index < (int)_colors.size(), false);
1569  _color_names[color_index] = iterator.get_fixed_string(name_length);
1570  }
1571  }
1572 
1573  check_remaining_size(iterator, "color palette");
1574  return true;
1575 }
1576 
1577 ////////////////////////////////////////////////////////////////////
1578 // Function: FltHeader::extract_material
1579 // Access: Private
1580 // Description: Reads a single material ancillary record.
1581 ////////////////////////////////////////////////////////////////////
1582 bool FltHeader::
1583 extract_material(FltRecordReader &reader) {
1584  PT(FltMaterial) material = new FltMaterial(this);
1585  if (!material->extract_record(reader)) {
1586  return false;
1587  }
1588  add_material(material);
1589 
1590  return true;
1591 }
1592 
1593 ////////////////////////////////////////////////////////////////////
1594 // Function: FltHeader::extract_14_material_palette
1595 // Access: Private
1596 // Description: Reads the v14.2 material palette.
1597 ////////////////////////////////////////////////////////////////////
1598 bool FltHeader::
1599 extract_14_material_palette(FltRecordReader &reader) {
1600  nassertr(reader.get_opcode() == FO_14_material_palette, false);
1601  DatagramIterator &iterator = reader.get_iterator();
1602 
1603  if (_got_14_material_palette) {
1604  nout << "Warning: multiple material palettes found.\n";
1605  }
1606  _got_14_material_palette = true;
1607 
1608  static const int expected_material_entries = 64;
1609 
1610  _materials.clear();
1611  for (int i = 0; i < expected_material_entries; i++) {
1612  if (iterator.get_remaining_size() == 0) {
1613  // An early end to the palette is acceptable.
1614  return true;
1615  }
1616  PT(FltMaterial) material = new FltMaterial(this);
1617  if (!material->extract_14_record(i, iterator)) {
1618  return false;
1619  }
1620  add_material(material);
1621  }
1622 
1623  check_remaining_size(iterator, "material palette");
1624  return true;
1625 }
1626 
1627 ////////////////////////////////////////////////////////////////////
1628 // Function: FltHeader::extract_texture
1629 // Access: Private
1630 // Description: Reads a single texture ancillary record.
1631 ////////////////////////////////////////////////////////////////////
1632 bool FltHeader::
1633 extract_texture(FltRecordReader &reader) {
1634  FltTexture *texture = new FltTexture(this);
1635  if (!texture->extract_record(reader)) {
1636  return false;
1637  }
1638  add_texture(texture);
1639 
1640  return true;
1641 }
1642 
1643 ////////////////////////////////////////////////////////////////////
1644 // Function: FltHeader::extract_texture_map
1645 // Access: Private
1646 // Description: Reads the a single texture mapping ancillary record.
1647 // This describes a kind of texture mapping in the
1648 // texture mapping palette.
1649 ////////////////////////////////////////////////////////////////////
1650 bool FltHeader::
1651 extract_texture_map(FltRecordReader &reader) {
1652  // At the moment, we ignore this, since it's not needed for
1653  // meaningful extraction of data: we can get this information from
1654  // the UV's for a particular model. We just add an
1655  // UnsupportedRecord for it.
1656  FltUnsupportedRecord *rec = new FltUnsupportedRecord(this);
1657  if (!rec->extract_record(reader)) {
1658  return false;
1659  }
1660  add_ancillary(rec);
1661 
1662  return true;
1663 }
1664 
1665 ////////////////////////////////////////////////////////////////////
1666 // Function: FltHeader::extract_light_source
1667 // Access: Private
1668 // Description: Reads a single light source ancillary record.
1669 ////////////////////////////////////////////////////////////////////
1670 bool FltHeader::
1671 extract_light_source(FltRecordReader &reader) {
1672  FltLightSourceDefinition *light_source = new FltLightSourceDefinition(this);
1673  if (!light_source->extract_record(reader)) {
1674  return false;
1675  }
1676  add_light_source(light_source);
1677 
1678  return true;
1679 }
1680 
1681 ////////////////////////////////////////////////////////////////////
1682 // Function: FltHeader::extract_eyepoint_palette
1683 // Access: Private
1684 // Description: Reads the eyepoint/trackplane palette.
1685 ////////////////////////////////////////////////////////////////////
1686 bool FltHeader::
1687 extract_eyepoint_palette(FltRecordReader &reader) {
1688  nassertr(reader.get_opcode() == FO_eyepoint_palette, false);
1689  DatagramIterator &iterator = reader.get_iterator();
1690 
1691  iterator.skip_bytes(4);
1692 
1693  int i;
1694  int num_eyepoints = get_num_eyepoints();
1695  for (i = 0; i < num_eyepoints; i++) {
1696  if (!_eyepoints[i].extract_record(reader)) {
1697  return false;
1698  }
1699  }
1700 
1701  int num_trackplanes = get_num_trackplanes();
1702  for (i = 0; i < num_trackplanes; i++) {
1703  if (!_trackplanes[i].extract_record(reader)) {
1704  return false;
1705  }
1706  }
1707 
1708  _got_eyepoint_trackplane_palette = true;
1709 
1710  if (get_flt_version() >= 1420) {
1711  // I have no idea what bytes are supposed to be here in earlier
1712  // versions that 14.2, but who really cares? Don't bother
1713  // reporting it if there are too many bytes in old versions.
1714  check_remaining_size(iterator, "eyepoint palette");
1715  }
1716  return true;
1717 }
1718 
1719 ////////////////////////////////////////////////////////////////////
1720 // Function: FltHeader::write_vertex_palette
1721 // Access: Private
1722 // Description: Writes out the vertex palette with all of its
1723 // vertices.
1724 ////////////////////////////////////////////////////////////////////
1725 FltError FltHeader::
1726 write_vertex_palette(FltRecordWriter &writer) const {
1727  FltError result;
1728 
1729  int vertex_palette_length =
1730  ((FltHeader *)this)->update_vertex_lookups();
1731  Datagram vertex_palette;
1732  vertex_palette.add_be_int32(vertex_palette_length);
1733  result = writer.write_record(FO_vertex_palette, vertex_palette);
1734  if (result != FE_ok) {
1735  return result;
1736  }
1737  // Now write out each vertex in the palette.
1738  Vertices::const_iterator vi;
1739  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
1740  FltVertex *vertex = (*vi);
1741  vertex->build_record(writer);
1742  result = writer.advance();
1743  if (result != FE_ok) {
1744  return result;
1745  }
1746  }
1747 
1748  return FE_ok;
1749 }
1750 
1751 
1752 ////////////////////////////////////////////////////////////////////
1753 // Function: FltHeader::write_color_palette
1754 // Access: Private
1755 // Description: Writes out the color palette.
1756 ////////////////////////////////////////////////////////////////////
1757 FltError FltHeader::
1758 write_color_palette(FltRecordWriter &writer) const {
1759  writer.set_opcode(FO_color_palette);
1760  Datagram &datagram = writer.update_datagram();
1761 
1762  datagram.pad_bytes(128);
1763 
1764  // How many colors should we write?
1765  int num_colors = 1024;
1766 
1767  Colors::const_iterator ci;
1768  for (ci = _colors.begin(); num_colors > 0 && ci != _colors.end(); ++ci) {
1769  if (!(*ci).build_record(writer)) {
1770  assert(!flt_error_abort);
1771  return FE_invalid_record;
1772  }
1773  num_colors--;
1774  }
1775 
1776  // Now we might need to pad the record to fill up the required
1777  // number of colors.
1778  if (num_colors > 0) {
1779  FltPackedColor empty;
1780  while (num_colors > 0) {
1781  if (!empty.build_record(writer)) {
1782  assert(!flt_error_abort);
1783  return FE_invalid_record;
1784  }
1785  num_colors--;
1786  }
1787  }
1788 
1789  // Now append all the names at the end.
1790  ColorNames::const_iterator ni;
1791  for (ni = _color_names.begin(); ni != _color_names.end(); ++ni) {
1792  string name = (*ni).second.substr(0, 80);
1793  int entry_length = name.length() + 8;
1794  datagram.add_be_uint16(entry_length);
1795  datagram.pad_bytes(2);
1796  datagram.add_be_uint16((*ni).first);
1797  datagram.pad_bytes(2);
1798  datagram.add_fixed_string(name, name.length());
1799  }
1800 
1801  return writer.advance();
1802 }
1803 
1804 ////////////////////////////////////////////////////////////////////
1805 // Function: FltHeader::write_material_palette
1806 // Access: Private
1807 // Description: Writes out the material palette.
1808 ////////////////////////////////////////////////////////////////////
1809 FltError FltHeader::
1810 write_material_palette(FltRecordWriter &writer) const {
1811  FltError result;
1812 
1813  if (get_flt_version() >= 1520) {
1814  // Write a version 15 material palette.
1815  Materials::const_iterator mi;
1816  for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
1817  FltMaterial *material = (*mi).second;
1818  material->build_record(writer);
1819 
1820  result = writer.advance();
1821  if (result != FE_ok) {
1822  return result;
1823  }
1824  }
1825 
1826  } else {
1827  // Write a version 14 material palette.
1828  if (_materials.empty()) {
1829  // No palette is OK.
1830  return FE_ok;
1831  }
1832  writer.set_opcode(FO_14_material_palette);
1833  Datagram &datagram = writer.update_datagram();
1834 
1835  PT(FltMaterial) dummy_material = new FltMaterial(_header);
1836 
1837  Materials::const_iterator mi = _materials.lower_bound(0);
1838  int index;
1839  static const int expected_material_entries = 64;
1840  for (index = 0; index < expected_material_entries; index++) {
1841  if (mi == _materials.end() || index < (*mi).first) {
1842  dummy_material->build_14_record(datagram);
1843  } else {
1844  nassertr(index == (*mi).first, FE_internal);
1845  FltMaterial *material = (*mi).second;
1846  material->build_14_record(datagram);
1847  ++mi;
1848  }
1849  }
1850 
1851  result = writer.advance();
1852  if (result != FE_ok) {
1853  return result;
1854  }
1855  }
1856 
1857  return FE_ok;
1858 }
1859 
1860 ////////////////////////////////////////////////////////////////////
1861 // Function: FltHeader::write_texture_palette
1862 // Access: Private
1863 // Description: Writes out the texture palette.
1864 ////////////////////////////////////////////////////////////////////
1865 FltError FltHeader::
1866 write_texture_palette(FltRecordWriter &writer) const {
1867  FltError result;
1868 
1869  Textures::const_iterator ti;
1870  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
1871  FltTexture *texture = (*ti).second;
1872  texture->build_record(writer);
1873  result = writer.advance();
1874  if (result != FE_ok) {
1875  return result;
1876  }
1877  }
1878 
1879  return FE_ok;
1880 }
1881 
1882 ////////////////////////////////////////////////////////////////////
1883 // Function: FltHeader::write_light_source_palette
1884 // Access: Private
1885 // Description: Writes out the light source palette.
1886 ////////////////////////////////////////////////////////////////////
1887 FltError FltHeader::
1888 write_light_source_palette(FltRecordWriter &writer) const {
1889  FltError result;
1890 
1891  LightSources::const_iterator li;
1892  for (li = _light_sources.begin(); li != _light_sources.end(); ++li) {
1893  FltLightSourceDefinition *light_source = (*li).second;
1894  light_source->build_record(writer);
1895  result = writer.advance();
1896  if (result != FE_ok) {
1897  return result;
1898  }
1899  }
1900 
1901  return FE_ok;
1902 }
1903 
1904 ////////////////////////////////////////////////////////////////////
1905 // Function: FltHeader::write_eyepoint_palette
1906 // Access: Private
1907 // Description: Writes out the eyepoint/trackplane palette, if we
1908 // have one.
1909 ////////////////////////////////////////////////////////////////////
1910 FltError FltHeader::
1911 write_eyepoint_palette(FltRecordWriter &writer) const {
1912  if (!_got_eyepoint_trackplane_palette) {
1913  return FE_ok;
1914  }
1915 
1916  writer.set_opcode(FO_eyepoint_palette);
1917  Datagram &datagram = writer.update_datagram();
1918  datagram.pad_bytes(4);
1919 
1920  int i;
1921  int num_eyepoints = get_num_eyepoints();
1922  for (i = 0; i < num_eyepoints; i++) {
1923  if (!_eyepoints[i].build_record(writer)) {
1924  assert(!flt_error_abort);
1925  return FE_bad_data;
1926  }
1927  }
1928 
1929  int num_trackplanes = get_num_trackplanes();
1930  for (i = 0; i < num_trackplanes; i++) {
1931  if (!_trackplanes[i].build_record(writer)) {
1932  assert(!flt_error_abort);
1933  return FE_bad_data;
1934  }
1935  }
1936 
1937  return writer.advance();
1938 }
int get_closest_color(const LColor &color) const
Returns the color index of the nearest color in the palette that matches the given four-component col...
Definition: fltHeader.cxx:730
int get_offset_by_vertex(FltVertex *vertex)
Returns the byte offset into the vertex palette associated with the given vertex pointer.
Definition: fltHeader.cxx:619
A single eyepoint entry in the eyepoint/trackplane palette.
Definition: fltEyepoint.h:30
int get_closest_rgb(const LRGBColor &color) const
Returns the color index of the nearest color in the palette that matches the given three-component co...
Definition: fltHeader.cxx:796
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
FltTrackplane * get_trackplane(int n)
Returns the nth trackplane in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1199
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly...
A base class for any of a broad family of flt beads that include an ID.
Definition: fltBeadID.h:27
This class turns an istream into a sequence of FltRecords by reading a sequence of Datagrams and extr...
bool build_14_record(Datagram &datagram)
Fills up the current record on the FltRecordWriter with data for this record, formatted as a part of ...
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
Definition: fltHeader.cxx:122
void set_flt_version(int version)
Changes the version number of the flt file that will be reported in the header.
Definition: fltHeader.cxx:375
DistanceUnit get_units() const
Returns the units indicated by the flt header, or DU_invalid if the units in the header are not under...
Definition: fltHeader.cxx:451
void add_int8(PN_int8 value)
Adds a signed 8-bit integer to the datagram.
Definition: datagram.I:128
static int max_flt_version()
Returns the latest flt version number that this codebase is known to support (times 100)...
Definition: fltHeader.cxx:403
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
PathReplace * get_path_replace()
Returns a pointer to the PathReplace object associated with this converter.
Definition: fltHeader.cxx:153
bool has_light_source(int light_index) const
Returns true if a light source with the given index has been defined.
Definition: fltHeader.cxx:1076
FltInstanceDefinition * get_instance(int instance_index) const
Returns the instance subtree associated with the given index, or NULL if there is no such instance...
Definition: fltHeader.cxx:491
bool eof() const
Returns true if end-of-file has been reached without error.
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
Definition: fltRecord.cxx:340
Represents a single material in the material palette.
Definition: fltMaterial.h:30
void clear_materials()
Removes all materials from the palette.
Definition: fltHeader.cxx:958
LColor get_color(int color_index) const
Returns the four-component color corresponding to the given color index.
Definition: fltHeader.cxx:659
FltError write_flt(Filename filename)
Opens the indicated filename for writing and attempts to write the complete Flt file.
Definition: fltHeader.cxx:273
bool has_instance(int instance_index) const
Returns true if a instance subtree with the given index has been defined.
Definition: fltHeader.cxx:480
void add_texture(FltTexture *texture)
Defines a new texture.
Definition: fltHeader.cxx:1043
FltEyepoint * get_eyepoint(int n)
Returns the nth eyepoint in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1175
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
FltVertex * get_vertex_by_offset(int offset)
Returns the particular vertex pointer associated with the given byte offset into the vertex palette...
Definition: fltHeader.cxx:596
void pad_bytes(size_t size)
Adds the indicated number of zero bytes to the datagram.
Definition: datagram.cxx:111
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:48
void append_path(const string &path, const string &separator=string())
Adds all of the directories listed in the search path to the end of the search list.
bool has_material(int material_index) const
Returns true if a material with the given index has been defined.
Definition: fltHeader.cxx:932
int get_num_colors() const
Returns the total number of different colors in the color palette.
Definition: fltHeader.cxx:647
void remove_texture(int texture_index)
Removes a particular texture from the texture palette, if it exists.
Definition: fltHeader.cxx:1065
void add_be_float64(PN_float64 value)
Adds a 64-bit big-endian floating-point number to the datagram.
Definition: datagram.I:339
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
Definition: fltTexture.cxx:98
void add_light_source(FltLightSourceDefinition *light_source)
Defines a new light source.
Definition: fltHeader.cxx:1115
FltMaterial * get_material(int material_index) const
Returns the material associated with the given index, or NULL if there is no such material...
Definition: fltHeader.cxx:943
A single trackplane entry in the eyepoint/trackplane palette.
Definition: fltTrackplane.h:30
FltVertex * get_vertex(int n) const
Returns the nth vertex of the vertex palette.
Definition: fltHeader.cxx:551
bool has_texture(int texture_index) const
Returns true if a texture with the given index has been defined.
Definition: fltHeader.cxx:1004
void clear_vertices()
Removes all vertices from the vertex palette.
Definition: fltHeader.cxx:562
static int min_flt_version()
Returns the earliest flt version number that this codebase supports (times 100).
Definition: fltHeader.cxx:391
Represents a single entry in the light source palette.
void remove_material(int material_index)
Removes a particular material from the material palette, if it exists.
Definition: fltHeader.cxx:993
void clear_instances()
Removes all instance subtrees from the instance pool.
Definition: fltHeader.cxx:506
Represents a single texture in the texture palette.
Definition: fltTexture.h:29
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
FltError read_flt(Filename filename)
Opens the indicated filename for reading and attempts to read the complete Flt file.
Definition: fltHeader.cxx:218
FltHeader(PathReplace *path_replace)
The FltHeader constructor accepts a PathReplace pointer; it uses this object to automatically convert...
Definition: fltHeader.cxx:45
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
const Filename & get_flt_filename() const
Returns the directory in which the flt file is considered to reside.
Definition: fltHeader.cxx:206
void remove_instance(int instance_index)
Removes a particular instance subtree from the pool, if it exists.
Definition: fltHeader.cxx:531
A packed color record, A, B, G, R.
FltLightSourceDefinition * get_light_source(int light_index) const
Returns the light source associated with the given index, or NULL if there is no such light source...
Definition: fltHeader.cxx:1087
void set_path_replace(PathReplace *path_replace)
Replaces the PathReplace object (which specifies how to mangle paths from the source to the destinati...
Definition: fltHeader.cxx:140
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Represents a single vertex in the vertex palette.
Definition: fltVertex.h:35
Filename convert_path(const Filename &orig_filename, const DSearchPath &additional_path=DSearchPath())
Uses the PathReplace object to convert the named filename as read from the flt record to its actual n...
Definition: fltHeader.cxx:178
istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read...
int get_num_eyepoints() const
Returns the number of eyepoints in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1164
void add_be_int32(PN_int32 value)
Adds a signed 32-bit big-endian integer to the datagram.
Definition: datagram.I:267
FltTexture * get_texture(int texture_index) const
Returns the texture associated with the given index, or NULL if there is no such texture.
Definition: fltHeader.cxx:1015
FltError advance()
Writes the current record to the flt file, and resets the current record to receive new data...
int get_record_length() const
Returns the length of this record in bytes as it will be written to the flt file. ...
Definition: fltVertex.cxx:70
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void check_remaining_size(const DatagramIterator &di, const string &name=string()) const
Checks that the iterator has no bytes left, as it should at the end of a successfully read record...
Definition: fltRecord.cxx:313
void set_flt_filename(const Filename &flt_filename)
Sets the filename–especially the directory part–in which the flt file is considered to reside...
Definition: fltHeader.cxx:195
void set_eyepoint_trackplane_palette(bool flag)
Sets the state of the eyepoint/trackplane palette flag.
Definition: fltHeader.cxx:1152
This encapsulates the user&#39;s command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:40
int get_num_vertices() const
Returns the number of vertices in the vertex palette.
Definition: fltHeader.cxx:541
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
bool check_version() const
Verifies that the version number read from the header is an understood version number, and prints a warning to the user if this is not so–the read may or may not succeed.
Definition: fltHeader.cxx:418
int get_num_trackplanes() const
Returns the number of trackplanes in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1188
int get_num_color_entries() const
Returns the number of actual entries in the color palette.
Definition: fltHeader.cxx:858
This class stores a list of directories that can be searched, in order, to locate a particular file...
Definition: dSearchPath.h:32
AttrUpdate get_auto_attr_update() const
Returns the current setting of the auto_attr_update flag.
Definition: fltHeader.cxx:347
void add_fixed_string(const string &str, size_t size)
Adds a fixed-length string to the datagram.
Definition: datagram.I:404
bool got_eyepoint_trackplane_palette() const
Returns true if we have read an eyepoint/trackplane palette, and at least some of the eyepoints and t...
Definition: fltHeader.cxx:1138
int get_num_color_shades() const
Returns the number of shades of brightness of each entry in the color palette.
Definition: fltHeader.cxx:871
string get_color_name(int color_index) const
Returns the name associated with the given color, if any.
Definition: fltHeader.cxx:713
void add_instance(FltInstanceDefinition *instance)
Defines a new instance subtree.
Definition: fltHeader.cxx:520
int get_flt_version() const
Returns the version number of the flt file as reported in the header, times 100.
Definition: fltHeader.cxx:359
void add_be_uint16(PN_uint16 value)
Adds an unsigned 16-bit big-endian integer to the datagram.
Definition: datagram.I:291
LRGBColor get_rgb(int color_index) const
Returns the three-component color corresponding to the given color index, ignoring the alpha componen...
Definition: fltHeader.cxx:681
A class to retrieve the individual data elements previously stored in a Datagram. ...
void add_ancillary(FltRecord *ancillary)
Adds a new unsupported ancillary record to the end of the list of ancillary records for this record...
Definition: fltRecord.cxx:253
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:2045
void add_be_uint32(PN_uint32 value)
Adds an unsigned 32-bit big-endian integer to the datagram.
Definition: datagram.I:303
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool has_color_name(int color_index) const
Returns true if the given color is named, false otherwise.
Definition: fltHeader.cxx:702
void add_material(FltMaterial *material)
Defines a new material.
Definition: fltHeader.cxx:971
void add_vertex(FltVertex *vertex)
Adds a new vertex to the end of the vertex palette.
Definition: fltHeader.cxx:578
void set_opcode(FltOpcode opcode)
Sets the opcode associated with the current record.
Datagram & update_datagram()
Returns a modifiable reference to the datagram associated with the current record.
void set_auto_attr_update(AttrUpdate attr)
Controls whether texture .attr files are written automatically when write_flt() is called...
Definition: fltHeader.cxx:336
void clear_light_sources()
Removes all light sources from the palette.
Definition: fltHeader.cxx:1102
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
string get_extension() const
Returns the file extension.
Definition: filename.I:477
void remove_light_source(int light_index)
Removes a particular light source from the light source palette, if it exists.
Definition: fltHeader.cxx:1126
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
int get_record_length() const
Returns the entire length of the record, including the four-byte header.
This special kind of record marks the top node of an instance subtree.
void add_be_int16(PN_int16 value)
Adds a signed 16-bit big-endian integer to the datagram.
Definition: datagram.I:255
void clear_textures()
Removes all textures from the palette.
Definition: fltHeader.cxx:1030
FltError write_record(FltOpcode opcode, const Datagram &datagram=Datagram())
A convenience function to quickly write a simple record that consists of an opcode and possibly a dat...