فهرست منبع

*** empty log message ***

David Rose 25 سال پیش
والد
کامیت
6be1258029

+ 33 - 37
panda/src/egg/eggGroup.cxx

@@ -6,14 +6,12 @@
 #include "eggGroup.h"
 #include "eggGroup.h"
 #include "eggMiscFuncs.h"
 #include "eggMiscFuncs.h"
 #include "eggVertexPool.h"
 #include "eggVertexPool.h"
+#include "lexerDefs.h"
 
 
 #include <indent.h>
 #include <indent.h>
 #include <string_utils.h>
 #include <string_utils.h>
 #include <lmatrix.h>
 #include <lmatrix.h>
 
 
-extern int eggyyparse(void);
-#include "parserDefs.h"
-#include "lexerDefs.h"
 
 
 TypeHandle EggGroup::_type_handle;
 TypeHandle EggGroup::_type_handle;
 
 
@@ -356,26 +354,6 @@ determine_bin() {
   return EggGroupNode::determine_bin();
   return EggGroupNode::determine_bin();
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggGroup::parse_egg
-//       Access: Public
-//  Description: Parses the egg syntax given in the indicate string as
-//               if it had been read from the egg file within the
-//               <Group> { ... } definition.  Updates the EggGroup
-//               accordingly.  Returns true if successful, false if
-//               there was some parse error.
-////////////////////////////////////////////////////////////////////
-bool EggGroup::
-parse_egg(const string &egg_syntax) {
-  istringstream in(egg_syntax);
-  egg_init_parser(in, "", this, this);
-  egg_start_group_body();
-  eggyyparse();
-  egg_cleanup_parser();
-
-  return (egg_error_count() == 0);
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::ref_vertex
 //     Function: EggGroup::ref_vertex
 //       Access: Public
 //       Access: Public
@@ -725,6 +703,21 @@ write_vertex_ref(ostream &out, int indent_level) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::egg_start_parse_body
+//       Access: Protected, Virtual
+//  Description: This function is called within parse_egg().  It
+//               should call the appropriate function on the lexer to
+//               initialize the parser into the state associated with
+//               this object.  If the object cannot be parsed into
+//               directly, it should return false.
+////////////////////////////////////////////////////////////////////
+bool EggGroup::
+egg_start_parse_body() {
+  egg_start_group_body();
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::adjust_under
 //     Function: EggGroup::adjust_under
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
@@ -741,6 +734,23 @@ adjust_under() {
   bool is_billboard_instance = 
   bool is_billboard_instance = 
     (get_billboard_type() != BT_none && !has_billboard_center());
     (get_billboard_type() != BT_none && !has_billboard_center());
 
 
+  // If we have our own transform, it carries forward.
+
+  // As of 4/18/01, this now also affects the local_coord flag, below.
+  // This means that a <Transform> entry within an <Instance> node
+  // transforms the instance itself.
+  if (has_transform()) {
+    _under_flags |= UF_under_transform;
+
+    // Our own transform also affects our node frame.
+    _node_frame = 
+      new MatrixFrame(get_transform() * get_node_frame());
+    _node_frame_inv =
+      new MatrixFrame(invert(get_node_frame()));
+    _vertex_to_node =
+      new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
+  }
+
   if (get_group_type() == GT_instance || is_billboard_instance) {
   if (get_group_type() == GT_instance || is_billboard_instance) {
     _under_flags |= UF_under_instance;
     _under_flags |= UF_under_instance;
     if (_under_flags & UF_under_transform) {
     if (_under_flags & UF_under_transform) {
@@ -757,20 +767,6 @@ adjust_under() {
     _vertex_frame_inv = _node_frame_inv;
     _vertex_frame_inv = _node_frame_inv;
     _vertex_to_node = NULL;
     _vertex_to_node = NULL;
   }
   }
-
-  // If we have our own transform, it carries forward, but it doesn't
-  // have any effect on the local_coord flag, above.
-  if (has_transform()) {
-    _under_flags |= UF_under_transform;
-
-    // Our own transform also affects our node frame.
-    _node_frame = 
-      new MatrixFrame(get_transform() * get_node_frame());
-    _node_frame_inv =
-      new MatrixFrame(invert(get_node_frame()));
-    _vertex_to_node =
-      new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 2
panda/src/egg/eggGroup.h

@@ -76,7 +76,6 @@ public:
   ~EggGroup();
   ~EggGroup();
 
 
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
-  bool parse_egg(const string &egg_syntax);
 
 
   virtual EggRenderMode *determine_alpha_mode();
   virtual EggRenderMode *determine_alpha_mode();
   virtual EggRenderMode *determine_depth_write_mode();
   virtual EggRenderMode *determine_depth_write_mode();
@@ -186,8 +185,8 @@ public:
 
 
 protected:
 protected:
   void write_vertex_ref(ostream &out, int indent_level) const;
   void write_vertex_ref(ostream &out, int indent_level) const;
+  virtual bool egg_start_parse_body();
   virtual void adjust_under();
   virtual void adjust_under();
-
   virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
   virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
 			   CoordinateSystem to_cs);
 			   CoordinateSystem to_cs);
   virtual void r_flatten_transforms();
   virtual void r_flatten_transforms();

+ 50 - 0
panda/src/egg/eggNode.cxx

@@ -10,6 +10,10 @@
 
 
 #include <algorithm>
 #include <algorithm>
 
 
+extern int eggyyparse(void);
+#include "parserDefs.h"
+#include "lexerDefs.h"
+
 TypeHandle EggNode::_type_handle;
 TypeHandle EggNode::_type_handle;
 
 
 
 
@@ -117,6 +121,38 @@ determine_bin() {
   return _parent->determine_bin();
   return _parent->determine_bin();
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::parse_egg
+//       Access: Public
+//  Description: Parses the egg syntax given in the indicate string as
+//               if it had been read from the egg file within this
+//               object's definition.  Updates the object accordingly.
+//               Returns true if successful, false if there was some
+//               parse error or if the object does not support this
+//               functionality.
+////////////////////////////////////////////////////////////////////
+bool EggNode::
+parse_egg(const string &egg_syntax) {
+  EggGroupNode *group = get_parent();
+  if (is_of_type(EggGroupNode::get_class_type())) {
+    DCAST_INTO_R(group, this, false);
+  }
+
+  istringstream in(egg_syntax);
+  egg_init_parser(in, "", this, group);
+
+  if (!egg_start_parse_body()) {
+    egg_cleanup_parser();
+    return false;
+  }
+
+  eggyyparse();
+  egg_cleanup_parser();
+
+  return (egg_error_count() == 0);
+}
+
 #ifndef NDEBUG
 #ifndef NDEBUG
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -157,6 +193,20 @@ test_under_integrity() const {
 #endif  // NDEBUG
 #endif  // NDEBUG
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::egg_start_parse_body
+//       Access: Protected, Virtual
+//  Description: This function is called within parse_egg().  It
+//               should call the appropriate function on the lexer to
+//               initialize the parser into the state associated with
+//               this object.  If the object cannot be parsed into
+//               directly, it should return false.
+////////////////////////////////////////////////////////////////////
+bool EggNode::
+egg_start_parse_body() {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggNode::update_under
 //     Function: EggNode::update_under
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 3 - 0
panda/src/egg/eggNode.h

@@ -56,6 +56,7 @@ public:
   virtual EggRenderMode *determine_bin();
   virtual EggRenderMode *determine_bin();
 
 
   virtual void write(ostream &out, int indent_level) const=0;
   virtual void write(ostream &out, int indent_level) const=0;
+  bool parse_egg(const string &egg_syntax);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   void test_under_integrity() const;
   void test_under_integrity() const;
@@ -71,6 +72,8 @@ protected:
     UF_local_coord     = 0x004,
     UF_local_coord     = 0x004,
   };
   };
 
 
+  virtual bool egg_start_parse_body();
+
   virtual void update_under(int depth_offset);
   virtual void update_under(int depth_offset);
   virtual void adjust_under();
   virtual void adjust_under();
 
 

+ 9 - 0
panda/src/egg/eggObject.cxx

@@ -7,3 +7,12 @@
 
 
 TypeHandle EggObject::_type_handle;
 TypeHandle EggObject::_type_handle;
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggObject::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggObject::
+~EggObject() { 
+}

+ 2 - 1
panda/src/egg/eggObject.h

@@ -25,8 +25,9 @@ public:
   INLINE EggObject(const EggObject &copy);
   INLINE EggObject(const EggObject &copy);
   INLINE EggObject &operator = (const EggObject &copy);
   INLINE EggObject &operator = (const EggObject &copy);
 
 
-  virtual ~EggObject() { }
+  virtual ~EggObject();
 
 
+public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
   }
   }

+ 16 - 0
panda/src/egg/eggPrimitive.cxx

@@ -7,6 +7,7 @@
 #include "eggVertexPool.h"
 #include "eggVertexPool.h"
 #include "eggMiscFuncs.h"
 #include "eggMiscFuncs.h"
 #include "eggTextureCollection.h"
 #include "eggTextureCollection.h"
+#include "lexerDefs.h"
 
 
 #include <indent.h>
 #include <indent.h>
 #include <vector_int.h>
 #include <vector_int.h>
@@ -505,6 +506,21 @@ write_body(ostream &out, int indent_level) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggPrimitive::egg_start_parse_body
+//       Access: Protected, Virtual
+//  Description: This function is called within parse_egg().  It
+//               should call the appropriate function on the lexer to
+//               initialize the parser into the state associated with
+//               this object.  If the object cannot be parsed into
+//               directly, it should return false.
+////////////////////////////////////////////////////////////////////
+bool EggPrimitive::
+egg_start_parse_body() {
+  egg_start_primitive_body();
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggPrimitive::r_transform
 //     Function: EggPrimitive::r_transform
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 2 - 0
panda/src/egg/eggPrimitive.h

@@ -15,6 +15,7 @@
 #include "eggMaterial.h"
 #include "eggMaterial.h"
 #include "eggRenderMode.h"
 #include "eggRenderMode.h"
 #include "vector_PT_EggVertex.h"
 #include "vector_PT_EggVertex.h"
+
 #include <pointerTo.h>
 #include <pointerTo.h>
 #include <vector>
 #include <vector>
 
 
@@ -143,6 +144,7 @@ private:
 protected:
 protected:
   void write_body(ostream &out, int indent_level) const;
   void write_body(ostream &out, int indent_level) const;
 
 
+  virtual bool egg_start_parse_body();
   virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
   virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
 			   CoordinateSystem to_cs);
 			   CoordinateSystem to_cs);
   virtual void r_flatten_transforms();
   virtual void r_flatten_transforms();

+ 16 - 0
panda/src/egg/eggTexture.cxx

@@ -5,6 +5,7 @@
 
 
 #include "eggTexture.h"
 #include "eggTexture.h"
 #include "eggMiscFuncs.h"
 #include "eggMiscFuncs.h"
+#include "lexerDefs.h"
 
 
 #include <indent.h>
 #include <indent.h>
 #include <string_utils.h>
 #include <string_utils.h>
@@ -490,6 +491,21 @@ string_env_type(const string &string) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::egg_start_parse_body
+//       Access: Protected, Virtual
+//  Description: This function is called within parse_egg().  It
+//               should call the appropriate function on the lexer to
+//               initialize the parser into the state associated with
+//               this object.  If the object cannot be parsed into
+//               directly, it should return false.
+////////////////////////////////////////////////////////////////////
+bool EggTexture::
+egg_start_parse_body() {
+  egg_start_texture_body();
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Format output operator
 //     Function: Format output operator
 //  Description: 
 //  Description: 

+ 3 - 0
panda/src/egg/eggTexture.h

@@ -124,6 +124,9 @@ public:
   static FilterType string_filter_type(const string &string);
   static FilterType string_filter_type(const string &string);
   static EnvType string_env_type(const string &string);
   static EnvType string_env_type(const string &string);
 
 
+protected:
+  virtual bool egg_start_parse_body();
+
 private:
 private:
   enum Flags {
   enum Flags {
     F_has_transform          = 0x0001,
     F_has_transform          = 0x0001,

+ 13 - 2
panda/src/egg/lexer.lxx

@@ -73,6 +73,16 @@ egg_start_group_body() {
   initial_token = START_GROUP_BODY;
   initial_token = START_GROUP_BODY;
 }
 }
 
 
+void
+egg_start_texture_body() {
+  initial_token = START_TEXTURE_BODY;
+}
+
+void
+egg_start_primitive_body() {
+  initial_token = START_PRIMITIVE_BODY;
+}
+
 int
 int
 egg_error_count() {
 egg_error_count() {
   return error_count;
   return error_count;
@@ -159,8 +169,9 @@ input_chars(char *buffer, int &result, int max_size) {
       // from the stream, copy it into the current_line array.  This
       // from the stream, copy it into the current_line array.  This
       // is because the \n.* rule below, which fills current_line
       // is because the \n.* rule below, which fills current_line
       // normally, doesn't catch the first line.
       // normally, doesn't catch the first line.
-      strncpy(current_line, yytext, max_error_width);
-      current_line[max_error_width] = '\0';
+      int length = min(max_error_width, result);
+      strncpy(current_line, buffer, length);
+      current_line[length] = '\0';
       line_number++;
       line_number++;
       col_number = 0;
       col_number = 0;
 
 

+ 2 - 0
panda/src/egg/lexerDefs.h

@@ -14,6 +14,8 @@
 
 
 void egg_init_lexer(istream &in, const string &filename);
 void egg_init_lexer(istream &in, const string &filename);
 void egg_start_group_body();
 void egg_start_group_body();
+void egg_start_texture_body();
+void egg_start_primitive_body();
 int egg_error_count();
 int egg_error_count();
 int egg_warning_count();
 int egg_warning_count();
 
 

+ 4 - 0
panda/src/egg/parser.yxx

@@ -136,6 +136,8 @@ egg_cleanup_parser() {
    of the input stream. */
    of the input stream. */
 %token START_EGG
 %token START_EGG
 %token START_GROUP_BODY
 %token START_GROUP_BODY
+%token START_TEXTURE_BODY
+%token START_PRIMITIVE_BODY
 
 
 %type <_egg> node
 %type <_egg> node
 %type <_egg> coordsystem
 %type <_egg> coordsystem
@@ -178,6 +180,8 @@ egg_cleanup_parser() {
 grammar:
 grammar:
 	START_EGG egg
 	START_EGG egg
 	| START_GROUP_BODY group_body
 	| START_GROUP_BODY group_body
+	| START_TEXTURE_BODY texture_body
+	| START_PRIMITIVE_BODY primitive_body
 	;
 	;
 
 
 /*
 /*

+ 4 - 2
pandatool/src/fltegg/Sources.pp

@@ -8,9 +8,11 @@
     m
     m
 
 
   #define SOURCES \
   #define SOURCES \
-    fltToEggConverter.I fltToEggConverter.cxx fltToEggConverter.h
+    fltToEggConverter.I fltToEggConverter.cxx fltToEggConverter.h \
+    fltToEggLevelState.I fltToEggLevelState.cxx fltToEggLevelState.h
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
-    fltToEggConverter.I fltToEggConverter.h
+    fltToEggConverter.I fltToEggConverter.h \
+    fltToEggLevelState.I fltToEggLevelState.h
 
 
 #end ss_lib_target
 #end ss_lib_target

+ 190 - 51
pandatool/src/fltegg/fltToEggConverter.cxx

@@ -14,6 +14,7 @@
 #include <fltFace.h>
 #include <fltFace.h>
 #include <fltVertex.h>
 #include <fltVertex.h>
 #include <fltVertexList.h>
 #include <fltVertexList.h>
+#include <fltExternalReference.h>
 #include <eggGroup.h>
 #include <eggGroup.h>
 #include <eggSwitchCondition.h>
 #include <eggSwitchCondition.h>
 #include <eggPrimitive.h>
 #include <eggPrimitive.h>
@@ -21,6 +22,7 @@
 #include <eggPoint.h>
 #include <eggPoint.h>
 #include <eggVertex.h>
 #include <eggVertex.h>
 #include <eggVertexPool.h>
 #include <eggVertexPool.h>
+#include <eggExternalReference.h>
 #include <string_utils.h>
 #include <string_utils.h>
 
 
 
 
@@ -41,8 +43,9 @@ FltToEggConverter(EggData &egg_data) : _egg_data(egg_data) {
 //  Description: Returns a newly-allocated EggData structure
 //  Description: Returns a newly-allocated EggData structure
 //               corresponding to the indicated flt structure.
 //               corresponding to the indicated flt structure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void FltToEggConverter::
+bool FltToEggConverter::
 convert_flt(const FltHeader *flt_header) {
 convert_flt(const FltHeader *flt_header) {
+  _error = false;
   _flt_header = flt_header;
   _flt_header = flt_header;
   
   
   if (_input_units == DU_invalid) {
   if (_input_units == DU_invalid) {
@@ -79,13 +82,17 @@ convert_flt(const FltHeader *flt_header) {
   // they're assigned to (for instance, to apply a transparency or
   // they're assigned to (for instance, to apply a transparency or
   // something).
   // something).
 
 
-  convert_record(_flt_header, (FltObject *)NULL, &_egg_data);
+  FltToEggLevelState state;
+  state._egg_parent = &_egg_data;
+  convert_record(_flt_header, state);
 
 
   if (_main_egg_vpool->empty()) {
   if (_main_egg_vpool->empty()) {
     // If we didn't get any global vertices, remove the vertex pool
     // If we didn't get any global vertices, remove the vertex pool
     // just for cleanliness.
     // just for cleanliness.
     _egg_data.remove_child(_main_egg_vpool);
     _egg_data.remove_child(_main_egg_vpool);
   }
   }
+
+  return !_error;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -94,34 +101,36 @@ convert_flt(const FltHeader *flt_header) {
 //  Description: Converts the record and all of its children.
 //  Description: Converts the record and all of its children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_record(const FltRecord *flt_record, const FltObject *flt_object,
-	       EggGroupNode *egg_group) {
+convert_record(const FltRecord *flt_record, FltToEggLevelState &state) {
   int num_children = flt_record->get_num_children();
   int num_children = flt_record->get_num_children();
 
 
   for (int i = 0; i < num_children; i++) {
   for (int i = 0; i < num_children; i++) {
     const FltRecord *child = flt_record->get_child(i);
     const FltRecord *child = flt_record->get_child(i);
 
 
     if (child->is_of_type(FltLOD::get_class_type())) {
     if (child->is_of_type(FltLOD::get_class_type())) {
-      convert_lod(DCAST(FltLOD, child), flt_object, egg_group);
+      convert_lod(DCAST(FltLOD, child), state);
 
 
     } else if (child->is_of_type(FltGroup::get_class_type())) {
     } else if (child->is_of_type(FltGroup::get_class_type())) {
-      convert_group(DCAST(FltGroup, child), flt_object, egg_group);
+      convert_group(DCAST(FltGroup, child), state);
 
 
     } else if (child->is_of_type(FltObject::get_class_type())) {
     } else if (child->is_of_type(FltObject::get_class_type())) {
-      convert_object(DCAST(FltObject, child), flt_object, egg_group);
+      convert_object(DCAST(FltObject, child), state);
 
 
     } else if (child->is_of_type(FltFace::get_class_type())) {
     } else if (child->is_of_type(FltFace::get_class_type())) {
-      convert_face(DCAST(FltFace, child), flt_object, egg_group);
+      convert_face(DCAST(FltFace, child), state);
+
+    } else if (child->is_of_type(FltExternalReference::get_class_type())) {
+      convert_ext_ref(DCAST(FltExternalReference, child), state);
 
 
       // Fallbacks.
       // Fallbacks.
     } else if (child->is_of_type(FltBeadID::get_class_type())) {
     } else if (child->is_of_type(FltBeadID::get_class_type())) {
-      convert_bead_id(DCAST(FltBeadID, child), flt_object, egg_group);
+      convert_bead_id(DCAST(FltBeadID, child), state);
 
 
     } else if (child->is_of_type(FltBead::get_class_type())) {
     } else if (child->is_of_type(FltBead::get_class_type())) {
-      convert_bead(DCAST(FltBead, child), flt_object, egg_group);
+      convert_bead(DCAST(FltBead, child), state);
 
 
     } else {
     } else {
-      convert_record(child, flt_object, egg_group);
+      convert_record(child, state);
     }
     }
   }
   }
 }
 }
@@ -132,10 +141,9 @@ convert_record(const FltRecord *flt_record, const FltObject *flt_object,
 //  Description: Converts the LOD bead and all of its children.
 //  Description: Converts the LOD bead and all of its children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
-	    EggGroupNode *egg_parent) {
+convert_lod(const FltLOD *flt_lod, FltToEggLevelState &state) {
   EggGroup *egg_group = new EggGroup(flt_lod->get_id());
   EggGroup *egg_group = new EggGroup(flt_lod->get_id());
-  egg_parent->add_child(egg_group);
+  state._egg_parent->add_child(egg_group);
 
 
   EggSwitchConditionDistance lod
   EggSwitchConditionDistance lod
     (flt_lod->_switch_in, flt_lod->_switch_out,
     (flt_lod->_switch_in, flt_lod->_switch_out,
@@ -143,7 +151,12 @@ convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
      flt_lod->_transition_range);
      flt_lod->_transition_range);
   egg_group->set_lod(lod);
   egg_group->set_lod(lod);
 
 
-  convert_record(flt_lod, flt_object, egg_group);
+  set_transform(flt_lod, egg_group);
+  parse_comment(flt_lod, egg_group);
+
+  FltToEggLevelState next_state(state);
+  next_state._egg_parent = egg_group;
+  convert_record(flt_lod, next_state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -152,10 +165,9 @@ convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
 //  Description: Converts the group and all of its children.
 //  Description: Converts the group and all of its children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_group(const FltGroup *flt_group, const FltObject *flt_object,
-	      EggGroupNode *egg_parent) {
+convert_group(const FltGroup *flt_group, FltToEggLevelState &state) {
   EggGroup *egg_group = new EggGroup(flt_group->get_id());
   EggGroup *egg_group = new EggGroup(flt_group->get_id());
-  egg_parent->add_child(egg_group);
+  state._egg_parent->add_child(egg_group);
 
 
   if ((flt_group->_flags & FltGroup::F_forward_animation) != 0) {
   if ((flt_group->_flags & FltGroup::F_forward_animation) != 0) {
     // It's a sequence animation.
     // It's a sequence animation.
@@ -163,13 +175,14 @@ convert_group(const FltGroup *flt_group, const FltObject *flt_object,
     egg_group->set_switch_fps(24.0);
     egg_group->set_switch_fps(24.0);
   }
   }
 
 
-  if (flt_group->has_transform()) {
-    egg_group->set_transform(flt_group->get_transform());
-  }
+  set_transform(flt_group, egg_group);
+  parse_comment(flt_group, egg_group);
 
 
   ///*** replicate count.
   ///*** replicate count.
 
 
-  convert_record(flt_group, flt_object, egg_group);
+  FltToEggLevelState next_state(state);
+  next_state._egg_parent = egg_group;
+  convert_record(flt_group, next_state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -178,16 +191,17 @@ convert_group(const FltGroup *flt_group, const FltObject *flt_object,
 //  Description: Converts the object and all of its children.
 //  Description: Converts the object and all of its children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_object(const FltObject *flt_object, const FltObject *,
-	       EggGroupNode *egg_parent) {
+convert_object(const FltObject *flt_object, FltToEggLevelState &state) {
   EggGroup *egg_group = new EggGroup(flt_object->get_id());
   EggGroup *egg_group = new EggGroup(flt_object->get_id());
-  egg_parent->add_child(egg_group);
+  state._egg_parent->add_child(egg_group);
 
 
-  if (flt_object->has_transform()) {
-    egg_group->set_transform(flt_object->get_transform());
-  }
+  set_transform(flt_object, egg_group);
+  parse_comment(flt_object, egg_group);
 
 
-  convert_record(flt_object, flt_object, egg_group);
+  FltToEggLevelState next_state(state);
+  next_state._flt_object = flt_object;
+  next_state._egg_parent = egg_group;
+  convert_record(flt_object, next_state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -197,16 +211,16 @@ convert_object(const FltObject *flt_object, const FltObject *,
 //               children.
 //               children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_bead_id(const FltBeadID *flt_bead, const FltObject *flt_object,
-		EggGroupNode *egg_parent) {
+convert_bead_id(const FltBeadID *flt_bead, FltToEggLevelState &state) {
   EggGroup *egg_group = new EggGroup(flt_bead->get_id());
   EggGroup *egg_group = new EggGroup(flt_bead->get_id());
-  egg_parent->add_child(egg_group);
+  state._egg_parent->add_child(egg_group);
 
 
-  if (flt_bead->has_transform()) {
-    egg_group->set_transform(flt_bead->get_transform());
-  }
+  set_transform(flt_bead, egg_group);
+  parse_comment(flt_bead, egg_group);
 
 
-  convert_record(flt_bead, flt_object, egg_group);
+  FltToEggLevelState next_state(state);
+  next_state._egg_parent = egg_group;
+  convert_record(flt_bead, next_state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -216,16 +230,16 @@ convert_bead_id(const FltBeadID *flt_bead, const FltObject *flt_object,
 //               children.
 //               children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_bead(const FltBead *flt_bead, const FltObject *flt_object,
-	     EggGroupNode *egg_parent) {
+convert_bead(const FltBead *flt_bead, FltToEggLevelState &state) {
   EggGroup *egg_group = new EggGroup;
   EggGroup *egg_group = new EggGroup;
-  egg_parent->add_child(egg_group);
+  state._egg_parent->add_child(egg_group);
 
 
-  if (flt_bead->has_transform()) {
-    egg_group->set_transform(flt_bead->get_transform());
-  }
+  set_transform(flt_bead, egg_group);
+  parse_comment(flt_bead, "anonymous", egg_group);
 
 
-  convert_record(flt_bead, flt_object, egg_group);
+  FltToEggLevelState next_state(state);
+  next_state._egg_parent = egg_group;
+  convert_record(flt_bead, next_state);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -234,8 +248,7 @@ convert_bead(const FltBead *flt_bead, const FltObject *flt_object,
 //  Description: Converts the face and all of its children.
 //  Description: Converts the face and all of its children.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-convert_face(const FltFace *flt_face, const FltObject *flt_object,
-	     EggGroupNode *egg_parent) {
+convert_face(const FltFace *flt_face, FltToEggLevelState &state) {
   bool is_light;
   bool is_light;
   switch (flt_face->_draw_type) {
   switch (flt_face->_draw_type) {
   case FltGeometry::DT_omni_light:
   case FltGeometry::DT_omni_light:
@@ -248,15 +261,13 @@ convert_face(const FltFace *flt_face, const FltObject *flt_object,
     is_light = false;
     is_light = false;
   }
   }
 
 
-  EggPrimitive *egg_prim;
+  PT(EggPrimitive) egg_prim;
   if (is_light) {
   if (is_light) {
     egg_prim = new EggPoint;
     egg_prim = new EggPoint;
   } else {
   } else {
     egg_prim = new EggPolygon;
     egg_prim = new EggPolygon;
   }
   }
 
 
-  egg_parent->add_child(egg_prim);
-
   // Collect the vertices for this primitive.
   // Collect the vertices for this primitive.
   vector< PT(EggVertex) > vertices;
   vector< PT(EggVertex) > vertices;
 
 
@@ -277,7 +288,25 @@ convert_face(const FltFace *flt_face, const FltObject *flt_object,
     }
     }
   }
   }
 
 
-  setup_geometry(flt_face, flt_object, egg_prim, _main_egg_vpool, vertices);
+  setup_geometry(flt_face, state, egg_prim, _main_egg_vpool, vertices);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_ext_ref
+//       Access: Private
+//  Description: Converts the external reference node.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state) {
+  // Get a group node to put the reference into.
+  EggGroupNode *egg_parent = 
+    state.get_synthetic_group("", flt_ext->get_transform());
+
+  Filename filename = flt_ext->get_ref_filename();
+  filename.set_extension("egg");
+
+  EggExternalReference *egg_ref = new EggExternalReference("", filename);
+  egg_parent->add_child(egg_ref);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -286,12 +315,20 @@ convert_face(const FltFace *flt_face, const FltObject *flt_object,
 //  Description: Applies the state indicated in the FltGeometry record
 //  Description: Applies the state indicated in the FltGeometry record
 //               to the indicated EggPrimitive and all of its
 //               to the indicated EggPrimitive and all of its
 //               indicated vertices, and then officially adds the
 //               indicated vertices, and then officially adds the
-//               vertices to the vertex pool and to the primitive.
+//               vertices to the vertex pool and to the primitive, and
+//               adds the primitive to its appropriate parent.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FltToEggConverter::
 void FltToEggConverter::
-setup_geometry(const FltGeometry *flt_geom, const FltObject *,
+setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
 	       EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
 	       EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
 	       const FltToEggConverter::EggVertices &vertices) {
 	       const FltToEggConverter::EggVertices &vertices) {
+
+  // Add the primitive to its appropriate parent.
+  EggGroupNode *egg_parent = 
+    state.get_synthetic_group(flt_geom->get_id(), flt_geom->get_transform());
+  egg_parent->add_child(egg_prim);
+
+  // Now examine the vertices.
   EggVertices::const_iterator vi;
   EggVertices::const_iterator vi;
 
 
   if (flt_geom->has_color()) {
   if (flt_geom->has_color()) {
@@ -364,10 +401,112 @@ setup_geometry(const FltGeometry *flt_geom, const FltObject *,
     }
     }
   }
   }
 
 
+  if (flt_geom->_draw_type == FltGeometry::DT_solid_no_backface) {
+    // A double-sided polygon.
+    egg_prim->set_bface_flag(true);
+  }
+
   for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
   for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
     EggVertex *egg_vertex = egg_vpool->create_unique_vertex(*(*vi));
     EggVertex *egg_vertex = egg_vpool->create_unique_vertex(*(*vi));
     egg_prim->add_vertex(egg_vertex);
     egg_prim->add_vertex(egg_vertex);
   }
   }
+
+  parse_comment(flt_geom, egg_prim);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::set_transform
+//       Access: Private
+//  Description: Sets up the group to reflect the transform indicated
+//               by the given record, if any.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
+  if (flt_bead->has_transform()) {
+    egg_group->set_transform(flt_bead->get_transform());
+    egg_group->set_group_type(EggGroup::GT_instance);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::parse_comment
+//       Access: Private
+//  Description: Scans the comment on this record for "<egg> { ... }"
+//               and parses the enclosed string as if it appeared in
+//               the egg file.  Returns true on success, false on
+//               syntax error (in which case _error is also set to
+//               true).
+////////////////////////////////////////////////////////////////////
+bool FltToEggConverter::
+parse_comment(const FltBeadID *flt_bead, EggNode *egg_node) {
+  return parse_comment(flt_bead, flt_bead->get_id(), egg_node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::parse_comment
+//       Access: Private
+//  Description: Scans the comment on this record for "<egg> { ... }"
+//               and parses the enclosed string as if it appeared in
+//               the egg file.  Returns true on success, false on
+//               syntax error (in which case _error is also set to
+//               true).
+////////////////////////////////////////////////////////////////////
+bool FltToEggConverter::
+parse_comment(const FltRecord *flt_record, const string &name,
+	      EggNode *egg_node) {
+  if (!flt_record->has_comment()) {
+    // No comment.
+    return true;
+  }
+  string comment = flt_record->get_comment();
+
+  // Scan for <egg>.
+  size_t p;
+  p = 0;
+
+  static const string egg_str = "<egg>";
+
+  while (p < comment.length()) {
+    if (cmp_nocase(comment.substr(p, 5), egg_str) == 0) {
+      p += 5;
+      // Now scan past whitespace for the open curly brace.
+      while (p < comment.length() && isspace(comment[p])) {
+	++p;
+      }
+      if (p < comment.length() && comment[p] == '{') {
+	// Here's the beginning.  Now lop off the closing brace at the
+	// end.
+	++p;
+	size_t q = comment.length() - 1;
+	while (q > p && comment[q] != '}') {
+	  --q;
+	}
+	if (q == p) {
+	  nout << "No closing brace in comment for " 
+	       << name << "\n\n";
+	  _error = true;
+	  return false;
+	}
+	string egg_syntax = comment.substr(p, q - p);
+
+	if (!egg_node->parse_egg(egg_syntax)) {
+	  nout << "Syntax error in comment for "
+	       << name << "\n\n";
+	  _error = true;
+	  return false;
+	}
+	// Correctly parsed!
+	return true;
+      }
+      nout << "No opening brace in comment for " 
+	   << name << "\n\n";
+      _error = true;
+      return false;
+    }
+  }
+
+  // No <egg> appears in this comment.
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 21 - 18
pandatool/src/fltegg/fltToEggConverter.h

@@ -8,6 +8,8 @@
 
 
 #include <pandatoolbase.h>
 #include <pandatoolbase.h>
 
 
+#include "fltToEggLevelState.h"
+
 #include <distanceUnit.h>
 #include <distanceUnit.h>
 
 
 #include <fltHeader.h>
 #include <fltHeader.h>
@@ -25,6 +27,7 @@ class FltBead;
 class FltVertex;
 class FltVertex;
 class FltGeometry;
 class FltGeometry;
 class FltFace;
 class FltFace;
+class FltExternalReference;
 class FltTexture;
 class FltTexture;
 class EggGroupNode;
 class EggGroupNode;
 class EggPrimitive;
 class EggPrimitive;
@@ -45,31 +48,29 @@ public:
   INLINE void set_input_units(DistanceUnit input_units);
   INLINE void set_input_units(DistanceUnit input_units);
   INLINE void set_output_units(DistanceUnit output_units);
   INLINE void set_output_units(DistanceUnit output_units);
 
 
-  void convert_flt(const FltHeader *flt_header);
+  bool convert_flt(const FltHeader *flt_header);
 
 
 private:
 private:
   typedef vector< PT(EggVertex) > EggVertices;
   typedef vector< PT(EggVertex) > EggVertices;
 
 
-  void convert_record(const FltRecord *flt_record, const FltObject *flt_object,
-		      EggGroupNode *egg_group);
-  void convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
-		   EggGroupNode *egg_parent);
-  void convert_group(const FltGroup *flt_group, const FltObject *flt_object,
-		     EggGroupNode *egg_parent);
-  void convert_object(const FltObject *flt_object, const FltObject *,
-		      EggGroupNode *egg_parent);
-  void convert_bead_id(const FltBeadID *flt_bead, const FltObject *flt_object,
-		       EggGroupNode *egg_parent);
-  void convert_bead(const FltBead *flt_bead, const FltObject *flt_object,
-		    EggGroupNode *egg_parent);
-  void convert_face(const FltFace *flt_face, const FltObject *flt_object,
-		    EggGroupNode *egg_parent);
-
-
-  void setup_geometry(const FltGeometry *flt_geom, const FltObject *flt_object,
+  void convert_record(const FltRecord *flt_record, FltToEggLevelState &state);
+  void convert_lod(const FltLOD *flt_lod, FltToEggLevelState &state);
+  void convert_group(const FltGroup *flt_group, FltToEggLevelState &state);
+  void convert_object(const FltObject *flt_object, FltToEggLevelState &state);
+  void convert_bead_id(const FltBeadID *flt_bead, FltToEggLevelState &state);
+  void convert_bead(const FltBead *flt_bead, FltToEggLevelState &state);
+  void convert_face(const FltFace *flt_face, FltToEggLevelState &state);
+  void convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state);
+		    
+  void setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
 		      EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
 		      EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
 		      const EggVertices &vertices);
 		      const EggVertices &vertices);
 
 
+  void set_transform(const FltBead *flt_bead, EggGroup *egg_group);
+  bool parse_comment(const FltBeadID *flt_bead, EggNode *egg_node);
+  bool parse_comment(const FltRecord *flt_record, const string &name,
+		     EggNode *egg_node);
+
   PT(EggVertex) make_egg_vertex(const FltVertex *flt_vertex);
   PT(EggVertex) make_egg_vertex(const FltVertex *flt_vertex);
   PT(EggTexture) make_egg_texture(const FltTexture *flt_texture);
   PT(EggTexture) make_egg_texture(const FltTexture *flt_texture);
 
 
@@ -83,6 +84,8 @@ private:
 
 
   typedef map<const FltTexture *, PT(EggTexture) > Textures;
   typedef map<const FltTexture *, PT(EggTexture) > Textures;
   Textures _textures;
   Textures _textures;
+
+  bool _error;
 };
 };
 
 
 #include "fltToEggConverter.I"
 #include "fltToEggConverter.I"

+ 40 - 0
pandatool/src/fltegg/fltToEggLevelState.I

@@ -0,0 +1,40 @@
+// Filename: fltToEggLevelState.I
+// Created by:  drose (18Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE FltToEggLevelState::
+FltToEggLevelState() {
+  _flt_object = (FltObject *)NULL;
+  _egg_parent = (EggGroupNode *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE FltToEggLevelState::
+FltToEggLevelState(const FltToEggLevelState &copy) :
+  _flt_object(copy._flt_object),
+  _egg_parent(copy._egg_parent)
+{
+  // We don't bother to copy the _parents map.
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void FltToEggLevelState::
+operator = (const FltToEggLevelState &copy) {
+  _flt_object = copy._flt_object;
+  _egg_parent = copy._egg_parent;
+  // We don't bother to copy the _parents map.
+}

+ 111 - 0
pandatool/src/fltegg/fltToEggLevelState.cxx

@@ -0,0 +1,111 @@
+// Filename: fltToEggLevelState.cxx
+// Created by:  drose (18Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltToEggLevelState.h"
+
+#include <eggGroup.h>
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltToEggLevelState::
+~FltToEggLevelState() {
+  Parents::iterator pi;
+  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
+    delete (*pi).second;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::ParentNodes::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltToEggLevelState::ParentNodes::
+ParentNodes() {
+  _axial_billboard = (EggGroup *)NULL;
+  _point_billboard = (EggGroup *)NULL;
+  _plain = (EggGroup *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggLevelState::get_synthetic_group
+//       Access: Public
+//  Description: Sometimes it is necessary to synthesize a group
+//               within a particular EggGroup, for instance to insert
+//               a transform or billboard flag.  This function will
+//               synthesize a group as needed, or return an existing
+//               group (if the group need not be synthesized, or if a
+//               matching group was previously synthesized).
+//
+//               This collects together polygons that share the same
+//               billboard axis and/or transform space into the same
+//               group, rather that wastefully creating a group per
+//               polygon.
+////////////////////////////////////////////////////////////////////
+EggGroupNode *FltToEggLevelState::
+get_synthetic_group(const string &name,
+		    const LMatrix4d &transform,
+		    FltGeometry::BillboardType type) {
+
+  bool is_identity = transform.almost_equal(LMatrix4d::ident_mat());
+  if (is_identity && type == FltGeometry::BT_none) {
+    // Trivial case: the primitive belongs directly in its parent
+    // group node.
+    return _egg_parent;
+  }
+
+  // For other cases, we may have to create a subgroup to put the
+  // primitive into.
+  Parents::iterator pi;
+  pi = _parents.find(transform);
+  ParentNodes *nodes;
+  if (pi != _parents.end()) {
+    nodes = (*pi).second;
+  } else {
+    nodes = new ParentNodes;
+    _parents.insert(Parents::value_type(transform, nodes));
+  }
+
+  switch (type) {
+  case FltGeometry::BT_axial:
+    if (nodes->_axial_billboard == (EggGroupNode *)NULL) {
+      nodes->_axial_billboard = new EggGroup(name);
+      _egg_parent->add_child(nodes->_axial_billboard);
+      nodes->_axial_billboard->set_billboard_type(EggGroup::BT_axis);
+      if (!is_identity) {
+	nodes->_axial_billboard->set_transform(transform);
+	nodes->_axial_billboard->set_group_type(EggGroup::GT_instance);
+      }
+    }
+    return nodes->_axial_billboard;
+
+  case FltGeometry::BT_point:
+    if (nodes->_point_billboard == (EggGroupNode *)NULL) {
+      nodes->_point_billboard = new EggGroup(name);
+      _egg_parent->add_child(nodes->_point_billboard);
+      nodes->_point_billboard->set_billboard_type(EggGroup::BT_point_world_relative);
+      if (!is_identity) {
+	nodes->_point_billboard->set_transform(transform);
+	nodes->_point_billboard->set_group_type(EggGroup::GT_instance);
+      }
+    }
+    return nodes->_point_billboard;
+
+  default:
+    if (nodes->_plain == (EggGroupNode *)NULL) {
+      nodes->_plain = new EggGroup(name);
+      _egg_parent->add_child(nodes->_plain);
+      if (!is_identity) {
+	nodes->_plain->set_transform(transform);
+	nodes->_plain->set_group_type(EggGroup::GT_instance);
+      }
+    }
+    return nodes->_plain;
+  }
+}

+ 52 - 0
pandatool/src/fltegg/fltToEggLevelState.h

@@ -0,0 +1,52 @@
+// Filename: fltToEggLevelState.h
+// Created by:  drose (18Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTTOEGGLEVELSTATE_H
+#define FLTTOEGGLEVELSTATE_H
+
+#include <pandatoolbase.h>
+
+#include <fltGeometry.h>
+
+class FltObject;
+class EggGroupNode;
+class EggGroup;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltToEggLevelState
+// Description : This keeps track of relevant things about the
+//               traversal as we walk through the flt hierarchy.
+////////////////////////////////////////////////////////////////////
+class FltToEggLevelState {
+public:
+  INLINE FltToEggLevelState();
+  INLINE FltToEggLevelState(const FltToEggLevelState &copy);
+  INLINE void operator = (const FltToEggLevelState &copy);
+  ~FltToEggLevelState();
+
+  EggGroupNode *get_synthetic_group(const string &name,
+				    const LMatrix4d &transform,
+				    FltGeometry::BillboardType type = FltGeometry::BT_none);
+
+  const FltObject *_flt_object;
+  EggGroupNode *_egg_parent;
+
+private:
+  class ParentNodes {
+  public:
+    ParentNodes();
+
+    EggGroup *_axial_billboard;
+    EggGroup *_point_billboard;
+    EggGroup *_plain;
+  };
+
+  typedef map<LMatrix4d, ParentNodes *> Parents;
+  Parents _parents;
+};
+
+#include "fltToEggLevelState.I"
+  
+#endif

+ 5 - 1
pandatool/src/fltprogs/fltToEgg.cxx

@@ -59,7 +59,11 @@ run() {
   _data.set_coordinate_system(_coordinate_system);
   _data.set_coordinate_system(_coordinate_system);
 
 
   FltToEggConverter converter(_data);
   FltToEggConverter converter(_data);
-  converter.convert_flt(header);
+  if (!converter.convert_flt(header)) {
+    nout << "Errors in conversion.\n";
+    exit(1);
+  }
+
   write_egg_file();
   write_egg_file();
 }
 }