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