Panda3D
Loading...
Searching...
No Matches
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"
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
26TypeHandle 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 */
39FltHeader(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 */
128set_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 */
148get_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 */
157convert_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 */
171set_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 */
179get_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 */
188read_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 */
208read_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 */
237write_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 */
263write_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 */
291set_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 */
299FltHeader::AttrUpdate FltHeader::
300get_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 */
309get_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 */
322set_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 */
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 */
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 */
357check_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 */
387get_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 */
413has_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 */
422get_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 */
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 */
453remove_instance(int instance_index) {
454 _instances.erase(instance_index);
455}
456
457/**
458 * Returns the number of vertices in the vertex palette.
459 */
461get_num_vertices() const {
462 return _vertices.size();
463}
464
465/**
466 * Returns the nth vertex of the vertex palette.
467 */
469get_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 */
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 */
491add_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 */
506get_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 */
550get_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 */
559get_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 */
577LRGBColor FltHeader::
578get_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 */
596has_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 */
603std::string FltHeader::
604get_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 */
618get_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 */
680get_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 */
738get_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 */
748get_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 */
758get_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 */
780LRGBColor FltHeader::
781get_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 */
798has_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 */
807get_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 */
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 */
830add_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 */
849remove_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 */
857has_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 */
866get_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 */
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 */
889add_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 */
908remove_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 */
916has_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 */
925get_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 */
957remove_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 */
987get_num_eyepoints() const {
988 return 10;
989}
990
991/**
992 * Returns the nth eyepoint in the eyepoint/trackplane palette.
993 */
995get_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 */
1005get_num_trackplanes() const {
1006 return 10;
1007}
1008
1009/**
1010 * Returns the nth trackplane in the eyepoint/trackplane palette.
1011 */
1013get_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 */
1026int FltHeader::
1027update_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 */
1050bool FltHeader::
1051extract_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 */
1136bool FltHeader::
1137extract_ancillary(FltRecordReader &reader) {
1138 switch (reader.get_opcode()) {
1139 case FO_vertex_palette:
1140 // We're about to begin the vertex palette!
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 */
1183bool FltHeader::
1184build_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 */
1265FltError FltHeader::
1266write_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 */
1306bool FltHeader::
1307extract_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 */
1326bool FltHeader::
1327extract_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 */
1373bool FltHeader::
1374extract_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 */
1387bool FltHeader::
1388extract_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 */
1419bool FltHeader::
1420extract_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 */
1434bool FltHeader::
1435extract_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.
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 */
1451bool FltHeader::
1452extract_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 */
1465bool FltHeader::
1466extract_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 */
1501FltError FltHeader::
1502write_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 */
1531FltError FltHeader::
1532write_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 */
1581FltError FltHeader::
1582write_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 */
1635FltError FltHeader::
1636write_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 */
1655FltError FltHeader::
1656write_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 */
1675FltError FltHeader::
1676write_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:44
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.
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).
void add_material(FltMaterial *material)
Defines a new material.
DistanceUnit get_units() const
Returns the units indicated by the flt header, or DU_invalid if the units in the header are not under...
int get_num_color_shades() const
Returns the number of shades of brightness of each entry in the color palette.
int get_offset_by_vertex(FltVertex *vertex)
Returns the byte offset into the vertex palette associated with the given vertex pointer.
void add_instance(FltInstanceDefinition *instance)
Defines a new instance subtree.
int get_num_eyepoints() const
Returns the number of eyepoints in the eyepoint/trackplane palette.
FltMaterial * get_material(int material_index) const
Returns the material associated with the given index, or NULL if there is no such material.
bool has_texture(int texture_index) const
Returns true if a texture with the given index has been defined.
const Filename & get_flt_filename() const
Returns the directory in which the flt file is considered to reside.
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
FltEyepoint * get_eyepoint(int n)
Returns the nth eyepoint in the eyepoint/trackplane palette.
int get_flt_version() const
Returns the version number of the flt file as reported in the header, times 100.
bool has_light_source(int light_index) const
Returns true if a light source with the given index has been defined.
int get_num_color_entries() const
Returns the number of actual entries in the color palette.
void add_vertex(FltVertex *vertex)
Adds a new vertex to the end of the vertex palette.
AttrUpdate get_auto_attr_update() const
Returns the current setting of the auto_attr_update flag.
void set_auto_attr_update(AttrUpdate attr)
Controls whether texture .attr files are written automatically when write_flt() is called.
void set_flt_filename(const Filename &flt_filename)
Sets the filename–especially the directory part–in which the flt file is considered to reside.
void set_path_replace(PathReplace *path_replace)
Replaces the PathReplace object (which specifies how to mangle paths from the source to the destinati...
void add_texture(FltTexture *texture)
Defines a new texture.
void set_flt_version(int version)
Changes the version number of the flt file that will be reported in the header.
bool check_version() const
Verifies that the version number read from the header is an understood version number,...
std::string get_color_name(int color_index) const
Returns the name associated with the given color, if any.
FltError read_flt(Filename filename)
Opens the indicated filename for reading and attempts to read the complete Flt file.
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.
bool has_color_name(int color_index) const
Returns true if the given color is named, false otherwise.
LColor get_color(int color_index) const
Returns the four-component color corresponding to the given color index.
FltVertex * get_vertex(int n) const
Returns the nth vertex of the vertex palette.
LRGBColor get_rgb(int color_index) const
Returns the three-component color corresponding to the given color index, ignoring the alpha componen...
void remove_instance(int instance_index)
Removes a particular instance subtree from the pool, if it exists.
void clear_instances()
Removes all instance subtrees from the instance pool.
static int min_flt_version()
Returns the earliest flt version number that this codebase supports (times 100).
FltTrackplane * get_trackplane(int n)
Returns the nth trackplane in the eyepoint/trackplane palette.
void remove_light_source(int light_index)
Removes a particular light source from the light source palette, if it exists.
void add_light_source(FltLightSourceDefinition *light_source)
Defines a new light source.
void clear_textures()
Removes all textures from the palette.
FltInstanceDefinition * get_instance(int instance_index) const
Returns the instance subtree associated with the given index, or NULL if there is no such instance.
PathReplace * get_path_replace()
Returns a pointer to the PathReplace object associated with this converter.
void remove_material(int material_index)
Removes a particular material from the material palette, if it exists.
FltError write_flt(Filename filename)
Opens the indicated filename for writing and attempts to write the complete Flt file.
void set_eyepoint_trackplane_palette(bool flag)
Sets the state of the eyepoint/trackplane palette flag.
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...
int get_num_colors() const
Returns the total number of different colors in the color palette.
void clear_materials()
Removes all materials from the palette.
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.
void remove_texture(int texture_index)
Removes a particular texture from the texture palette, if it exists.
int get_num_trackplanes() const
Returns the number of trackplanes in the eyepoint/trackplane palette.
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...
void clear_vertices()
Removes all vertices from the vertex palette.
void clear_light_sources()
Removes all light sources from the palette.
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...
bool has_material(int material_index) const
Returns true if a material with the given index has been defined.
int get_num_vertices() const
Returns the number of vertices in the vertex palette.
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...
FltTexture * get_texture(int texture_index) const
Returns the texture associated with the given index, or NULL if there is no such texture.
bool has_instance(int instance_index) const
Returns true if a instance subtree with the given index has been defined.
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.
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
void add_ancillary(FltRecord *ancillary)
Adds a new unsupported ancillary record to the end of the list of ancillary records for this record.
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...
A single trackplane entry in the eyepoint/trackplane palette.
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...
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.