| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- /**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University. All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license. You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file fltRecord.cxx
- * @author drose
- * @date 2000-08-24
- */
- #include "fltRecord.h"
- #include "fltRecordReader.h"
- #include "fltRecordWriter.h"
- #include "fltHeader.h"
- #include "fltGroup.h"
- #include "fltObject.h"
- #include "fltFace.h"
- #include "fltCurve.h"
- #include "fltMesh.h"
- #include "fltLocalVertexPool.h"
- #include "fltMeshPrimitive.h"
- #include "fltVertexList.h"
- #include "fltLOD.h"
- #include "fltInstanceDefinition.h"
- #include "fltInstanceRef.h"
- #include "fltUnsupportedRecord.h"
- #include "fltExternalReference.h"
- #include "fltVectorRecord.h"
- #include "config_flt.h"
- #include "dcast.h"
- #include "indent.h"
- #include "datagramIterator.h"
- #include <assert.h>
- TypeHandle FltRecord::_type_handle;
- /**
- *
- */
- FltRecord::
- FltRecord(FltHeader *header) :
- _header(header)
- {
- }
- /**
- *
- */
- FltRecord::
- ~FltRecord() {
- }
- /**
- * Returns the number of child records of this record. This reflects the
- * normal scene graph hierarchy.
- */
- int FltRecord::
- get_num_children() const {
- return _children.size();
- }
- /**
- * Returns the nth child of this record.
- */
- FltRecord *FltRecord::
- get_child(int n) const {
- nassertr(n >= 0 && n < (int)_children.size(), nullptr);
- return _children[n];
- }
- /**
- * Removes all children from this record.
- */
- void FltRecord::
- clear_children() {
- _children.clear();
- }
- /**
- * Adds a new child to the end of the list of children for this record.
- */
- void FltRecord::
- add_child(FltRecord *child) {
- _children.push_back(child);
- }
- /**
- * Returns the number of subface records of this record. Normally, subfaces
- * will only be present on object records, although it is logically possible
- * for them to appear anywhere.
- */
- int FltRecord::
- get_num_subfaces() const {
- return _subfaces.size();
- }
- /**
- * Returns the nth subface of this record.
- */
- FltRecord *FltRecord::
- get_subface(int n) const {
- nassertr(n >= 0 && n < (int)_subfaces.size(), nullptr);
- return _subfaces[n];
- }
- /**
- * Removes all subfaces from this record.
- */
- void FltRecord::
- clear_subfaces() {
- _subfaces.clear();
- }
- /**
- * Adds a new subface to the end of the list of subfaces for this record.
- */
- void FltRecord::
- add_subface(FltRecord *subface) {
- _subfaces.push_back(subface);
- }
- /**
- * Returns the number of extension attribute records for this object. These
- * are auxiliary nodes, presumably of type FO_extension, that have some local
- * meaning to the object.
- */
- int FltRecord::
- get_num_extensions() const {
- return _extensions.size();
- }
- /**
- * Returns the nth extension of this record.
- */
- FltRecord *FltRecord::
- get_extension(int n) const {
- nassertr(n >= 0 && n < (int)_extensions.size(), nullptr);
- return _extensions[n];
- }
- /**
- * Removes all extensions from this record.
- */
- void FltRecord::
- clear_extensions() {
- _extensions.clear();
- }
- /**
- * Adds a new extension to the end of the list of extensions for this record.
- * This should be a record of type FO_extension.
- */
- void FltRecord::
- add_extension(FltRecord *extension) {
- _extensions.push_back(extension);
- }
- /**
- * Returns the number of unsupported ancillary records of this record. These
- * are ancillary records that appeared following this record in the flt file
- * but that aren't directly understood by the flt loader--normally, an
- * ancillary record is examined and decoded on the spot, and no pointer to it
- * is kept.
- */
- int FltRecord::
- get_num_ancillary() const {
- return _ancillary.size();
- }
- /**
- * Returns the nth unsupported ancillary record of this record. See
- * get_num_ancillary().
- */
- FltRecord *FltRecord::
- get_ancillary(int n) const {
- nassertr(n >= 0 && n < (int)_ancillary.size(), nullptr);
- return _ancillary[n];
- }
- /**
- * Removes all unsupported ancillary records from this record. See
- * get_num_ancillary().
- */
- void FltRecord::
- clear_ancillary() {
- _ancillary.clear();
- }
- /**
- * Adds a new unsupported ancillary record to the end of the list of ancillary
- * records for this record. This record will be written to the flt file
- * following this record, without attempting to understand what is in it.
- *
- * Normally, there is no reason to use this function; if the data stored in
- * the FltRecord requires one or more ancillary record, the appropriate
- * records will automatically be generated when the record is written. This
- * function is only required to output a record whose type is not supported by
- * the flt loader. But it would be better to extend the flt loader to know
- * about this new kind of data record.
- */
- void FltRecord::
- add_ancillary(FltRecord *ancillary) {
- _ancillary.push_back(ancillary);
- }
- /**
- * Returns true if this record has a nonempty comment, false otherwise.
- */
- bool FltRecord::
- has_comment() const {
- return !_comment.empty();
- }
- /**
- * Retrieves the comment for this record, or empty string if the record has no
- * comment.
- */
- const std::string &FltRecord::
- get_comment() const {
- return _comment;
- }
- /**
- * Removes the comment for this record.
- */
- void FltRecord::
- clear_comment() {
- _comment = "";
- }
- /**
- * Changes the comment for this record.
- */
- void FltRecord::
- set_comment(const std::string &comment) {
- _comment = comment;
- }
- /**
- * Checks that the iterator has no bytes left, as it should at the end of a
- * successfully read record. If there *are* remaining bytes, print a warning
- * message but otherwise don't worry about it.
- *
- * If we are attempting to read a flt file whose version is newer than the
- * newest this program understands, don't even print a warning message, since
- * this is exactly the sort of thing we expect.
- */
- void FltRecord::
- check_remaining_size(const DatagramIterator &di, const std::string &name) const {
- if (di.get_remaining_size() == 0) {
- return;
- }
- if (_header->get_flt_version() <= _header->max_flt_version()) {
- nout << "Warning! Ignoring extra " << di.get_remaining_size()
- << " bytes at the end of a ";
- if (name.empty()) {
- nout << get_type();
- } else {
- nout << name;
- }
- nout << " record.\n";
- }
- }
- /**
- * Walks the hierarchy at this record and below and copies the
- * _converted_filename record into the _orig_filename record, so the flt file
- * will be written out with the converted filename instead of what was
- * originally read in.
- */
- void FltRecord::
- apply_converted_filenames() {
- Records::const_iterator ci;
- for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
- (*ci)->apply_converted_filenames();
- }
- for (ci = _children.begin(); ci != _children.end(); ++ci) {
- (*ci)->apply_converted_filenames();
- }
- }
- /**
- * Writes a quick one-line description of the record, but not its children.
- * This is a human-readable description, primarily for debugging; to write a
- * flt file, use FltHeader::write_flt().
- */
- void FltRecord::
- output(std::ostream &out) const {
- out << get_type();
- }
- /**
- * Writes a multiple-line description of the record and all of its children.
- * This is a human-readable description, primarily for debugging; to write a
- * flt file, use FltHeader::write_flt().
- */
- void FltRecord::
- write(std::ostream &out, int indent_level) const {
- indent(out, indent_level) << *this;
- write_children(out, indent_level);
- }
- /**
- * Assuming the current write position has been left at the end of the last
- * line of the record description, writes out the list of children.
- */
- void FltRecord::
- write_children(std::ostream &out, int indent_level) const {
- if (!_ancillary.empty()) {
- out << " + " << _ancillary.size() << " ancillary";
- }
- if (!_extensions.empty()) {
- out << " + " << _extensions.size() << " extensions";
- }
- if (!_subfaces.empty()) {
- out << " [";
- Records::const_iterator ci;
- for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
- out << " " << *(*ci);
- }
- out << " ]";
- }
- if (!_children.empty()) {
- out << " {\n";
- Records::const_iterator ci;
- for (ci = _children.begin(); ci != _children.end(); ++ci) {
- (*ci)->write(out, indent_level + 2);
- }
- indent(out, indent_level) << "}\n";
- } else {
- out << "\n";
- }
- }
- /*
- virtual void write(ostream &out) const;
- virtual void build_record(Datagram &datagram) const;
- */
- /**
- * Returns true if the indicated opcode corresponds to an ancillary record
- * type, false otherwise. In general, this function is used to identify
- * ancillary records that are not presently supported by the FltReader; these
- * will be ignored. Normally, ancillary records will be detected and
- * processed by extract_ancillary().
- */
- bool FltRecord::
- is_ancillary(FltOpcode opcode) {
- switch (opcode) {
- case FO_comment:
- case FO_long_id:
- case FO_multitexture:
- case FO_uv_list:
- case FO_replicate:
- case FO_road_zone:
- case FO_transform_matrix:
- case FO_rotate_about_edge:
- case FO_translate:
- case FO_scale:
- case FO_rotate_about_point:
- case FO_rotate_and_scale:
- case FO_put:
- case FO_general_matrix:
- case FO_vector:
- case FO_bounding_box:
- case FO_bounding_sphere:
- case FO_bounding_cylinder:
- case FO_bv_center:
- case FO_bv_orientation:
- case FO_local_vertex_pool:
- case FO_cat_data:
- case FO_14_material_palette:
- case FO_vertex_palette:
- case FO_vertex_c:
- case FO_vertex_cn:
- case FO_vertex_cnu:
- case FO_vertex_cu:
- case FO_color_palette:
- case FO_name_table:
- case FO_15_material:
- case FO_texture:
- case FO_eyepoint_palette:
- case FO_light_definition:
- case FO_texture_map_palette:
- return true;
- case FO_header:
- case FO_mesh:
- case FO_mesh_primitive:
- case FO_group:
- case FO_object:
- case FO_face:
- case FO_light_point:
- case FO_dof:
- case FO_vertex_list:
- case FO_morph_list:
- case FO_bsp:
- case FO_external_ref:
- case FO_lod:
- case FO_sound:
- case FO_light_source:
- case FO_road_segment:
- case FO_road_construction:
- case FO_road_path:
- case FO_clip_region:
- case FO_text:
- case FO_switch:
- case FO_cat:
- case FO_extension:
- case FO_curve:
- return false;
- case FO_push:
- case FO_pop:
- case FO_push_face:
- case FO_pop_face:
- case FO_push_attribute:
- case FO_pop_attribute:
- case FO_push_extension:
- case FO_pop_extension:
- case FO_instance:
- case FO_instance_ref:
- return false;
- default:
- nout << "Don't know whether " << opcode << " is ancillary.\n";
- return false;
- }
- }
- /**
- * Creates a new FltRecord corresponding to the opcode. If the opcode is
- * unknown, creates a FltUnsupportedRecord.
- */
- FltRecord *FltRecord::
- create_new_record(FltOpcode opcode) const {
- switch (opcode) {
- case FO_group:
- return new FltGroup(_header);
- case FO_object:
- return new FltObject(_header);
- case FO_face:
- return new FltFace(_header);
- case FO_curve:
- return new FltCurve(_header);
- case FO_mesh:
- return new FltMesh(_header);
- case FO_local_vertex_pool:
- return new FltLocalVertexPool(_header);
- case FO_mesh_primitive:
- return new FltMeshPrimitive(_header);
- case FO_vertex_list:
- return new FltVertexList(_header);
- case FO_lod:
- return new FltLOD(_header);
- case FO_instance:
- return new FltInstanceDefinition(_header);
- case FO_instance_ref:
- return new FltInstanceRef(_header);
- case FO_external_ref:
- return new FltExternalReference(_header);
- case FO_vector:
- return new FltVectorRecord(_header);
- default:
- nout << "Ignoring unsupported record " << opcode << "\n";
- return new FltUnsupportedRecord(_header);
- }
- }
- /**
- * Extracts this record information from the current record presented in the
- * reader, then advances the reader and continues to read any children, if
- * present. On return, the reader is position on the next sibling record to
- * this record.
- *
- * Returns FE_ok if successful, otherwise on error.
- */
- FltError FltRecord::
- read_record_and_children(FltRecordReader &reader) {
- if (!extract_record(reader)) {
- nout << "Could not extract record for " << *this << "\n";
- assert(!flt_error_abort);
- return FE_invalid_record;
- }
- FltError result = reader.advance();
- if (result == FE_end_of_file) {
- return FE_ok;
- } else if (result != FE_ok) {
- return result;
- }
- while (true) {
- if (extract_ancillary(reader)) {
- // Ok, a known ancillary record. Fine.
- } else if (reader.get_opcode() == FO_push) {
- // A push begins a new list of children.
- result = reader.advance();
- if (result != FE_ok) {
- return result;
- }
- while (reader.get_opcode() != FO_pop) {
- PT(FltRecord) child = create_new_record(reader.get_opcode());
- FltError result = child->read_record_and_children(reader);
- if (result != FE_ok) {
- return result;
- }
- if (child->is_of_type(FltInstanceDefinition::get_class_type())) {
- // A special case for an instance definition. These shouldn't
- // appear in the hierarchy, but should instead be added directly to
- // the header.
- _header->add_instance(DCAST(FltInstanceDefinition, child));
- } else {
- add_child(child);
- }
- if (reader.eof() || reader.error()) {
- assert(!flt_error_abort);
- return FE_end_of_file;
- }
- }
- } else if (reader.get_opcode() == FO_push_face) {
- // A push subface begins a new list of subfaces.
- result = reader.advance();
- if (result != FE_ok) {
- return result;
- }
- while (reader.get_opcode() != FO_pop_face) {
- PT(FltRecord) subface = create_new_record(reader.get_opcode());
- FltError result = subface->read_record_and_children(reader);
- if (result != FE_ok) {
- return result;
- }
- add_subface(subface);
- if (reader.eof() || reader.error()) {
- assert(!flt_error_abort);
- return FE_end_of_file;
- }
- }
- } else if (reader.get_opcode() == FO_push_extension) {
- // A push extension begins a new list of extensions.
- result = reader.advance();
- if (result != FE_ok) {
- return result;
- }
- while (reader.get_opcode() != FO_pop_extension) {
- PT(FltRecord) extension = create_new_record(reader.get_opcode());
- FltError result = extension->read_record_and_children(reader);
- if (result != FE_ok) {
- return result;
- }
- add_extension(extension);
- if (reader.eof() || reader.error()) {
- assert(!flt_error_abort);
- return FE_end_of_file;
- }
- }
- } else if (is_ancillary(reader.get_opcode())) {
- // An unsupported ancillary record. Skip it.
- PT(FltRecord) ancillary = create_new_record(reader.get_opcode());
- ancillary->extract_record(reader);
- _ancillary.push_back(ancillary);
- } else {
- // None of the above: we're done.
- return FE_ok;
- }
- // Skip to the next record. If that's the end, fine.
- result = reader.advance(true);
- if (reader.eof() || result != FE_ok) {
- return result;
- }
- }
- }
- /**
- * Fills in the information in this record based on the information given in
- * the indicated datagram, whose opcode has already been read. Returns true
- * on success, false if the datagram is invalid.
- */
- bool FltRecord::
- extract_record(FltRecordReader &) {
- return true;
- }
- /**
- * Checks whether the given record, which follows this record sequentially in
- * the file, is an ancillary record of this record. If it is, extracts the
- * relevant information and returns true; otherwise, leaves it alone and
- * returns false.
- */
- bool FltRecord::
- extract_ancillary(FltRecordReader &reader) {
- if (reader.get_opcode() == FO_comment) {
- DatagramIterator &di = reader.get_iterator();
- _comment = di.get_fixed_string(di.get_remaining_size());
- return true;
- }
- return false;
- }
- /**
- * Writes this record out to the flt file, along with all of its ancillary
- * records and children records. Returns FE_ok on success, or something else
- * on error.
- */
- FltError FltRecord::
- write_record_and_children(FltRecordWriter &writer) const {
- // First, write the record.
- if (!build_record(writer)) {
- assert(!flt_error_abort);
- return FE_bad_data;
- }
- FltError result = writer.advance();
- if (result != FE_ok) {
- return result;
- }
- // Then the ancillary data.
- result = write_ancillary(writer);
- if (result != FE_ok) {
- return result;
- }
- Records::const_iterator ci;
- for (ci = _ancillary.begin(); ci != _ancillary.end(); ++ci) {
- if (!(*ci)->build_record(writer)) {
- assert(!flt_error_abort);
- return FE_bad_data;
- }
- result = writer.advance();
- if (result != FE_ok) {
- return result;
- }
- }
- // Any extensions?
- if (!_extensions.empty()) {
- result = writer.write_record(FO_push_face);
- if (result != FE_ok) {
- return result;
- }
- for (ci = _extensions.begin(); ci != _extensions.end(); ++ci) {
- (*ci)->write_record_and_children(writer);
- }
- result = writer.write_record(FO_pop_face);
- if (result != FE_ok) {
- return result;
- }
- }
- // Finally, write all the children.
- if (!_children.empty()) {
- result = writer.write_record(FO_push);
- if (result != FE_ok) {
- return result;
- }
- for (ci = _children.begin(); ci != _children.end(); ++ci) {
- (*ci)->write_record_and_children(writer);
- }
- result = writer.write_record(FO_pop);
- if (result != FE_ok) {
- return result;
- }
- }
- // We must write subfaces *after* the list of children, or Creator will
- // crash trying to load the file.
- if (!_subfaces.empty()) {
- result = writer.write_record(FO_push_face);
- if (result != FE_ok) {
- return result;
- }
- for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
- (*ci)->write_record_and_children(writer);
- }
- result = writer.write_record(FO_pop_face);
- if (result != FE_ok) {
- return result;
- }
- }
- return FE_ok;
- }
- /**
- * Fills up the current record on the FltRecordWriter with data for this
- * record, but does not advance the writer. Returns true on success, false if
- * there is some error.
- */
- bool FltRecord::
- build_record(FltRecordWriter &) const {
- return true;
- }
- /**
- * Writes whatever ancillary records are required for this record. Returns
- * FE_ok on success, or something else if there is some error.
- */
- FltError FltRecord::
- write_ancillary(FltRecordWriter &writer) const {
- if (!_comment.empty()) {
- Datagram dc(_comment.data(), _comment.size());
- FltError result = writer.write_record(FO_comment, dc);
- if (result != FE_ok) {
- return result;
- }
- }
- return FE_ok;
- }
|