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  */
112 void FltHeader::
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  */
127 void FltHeader::
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  */
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  */
170 void FltHeader::
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  */
178 const Filename &FltHeader::
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  */
290 void FltHeader::
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::
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  */
308 int FltHeader::
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  */
321 void FltHeader::
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  */
334 int FltHeader::
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  */
344 int FltHeader::
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  */
356 bool FltHeader::
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  */
412 bool FltHeader::
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  */
434 void FltHeader::
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  */
444 void FltHeader::
446  _instances[instance->_instance_index] = instance;
447 }
448 
449 /**
450  * Removes a particular instance subtree from the pool, if it exists.
451  */
452 void FltHeader::
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  */
460 int FltHeader::
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  */
477 void FltHeader::
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  */
490 void FltHeader::
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  */
525 int FltHeader::
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  */
549 int FltHeader::
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  */
558 LColor FltHeader::
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  */
595 bool FltHeader::
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  */
617 int FltHeader::
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  */
679 int FltHeader::
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  */
737 int FltHeader::
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  */
747 int FltHeader::
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  */
757 LColor FltHeader::
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  */
797 bool FltHeader::
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  */
819 void FltHeader::
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  */
829 void FltHeader::
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  */
848 void FltHeader::
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  */
856 bool FltHeader::
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  */
878 void FltHeader::
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  */
888 void FltHeader::
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  */
907 void FltHeader::
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  */
915 bool FltHeader::
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  */
937 void FltHeader::
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  */
947 void FltHeader::
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  */
956 void FltHeader::
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  */
966 bool FltHeader::
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  */
977 void FltHeader::
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  */
986 int FltHeader::
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  */
1004 int FltHeader::
1006  return 10;
1007 }
1008 
1009 /**
1010  * Returns the nth trackplane in the eyepoint/trackplane palette.
1011  */
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 }
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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_dirname() const
Returns the directory part of the filename.
Definition: filename.I:358
A single eyepoint entry in the eyepoint/trackplane palette.
Definition: fltEyepoint.h:27
bool has_material(int material_index) const
Returns true if a material with the given index has been defined.
Definition: fltHeader.cxx:798
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_flt_version() const
Returns the version number of the flt file as reported in the header, times 100.
Definition: fltHeader.cxx:309
FltTrackplane * get_trackplane(int n)
Returns the nth trackplane in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1013
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly.
int get_num_trackplanes() const
Returns the number of trackplanes in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:1005
A base class for any of a broad family of flt beads that include an ID.
Definition: fltBeadID.h:24
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class turns an istream into a sequence of FltRecords by reading a sequence of Datagrams and extr...
std::string get_color_name(int color_index) const
Returns the name associated with the given color, if any.
Definition: fltHeader.cxx:604
bool build_14_record(Datagram &datagram)
Fills up the current record on the FltRecordWriter with data for this record, formatted as a part of ...
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
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
bool has_texture(int texture_index) const
Returns true if a texture with the given index has been defined.
Definition: fltHeader.cxx:857
static int max_flt_version()
Returns the latest flt version number that this codebase is known to support (times 100).
Definition: fltHeader.cxx:345
A hierarchy of directories and files that appears to be one continuous file system,...
PathReplace * get_path_replace()
Returns a pointer to the PathReplace object associated with this converter.
Definition: fltHeader.cxx:138
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,...
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
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
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
FltVertex * get_vertex(int n) const
Returns the nth vertex of the vertex palette.
Definition: fltHeader.cxx:469
Represents a single material in the material palette.
Definition: fltMaterial.h:28
void clear_materials()
Removes all materials from the palette.
Definition: fltHeader.cxx:820
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
FltError write_flt(Filename filename)
Opens the indicated filename for writing and attempts to write the complete Flt file.
Definition: fltHeader.cxx:237
void add_texture(FltTexture *texture)
Defines a new texture.
Definition: fltHeader.cxx:889
FltEyepoint * get_eyepoint(int n)
Returns the nth eyepoint in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:995
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
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 append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
bool check_version() const
Verifies that the version number read from the header is an understood version number,...
Definition: fltHeader.cxx:357
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
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
void pad_bytes(size_t size)
Adds the indicated number of zero bytes to the datagram.
Definition: datagram.cxx:99
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:44
DistanceUnit
This enumerated type lists all the kinds of units we're likely to come across in model conversion pro...
Definition: distanceUnit.h:23
int get_num_color_entries() const
Returns the number of actual entries in the color palette.
Definition: fltHeader.cxx:738
void remove_texture(int texture_index)
Removes a particular texture from the texture palette, if it exists.
Definition: fltHeader.cxx:908
void add_be_float64(PN_float64 value)
Adds a 64-bit big-endian floating-point number to the datagram.
Definition: datagram.I:209
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
void add_light_source(FltLightSourceDefinition *light_source)
Defines a new light source.
Definition: fltHeader.cxx:948
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
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
int get_num_vertices() const
Returns the number of vertices in the vertex palette.
Definition: fltHeader.cxx:461
A single trackplane entry in the eyepoint/trackplane palette.
Definition: fltTrackplane.h:27
void add_int8(int8_t value)
Adds a signed 8-bit integer to the datagram.
Definition: datagram.I:42
void clear_vertices()
Removes all vertices from the vertex palette.
Definition: fltHeader.cxx:478
static int min_flt_version()
Returns the earliest flt version number that this codebase supports (times 100).
Definition: fltHeader.cxx:335
LColor get_color(int color_index) const
Returns the four-component color corresponding to the given color index.
Definition: fltHeader.cxx:559
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:849
void add_be_uint16(uint16_t value)
Adds an unsigned 16-bit big-endian integer to the datagram.
Definition: datagram.I:172
void clear_instances()
Removes all instance subtrees from the instance pool.
Definition: fltHeader.cxx:435
Represents a single texture in the texture palette.
Definition: fltTexture.h:27
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
bool has_color_name(int color_index) const
Returns true if the given color is named, false otherwise.
Definition: fltHeader.cxx:596
void remove_instance(int instance_index)
Removes a particular instance subtree from the pool, if it exists.
Definition: fltHeader.cxx:453
int get_num_colors() const
Returns the total number of different colors in the color palette.
Definition: fltHeader.cxx:550
AttrUpdate get_auto_attr_update() const
Returns the current setting of the auto_attr_update flag.
Definition: fltHeader.cxx:300
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
void add_be_int16(int16_t value)
Adds a signed 16-bit big-endian integer to the datagram.
Definition: datagram.I:145
A packed color record, A, B, G, R.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
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
Represents a single vertex in the vertex palette.
Definition: fltVertex.h:32
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_light_source(int light_index) const
Returns true if a light source with the given index has been defined.
Definition: fltHeader.cxx:916
void add_be_uint32(uint32_t value)
Adds an unsigned 32-bit big-endian integer to the datagram.
Definition: datagram.I:181
int get_num_color_shades() const
Returns the number of shades of brightness of each entry in the color palette.
Definition: fltHeader.cxx:748
FltError advance()
Writes the current record to the flt file, and resets the current record to receive new data.
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
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_eyepoint_trackplane_palette(bool flag)
Sets the state of the eyepoint/trackplane palette flag.
Definition: fltHeader.cxx:978
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
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
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
void add_instance(FltInstanceDefinition *instance)
Defines a new instance subtree.
Definition: fltHeader.cxx:445
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.
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:207
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_int32(int32_t value)
Adds a signed 32-bit big-endian integer to the datagram.
Definition: datagram.I:154
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void add_material(FltMaterial *material)
Defines a new material.
Definition: fltHeader.cxx:830
void add_vertex(FltVertex *vertex)
Adds a new vertex to the end of the vertex palette.
Definition: fltHeader.cxx:491
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:291
void clear_light_sources()
Removes all light sources from the palette.
Definition: fltHeader.cxx:938
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void remove_light_source(int light_index)
Removes a particular light source from the light source palette, if it exists.
Definition: fltHeader.cxx:957
const Filename & get_flt_filename() const
Returns the directory in which the flt file is considered to reside.
Definition: fltHeader.cxx:179
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
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
This special kind of record marks the top node of an instance subtree.
bool has_instance(int instance_index) const
Returns true if a instance subtree with the given index has been defined.
Definition: fltHeader.cxx:413
void clear_textures()
Removes all textures from the palette.
Definition: fltHeader.cxx:879
bool eof() const
Returns true if end-of-file has been reached without error.
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...
int get_num_eyepoints() const
Returns the number of eyepoints in the eyepoint/trackplane palette.
Definition: fltHeader.cxx:987
int get_record_length() const
Returns the entire length of the record, including the four-byte header.