Browse Source

add 3-d texture coordinates to egg syntax

David Rose 20 năm trước cách đây
mục cha
commit
ae4051cef8
45 tập tin đã thay đổi với 4685 bổ sung4220 xóa
  1. 74 53
      panda/src/doc/eggSyntax.txt
  2. 3 3
      panda/src/egg/Sources.pp
  3. 4 4
      panda/src/egg/eggAttributes.cxx
  4. 13 2
      panda/src/egg/eggGroup.cxx
  5. 5 2
      panda/src/egg/eggGroup.h
  6. 22 0
      panda/src/egg/eggMiscFuncs.cxx
  7. 8 0
      panda/src/egg/eggMiscFuncs.h
  8. 11 34
      panda/src/egg/eggMorph.I
  9. 4 11
      panda/src/egg/eggMorph.h
  10. 5 2
      panda/src/egg/eggMorphList.I
  11. 2 1
      panda/src/egg/eggMorphList.h
  12. 12 0
      panda/src/egg/eggObject.cxx
  13. 5 0
      panda/src/egg/eggObject.h
  14. 7 2
      panda/src/egg/eggPrimitive.cxx
  15. 6 61
      panda/src/egg/eggTexture.I
  16. 5 6
      panda/src/egg/eggTexture.cxx
  17. 2 9
      panda/src/egg/eggTexture.h
  18. 369 0
      panda/src/egg/eggTransform.I
  19. 155 62
      panda/src/egg/eggTransform.cxx
  20. 48 27
      panda/src/egg/eggTransform.h
  21. 0 240
      panda/src/egg/eggTransform3d.I
  22. 1 1
      panda/src/egg/eggVertex.I
  23. 62 4
      panda/src/egg/eggVertex.cxx
  24. 5 2
      panda/src/egg/eggVertex.h
  25. 15 6
      panda/src/egg/eggVertexPool.cxx
  26. 2 1
      panda/src/egg/eggVertexPool.h
  27. 73 5
      panda/src/egg/eggVertexUV.I
  28. 37 9
      panda/src/egg/eggVertexUV.cxx
  29. 10 2
      panda/src/egg/eggVertexUV.h
  30. 1 1
      panda/src/egg/egg_composite2.cxx
  31. 2944 2965
      panda/src/egg/lexer.cxx.prebuilt
  32. 440 435
      panda/src/egg/parser.cxx.prebuilt
  33. 2 2
      panda/src/egg/parser.h.prebuilt
  34. 104 99
      panda/src/egg/parser.yxx
  35. 144 112
      panda/src/egg2pg/eggLoader.cxx
  36. 3 3
      panda/src/egg2pg/eggLoader.h
  37. 1 18
      panda/src/egg2pg/eggRenderState.cxx
  38. 1 1
      panda/src/egg2pg/eggRenderState.h
  39. 2 0
      panda/src/linmath/aa_luse.h
  40. 3 3
      pandatool/src/bam/bamToEgg.cxx
  41. 13 13
      pandatool/src/fltegg/fltToEggLevelState.cxx
  42. 56 13
      pandatool/src/fltprogs/eggToFlt.cxx
  43. 2 2
      pandatool/src/fltprogs/eggToFlt.h
  44. 2 2
      pandatool/src/palettizer/textureReference.cxx
  45. 2 2
      pandatool/src/xfileegg/xFileVertex.cxx

+ 74 - 53
panda/src/doc/eggSyntax.txt

@@ -372,36 +372,49 @@ appear before they are referenced.
 
   <Transform> { transform-definition }
 
-    This specifies a 2-d transformation that is applied to the UV's of
-    a surface to generate the texture coordinates.
-
-    The transform syntax is similar to that for groups, except it
-    defines a 2-d 3x3 matrix.  The definition may be any sequence of
-    zero or more of the following.  Transformations are post
-    multiplied in the order they are encountered to produce a net
-    transformation matrix.  Rotations are counterclockwise about the
-    origin in degrees.  Matrices, when specified explicitly, are
-    row-major.
-
-    <Translate> { x y }
-    <Rotate> { degrees }
-    <Scale> { x y }
-    <Scale> { s }
-
-    <Matrix3> {
-      00 01 02
-      10 11 12
-      20 21 22
-    }
+    This specifies a 2-d or 3-d transformation that is applied to the
+    UV's of a surface to generate the texture coordinates.
 
-    The transform definition might also include the following scalar:
+    The transform syntax is similar to that for groups, except it may
+    define either a 2-d 3x3 matrix or a 3-d 4x4 matrix.  (You should
+    use the two-dimensional forms if the UV's are two-dimensional, and
+    the three-dimensional forms if the UV's are three-dimensional.)
 
-    <Scalar> animated { 1 }
+    A two-dimensional transform may be any sequence of zero or more of
+    the following.  Transformations are post multiplied in the order
+    they are encountered to produce a net transformation matrix.
+    Rotations are counterclockwise about the origin in degrees.
+    Matrices, when specified explicitly, are row-major.
+
+      <Translate> { x y }
+      <Rotate> { degrees }
+      <Scale> { x y }
+      <Scale> { s }
+
+      <Matrix3> {
+        00 01 02
+        10 11 12
+        20 21 22
+      }
 
-    If this is set, it indicates the matrix may be animated by a
-    matrix channel, like a joint.  At present, this flag is not used;
-    eventually, it may be used to define an arbitrary texture
-    coordinate animation.
+    A three-dimensional transform may be any sequence of zero or more
+    of the following.  See the description under <Group>, below, for
+    more information.
+
+      <Translate> { x y z }
+      <RotX> { degrees }
+      <RotY> { degrees }
+      <RotZ> { degrees }
+      <Rotate> { degrees x y z }
+      <Scale> { x y z }
+      <Scale> { s }
+
+      <Matrix4> {
+        00 01 02 03
+        10 11 12 13
+        20 21 22 23
+        30 31 32 33
+      }
 
 
 <Material> name { [scalars] }
@@ -525,11 +538,18 @@ appear before they are referenced.
     (1 1 1 1).  The morph-list is an optional list of <DRGBA> entries.
 
 
-    <UV> [name] { u v [tangent] [binormal] [morph-list] }
+    <UV> [name] { u v [w] [tangent] [binormal] [morph-list] }
 
     This gives the texture coordinates of the vertex.  This must be
-    specified if a texture is to be mapped onto this geometry.  As
-    before, morph-list is an optional list of <DUV> entries.
+    specified if a texture is to be mapped onto this geometry.  
+
+    The texture coordinates are usually two-dimensional, with two
+    component values (u v), but they may also be three-dimensional,
+    with three component values (u v w).  (Arguably, it should be
+    called <UVW> instead of <UV> in the three-dimensional case, but
+    it's not.)
+
+    As before, morph-list is an optional list of <DUV> entries.
 
     Unlike the other kinds of attributes, there may be multiple sets
     of UV's on each vertex, each with a unique name; this provides
@@ -544,7 +564,7 @@ appear before they are referenced.
     different UV coordinate set.  If present, they have the expected
     syntax:
 
-    <UV> [name] { u v <Tangent> { x y z } <Binormal> { x y z } }
+    <UV> [name] { u v [w] <Tangent> { x y z } <Binormal> { x y z } }
 
 
 <DynamicVertexPool> name { vertices }
@@ -1000,12 +1020,13 @@ corresponding attribute entries:
   normalized to unit length.
 
 
-<DUV> target { u v }
+<DUV> target { u v [w] }
 
   A texture-coordinate delta, valid within a <UV> entry (within a
-  <Vertex> entry).  The given 2-valued offset vector, scaled by the
-  morph target's value, is added to the vertex's texture coordinates
-  each frame.
+  <Vertex> entry).  The offset vector should be 2-valued if the
+  enclosing UV is 2-valued, or 3-valued if the enclosing UV is
+  3-valued.  The given offset vector, scaled by the morph target's
+  value, is added to the vertex's texture coordinates each frame.
 
 
 <DRGBA> target { r g b a }
@@ -1366,25 +1387,25 @@ GROUPING ENTRIES
     a particular axis, either implicit (about the x, y, or z axis), or
     arbitrary.  Matrices, when specified explicitly, are row-major.
 
-    <Translate> { x y z }
-    <RotX> { degrees }
-    <RotY> { degrees }
-    <RotZ> { degrees }
-    <Rotate> { degrees x y z }
-    <Scale> { x y z }
-    <Scale> { s }
-
-    <Matrix4> {
-      00 01 02 03
-      10 11 12 13
-      20 21 22 23
-      30 31 32 33
-    }
+      <Translate> { x y z }
+      <RotX> { degrees }
+      <RotY> { degrees }
+      <RotZ> { degrees }
+      <Rotate> { degrees x y z }
+      <Scale> { x y z }
+      <Scale> { s }
+
+      <Matrix4> {
+        00 01 02 03
+        10 11 12 13
+        20 21 22 23
+        30 31 32 33
+      }
 
-    Note that the <Transform> block defines a 3-d transform when it
-    appears within the context of a node, while it defines a 2-d
-    transform (and has correspondingly different entries) when it
-    appears within the context of a texture.
+    Note that the <Transform> block should always define a 3-d
+    transform when it appears within the body of a <Group>, while it
+    may define either a 2-d or a 3-d transform when it appears within
+    the body of a <Texture>.  See <Texture>, above.
 
 
   <VertexRef> { indices <Ref> { pool-name } }

+ 3 - 3
panda/src/egg/Sources.pp

@@ -41,7 +41,7 @@
      eggTexture.h eggTextureCollection.I eggTextureCollection.h  \
      eggTriangleFan.I eggTriangleFan.h \
      eggTriangleStrip.I eggTriangleStrip.h \
-     eggTransform3d.I eggTransform3d.h \
+     eggTransform.I eggTransform.h \
      eggUserData.I eggUserData.h \
      eggUtilities.I eggUtilities.h \
      eggVertex.I eggVertex.h eggVertexPool.I eggVertexPool.h \
@@ -72,7 +72,7 @@
      eggPoolUniquifier.cxx eggPrimitive.cxx eggRenderMode.cxx  \
      eggSAnimData.cxx eggSurface.cxx eggSwitchCondition.cxx  \
      eggTable.cxx eggTexture.cxx eggTextureCollection.cxx  \
-     eggTransform3d.cxx \
+     eggTransform.cxx \
      eggTriangleFan.cxx \
      eggTriangleStrip.cxx \
      eggUserData.cxx \
@@ -104,7 +104,7 @@
     eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h \
     eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
     eggTexture.h eggTextureCollection.I eggTextureCollection.h \
-    eggTransform3d.I eggTransform3d.h \
+    eggTransform.I eggTransform.h \
     eggTriangleFan.I eggTriangleFan.h \
     eggTriangleStrip.I eggTriangleStrip.h \
     eggUserData.I eggUserData.h \

+ 4 - 4
panda/src/egg/eggAttributes.cxx

@@ -85,8 +85,8 @@ write(ostream &out, int indent_level) const {
         << "<Normal> { " << get_normal() << " }\n";
     } else {
       indent(out, indent_level) << "<Normal> {\n";
-      indent(out, indent_level+2) << get_normal() << "\n";
-      _dnormals.write(out, indent_level+2);
+      indent(out, indent_level + 2) << get_normal() << "\n";
+      _dnormals.write(out, indent_level + 2, "<DNormal>", 3);
       indent(out, indent_level) << "}\n";
     }
   }
@@ -96,8 +96,8 @@ write(ostream &out, int indent_level) const {
         << "<RGBA> { " << get_color() << " }\n";
     } else {
       indent(out, indent_level) << "<RGBA> {\n";
-      indent(out, indent_level+2) << get_color() << "\n";
-      _drgbas.write(out, indent_level+2);
+      indent(out, indent_level + 2) << get_color() << "\n";
+      _drgbas.write(out, indent_level + 2, "<DRBGA>", 4);
       indent(out, indent_level) << "}\n";
     }
   }

+ 13 - 2
panda/src/egg/eggGroup.cxx

@@ -63,7 +63,7 @@ EggGroup(const EggGroup &copy) {
 ////////////////////////////////////////////////////////////////////
 EggGroup &EggGroup::
 operator = (const EggGroup &copy) {
-  EggTransform3d::operator = (copy);
+  EggTransform::operator = (copy);
   _flags = copy._flags;
   _flags2 = copy._flags2;
   _collide_mask = copy._collide_mask;
@@ -215,7 +215,7 @@ write(ostream &out, int indent_level) const {
   write_switch_flags(out, indent_level + 2);
 
   if (has_transform()) {
-    EggTransform3d::write(out, indent_level + 2);
+    EggTransform::write(out, indent_level + 2);
   }
 
   write_object_types(out, indent_level + 2);
@@ -995,6 +995,17 @@ string_blend_operand(const string &strval) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::as_transform
+//       Access: Public, Virtual
+//  Description: Returns this object cross-cast to an EggTransform
+//               pointer, if it inherits from EggTransform, or NULL if
+//               it does not.
+////////////////////////////////////////////////////////////////////
+EggTransform *EggGroup::
+as_transform() {
+  return this;
+}
 
 
 ////////////////////////////////////////////////////////////////////

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

@@ -23,7 +23,7 @@
 
 #include "eggGroupNode.h"
 #include "eggRenderMode.h"
-#include "eggTransform3d.h"
+#include "eggTransform.h"
 #include "eggVertex.h"
 #include "eggSwitchCondition.h"
 #include "pt_EggVertex.h"
@@ -37,7 +37,7 @@
 // Description : The main glue of the egg hierarchy, this corresponds
 //               to the <Group>, <Instance>, and <Joint> type nodes.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEGG EggGroup : public EggGroupNode, public EggRenderMode, public EggTransform3d {
+class EXPCL_PANDAEGG EggGroup : public EggGroupNode, public EggRenderMode, public EggTransform {
 PUBLISHED:
   typedef pmap<PT_EggVertex, double> VertexRef;
   typedef pmap<string, string> TagData;
@@ -297,6 +297,9 @@ PUBLISHED:
   static BlendMode string_blend_mode(const string &strval);
   static BlendOperand string_blend_operand(const string &strval);
 
+public:
+  virtual EggTransform *as_transform();
+
 protected:
   void write_vertex_ref(ostream &out, int indent_level) const;
   virtual bool egg_start_parse_body();

+ 22 - 0
panda/src/egg/eggMiscFuncs.cxx

@@ -94,3 +94,25 @@ write_transform(ostream &out, const LMatrix3d &mat, int indent_level) {
   indent(out, indent_level+2) << "}\n";
   indent(out, indent_level) << "}\n";
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: write_transform
+//  Description: A helper function to write out a 4x4 transform
+//               matrix.
+////////////////////////////////////////////////////////////////////
+void
+write_transform(ostream &out, const LMatrix4d &mat, int indent_level) {
+  indent(out, indent_level) << "<Transform> {\n";
+
+  indent(out, indent_level+2) << "<Matrix4> {\n";
+
+  for (int r = 0; r < 4; r++) {
+    indent(out, indent_level+3);
+    for (int c = 0; c < 4; c++) {
+      out << " " << mat(r, c);
+    }
+    out << "\n";
+  }
+  indent(out, indent_level+2) << "}\n";
+  indent(out, indent_level) << "}\n";
+}

+ 8 - 0
panda/src/egg/eggMiscFuncs.h

@@ -55,6 +55,14 @@ enquote_string(ostream &out, const string &str,
 void
 write_transform(ostream &out, const LMatrix3d &mat, int indent_level);
 
+////////////////////////////////////////////////////////////////////
+//     Function: write_transform
+//  Description: A helper function to write out a 4x4 transform
+//               matrix.
+////////////////////////////////////////////////////////////////////
+void
+write_transform(ostream &out, const LMatrix4d &mat, int indent_level);
+
 
 #include "eggMiscFuncs.I"
 

+ 11 - 34
panda/src/egg/eggMorph.I

@@ -105,40 +105,17 @@ compare_to(const EggMorph<Parameter> &other) const {
   return _offset.compare_to(other._offset);
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggMorphVertex output operator
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ostream &operator << (ostream &out, const EggMorphVertex &m) {
-  return out << "<Dxyz> " << m.get_name() << " { " << m.get_offset() << " }";
-}
-
-
-/*
-////////////////////////////////////////////////////////////////////
-//     Function: EggMorphNormal output operator
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ostream &operator << (ostream &out, const EggMorphNormal &m) {
-  return out << "<DNormal> " << m.get_name() << " { " << m.get_offset() << " }";
-}
-*/
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggMorphTexCoord output operator
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE ostream &operator << (ostream &out, const EggMorphTexCoord &m) {
-  return out << "<Duv> " << m.get_name() << " { " << m.get_offset() << " }";
-}
-
-
 ////////////////////////////////////////////////////////////////////
-//     Function: EggMorphColor output operator
-//  Description:
+//     Function: EggMorph::output
+//       Access: Public
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-INLINE ostream &operator << (ostream &out, const EggMorphColor &m) {
-  return out << "<Drgba> " << m.get_name() << " { " << m.get_offset() << " }";
+template<class Parameter>
+INLINE void EggMorph<Parameter>::
+output(ostream &out, const string &tag, int num_dimensions) const {
+  out << tag << " " << get_name() << " {";
+  for (int i = 0; i < num_dimensions; ++i) {
+    out << " " << MAYBE_ZERO(_offset[i]);
+  }
+  out << " }";
 }

+ 4 - 11
panda/src/egg/eggMorph.h

@@ -46,28 +46,21 @@ public:
 
   INLINE int compare_to(const EggMorph<Parameter> &other) const;
 
+  INLINE void output(ostream &out, const string &tag,
+                     int num_dimensions) const;
+
 private:
   Parameter _offset;
 };
 
 EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, EggMorph<LVector3d>);
-EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, EggMorph<LVector2d>);
 EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEGG, EXPTP_PANDAEGG, EggMorph<LVector4f>);
 
 typedef EggMorph<LVector3d> EggMorphVertex;
 typedef EggMorph<LVector3d> EggMorphNormal;
-typedef EggMorph<LVector2d> EggMorphTexCoord;
+typedef EggMorph<LVector3d> EggMorphTexCoord;
 typedef EggMorph<LVector4f> EggMorphColor;
 
-INLINE ostream &operator << (ostream &out, const EggMorphVertex &m);
-INLINE ostream &operator << (ostream &out, const EggMorphTexCoord &m);
-INLINE ostream &operator << (ostream &out, const EggMorphColor &m);
-
-// EggMorphNormal is, by virtue of equivalent typedefs, another name
-// for EggMorphVertex.  Therefore we shouldn't define its output
-// operator again.
-//INLINE ostream &operator << (ostream &out, const EggMorphNormal &m);
-
 #include "eggMorph.I"
 
 #endif

+ 5 - 2
panda/src/egg/eggMorphList.I

@@ -231,11 +231,14 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 template<class MorphType>
 void EggMorphList<MorphType>::
-write(ostream &out, int indent_level) const {
+write(ostream &out, int indent_level, const string &tag, 
+      int num_dimensions) const {
   const_iterator i;
 
   for (i = begin(); i != end(); ++i) {
-    indent(out, indent_level) << *i << "\n";
+    indent(out, indent_level);
+    i->output(out, tag, num_dimensions);
+    out << "\n";
   }
 }
 

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

@@ -62,7 +62,8 @@ public:
   pair<iterator, bool> insert(const MorphType &value);
   INLINE void clear();
 
-  void write(ostream &out, int indent_level) const;
+  void write(ostream &out, int indent_level,
+             const string &tag, int num_dimensions) const;
 
 private:
   Morphs _morphs;

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

@@ -175,3 +175,15 @@ clear_user_data(TypeHandle type) {
     _user_data.erase(ui);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggObject::as_transform
+//       Access: Public, Virtual
+//  Description: Returns this object cross-cast to an EggTransform
+//               pointer, if it inherits from EggTransform, or NULL if
+//               it does not.
+////////////////////////////////////////////////////////////////////
+EggTransform *EggObject::
+as_transform() {
+  return NULL;
+}

+ 5 - 0
panda/src/egg/eggObject.h

@@ -25,6 +25,8 @@
 #include "pointerTo.h"
 #include "pmap.h"
 
+class EggTransform;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : EggObject
 // Description : The highest-level base class in the egg directory.
@@ -46,6 +48,9 @@ PUBLISHED:
   void clear_user_data();
   void clear_user_data(TypeHandle type);
 
+public:
+  virtual EggTransform *as_transform();
+
 private:
   typedef pmap<TypeHandle, PT(EggUserData) > UserData;
   UserData _user_data;

+ 7 - 2
panda/src/egg/eggPrimitive.cxx

@@ -1037,7 +1037,7 @@ r_apply_texmats(EggTextureCollection &textures) {
 
       // We've got a texture with a matrix applied.  Save the matrix,
       // and get a new texture without the matrix.
-      LMatrix3d mat = texture->get_transform();
+      LMatrix4d mat = texture->get_transform();
       EggTexture new_texture(*texture);
       new_texture.clear_transform();
       EggTexture *unique = textures.create_unique_texture(new_texture, ~0);
@@ -1055,7 +1055,12 @@ r_apply_texmats(EggTextureCollection &textures) {
         if (uv_obj != (EggVertexUV *)NULL) {
           EggVertex new_vertex(*vertex);
           PT(EggVertexUV) new_uv_obj = new EggVertexUV(*uv_obj);
-          new_uv_obj->set_uv(uv_obj->get_uv() * mat);
+          TexCoord3d uvw = uv_obj->get_uvw() * mat;
+          if (uv_obj->has_w() || !texture->is_transform_2d()) {
+            new_uv_obj->set_uvw(uvw);
+          } else {
+            new_uv_obj->set_uv(TexCoordd(uvw[0], uvw[1]));
+          }
           new_vertex.set_uv_obj(new_uv_obj);
           
           EggVertexPool *pool = vertex->get_pool();

+ 6 - 61
panda/src/egg/eggTexture.I

@@ -522,8 +522,12 @@ get_color() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void EggTexture::
 set_uv_name(const string &uv_name) {
-  _uv_name = uv_name;
-  _flags |= F_has_uv_name;
+  if (uv_name == "default" || uv_name.empty()) {
+    clear_uv_name();
+  } else {
+    _uv_name = uv_name;
+    _flags |= F_has_uv_name;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -663,65 +667,6 @@ get_alpha_scale() const {
   return _alpha_scale;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggTexture::set_transform
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE void EggTexture::
-set_transform(const LMatrix3d &transform) {
-  _transform = transform;
-  _flags |= F_has_transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTexture::clear_transform
-//       Access: Published
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE void EggTexture::
-clear_transform() {
-  _transform = LMatrix3d::ident_mat();
-  _flags &= ~F_has_transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTexture::has_transform
-//       Access: Published
-//  Description: Returns true if a texture matrix transform has been
-//               specified for the texture (even if the transform is
-//               identity).
-////////////////////////////////////////////////////////////////////
-INLINE bool EggTexture::
-has_transform() const {
-  return (_flags & F_has_transform) != 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTexture::get_transform
-//       Access: Published
-//  Description: Returns the texture matrix transform if one has been
-//               specified, or identity matrix otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE const LMatrix3d &EggTexture::
-get_transform() const {
-  return _transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTexture::transform_is_identity()
-//       Access: Published
-//  Description: Returns true if no texture matrix transform has been
-//               specified, or if the one specified is the identity
-//               transform.  Returns false only if a nonidentity
-//               transform has been applied.
-////////////////////////////////////////////////////////////////////
-INLINE bool EggTexture::
-transform_is_identity() const {
-  return (!has_transform() ||
-          _transform.almost_equal(LMatrix3d::ident_mat(), 0.0001));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTexture::set_alpha_filename
 //       Access: Published

+ 5 - 6
panda/src/egg/eggTexture.cxx

@@ -48,7 +48,6 @@ EggTexture(const string &tref_name, const string &filename)
   _priority = 0;
   _color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _flags = 0;
-  _transform = LMatrix3d::ident_mat();
   _alpha_file_channel = 0;
   _multitexture_sort = 0;
 }
@@ -74,6 +73,7 @@ operator = (const EggTexture &copy) {
 
   EggFilenameNode::operator = (copy);
   EggRenderMode::operator = (copy);
+  EggTransform::operator = (copy);
 
   _format = copy._format;
   _wrap_mode = copy._wrap_mode;
@@ -92,7 +92,6 @@ operator = (const EggTexture &copy) {
   _rgb_scale = 1;
   _alpha_scale = 1;
   _flags = copy._flags;
-  _transform = copy._transform;
   _alpha_filename = copy._alpha_filename;
   _alpha_fullpath = copy._alpha_fullpath;
   _alpha_file_channel = copy._alpha_file_channel;
@@ -247,7 +246,7 @@ write(ostream &out, int indent_level) const {
   EggRenderMode::write(out, indent_level + 2);
 
   if (has_transform()) {
-    write_transform(out, _transform, indent_level + 2);
+    EggTransform::write(out, indent_level + 2);
   }
 
   indent(out, indent_level) << "}\n";
@@ -324,7 +323,7 @@ is_equivalent_to(const EggTexture &other, int eq) const {
     }
 
     if (has_transform() && other.has_transform()) {
-      if (!_transform.almost_equal(other._transform, 0.0001)) {
+      if (!get_transform().almost_equal(other.get_transform(), 0.0001)) {
         return false;
       }
     }
@@ -400,9 +399,9 @@ sorts_less_than(const EggTexture &other, int eq) const {
     }
 
     if (has_transform() && other.has_transform()) {
-      int compare = _transform.compare_to(other._transform);
+      int compare = get_transform().compare_to(other.get_transform());
       if (compare != 0) {
-    return compare < 0;
+        return compare < 0;
       }
     }
   }

+ 2 - 9
panda/src/egg/eggTexture.h

@@ -23,6 +23,7 @@
 
 #include "eggRenderMode.h"
 #include "eggFilenameNode.h"
+#include "eggTransform.h"
 
 #include "pset.h"
 #include "luse.h"
@@ -33,7 +34,7 @@
 // Description : Defines a texture map that may be applied to
 //               geometry.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEGG EggTexture : public EggFilenameNode, public EggRenderMode {
+class EXPCL_PANDAEGG EggTexture : public EggFilenameNode, public EggRenderMode, public EggTransform {
 PUBLISHED:
   EggTexture(const string &tref_name, const string &filename);
   EggTexture(const EggTexture &copy);
@@ -216,12 +217,6 @@ PUBLISHED:
   INLINE bool has_alpha_scale() const;
   INLINE int get_alpha_scale() const;
 
-  INLINE void set_transform(const LMatrix3d &transform);
-  INLINE void clear_transform();
-  INLINE bool has_transform() const;
-  INLINE const LMatrix3d &get_transform() const;
-  INLINE bool transform_is_identity() const;
-
   INLINE void set_alpha_filename(const Filename &filename);
   INLINE void clear_alpha_filename();
   INLINE bool has_alpha_filename() const;
@@ -256,7 +251,6 @@ private:
   bool r_min_multitexture_sort(int sort, MultiTextures &cycle_detector);
 
   enum Flags {
-    F_has_transform          = 0x0001,
     F_has_alpha_filename     = 0x0002,
     F_has_anisotropic_degree = 0x0004,
     F_has_alpha_file_channel = 0x0008,
@@ -282,7 +276,6 @@ private:
   int _rgb_scale;
   int _alpha_scale;
   int _flags;
-  LMatrix3d _transform;
   Filename _alpha_filename;
   Filename _alpha_fullpath;
   int _alpha_file_channel;

+ 369 - 0
panda/src/egg/eggTransform.I

@@ -0,0 +1,369 @@
+// Filename: eggTransform.I
+// Created by:  drose (21Jun02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::Component::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform::Component::
+Component(EggTransform::ComponentType type, double number) :
+  _type(type),
+  _number(number)
+{
+  _vec2 = (LVecBase2d *)NULL;
+  _vec3 = (LVecBase3d *)NULL;
+  _mat3 = (LMatrix3d *)NULL;
+  _mat4 = (LMatrix4d *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::Component::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform::Component::
+Component(const EggTransform::Component &copy) :
+  _type(copy._type),
+  _number(copy._number)
+{
+  _vec2 = (LVecBase2d *)NULL;
+  _vec3 = (LVecBase3d *)NULL;
+  _mat3 = (LMatrix3d *)NULL;
+  _mat4 = (LMatrix4d *)NULL;
+  if (copy._vec2 != (LVecBase2d *)NULL) {
+    _vec2 = new LVector2d(*copy._vec2);
+  }
+  if (copy._vec3 != (LVecBase3d *)NULL) {
+    _vec3 = new LVector3d(*copy._vec3);
+  }
+  if (copy._mat3 != (LMatrix3d *)NULL) {
+    _mat3 = new LMatrix3d(*copy._mat3);
+  }
+  if (copy._mat4 != (LMatrix4d *)NULL) {
+    _mat4 = new LMatrix4d(*copy._mat4);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::Component::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::Component::
+operator = (const EggTransform::Component &copy) {
+  _type = copy._type;
+  _number = copy._number;
+  if (_vec2 != (LVecBase2d *)NULL) {
+    delete _vec2;
+    _vec2 = (LVecBase2d *)NULL;
+  }
+  if (_vec3 != (LVecBase3d *)NULL) {
+    delete _vec3;
+    _vec3 = (LVecBase3d *)NULL;
+  }
+  if (_mat3 != (LMatrix3d *)NULL) {
+    delete _mat3;
+    _mat3 = (LMatrix3d *)NULL;
+  }
+  if (_mat4 != (LMatrix4d *)NULL) {
+    delete _mat4;
+    _mat4 = (LMatrix4d *)NULL;
+  }
+  if (copy._vec2 != (LVecBase2d *)NULL) {
+    _vec2 = new LVecBase2d(*copy._vec2);
+  }
+  if (copy._vec3 != (LVecBase3d *)NULL) {
+    _vec3 = new LVecBase3d(*copy._vec3);
+  }
+  if (copy._mat3 != (LMatrix3d *)NULL) {
+    _mat3 = new LMatrix3d(*copy._mat3);
+  }
+  if (copy._mat4 != (LMatrix4d *)NULL) {
+    _mat4 = new LMatrix4d(*copy._mat4);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::Component::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform::Component::
+~Component() {
+  if (_vec2 != (LVecBase2d *)NULL) {
+    delete _vec2;
+  }
+  if (_vec3 != (LVecBase3d *)NULL) {
+    delete _vec3;
+  }
+  if (_mat3 != (LMatrix3d *)NULL) {
+    delete _mat3;
+  }
+  if (_mat4 != (LMatrix4d *)NULL) {
+    delete _mat4;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::clear_transform
+//       Access: Public
+//  Description: Resets the transform to empty, identity.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+clear_transform() {
+  internal_clear_transform();
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::add_matrix3
+//       Access: Public
+//  Description: Appends an arbitrary 3x3 matrix to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+add_matrix3(const LMatrix3d &mat) {
+  internal_add_matrix(mat);
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::add_matrix4
+//       Access: Public
+//  Description: Appends an arbitrary 4x4 matrix to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+add_matrix4(const LMatrix4d &mat) {
+  internal_add_matrix(mat);
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::has_transform
+//       Access: Public
+//  Description: Returns true if the transform is nonempty, false if
+//               it is empty (no transform components have been
+//               added).
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTransform::
+has_transform() const {
+  return !_components.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::is_transform_2d
+//       Access: Public
+//  Description: Returns true if the transform is specified as a 2-d
+//               transform, e.g. with a 3x3 matrix, or false if it is
+//               specified as a 3-d transform, with a 4x4 matrix.
+//
+//               Normally, EggTextures have a 2-d matrix (but
+//               occasionally they use a 3-d matrix), and EggGroups
+//               always have a 3-d matrix.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTransform::
+is_transform_2d() const {
+  return _is_transform_2d;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::set_transform_2d
+//       Access: Public
+//  Description: Sets the overall transform as a 3x3 matrix.  This
+//               completely replaces whatever componentwise transform
+//               may have been defined.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+set_transform_2d(const LMatrix3d &mat) {
+  internal_set_transform(mat);
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::set_transform
+//       Access: Public
+//  Description: Sets the overall transform as a 4x4 matrix.  This
+//               completely replaces whatever componentwise transform
+//               may have been defined.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+set_transform(const LMatrix4d &mat) {
+  internal_set_transform(mat);
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_transform_2d
+//       Access: Public
+//  Description: Returns the overall transform as a 3x3 matrix.  It is
+//               only valid to call this if is_transform_2d() has
+//               returned true.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix3d EggTransform::
+get_transform_2d() const {
+  nassertr(is_transform_2d(), LMatrix3d::ident_mat());
+  const LMatrix4d &t = _transform;
+  return LMatrix3d(t(0, 0), t(0, 1), t(0, 3),
+                   t(1, 0), t(1, 1), t(1, 3),
+                   t(3, 0), t(3, 1), t(3, 3));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_transform
+//       Access: Public
+//  Description: Returns the overall transform as a 4x4 matrix.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4d &EggTransform::
+get_transform() const {
+  return _transform;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::transform_is_identity
+//       Access: Public
+//  Description: Returns true if the described transform is identity,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTransform::
+transform_is_identity() const {
+  return _components.empty() ||
+    _transform.almost_equal(LMatrix4d::ident_mat(), 0.0001);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_num_components
+//       Access: Public
+//  Description: Returns the number of components that make up the
+//               transform.
+////////////////////////////////////////////////////////////////////
+INLINE int EggTransform::
+get_num_components() const {
+  return _components.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_type
+//       Access: Public
+//  Description: Returns the type of the nth component.
+////////////////////////////////////////////////////////////////////
+INLINE EggTransform::ComponentType EggTransform::
+get_component_type(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), CT_invalid);
+  return _components[n]._type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_number
+//       Access: Public
+//  Description: Returns the solitary number associated with the nth
+//               component.  In the case of a rotation, this is the
+//               angle in degrees to rotate; in the case of uniform
+//               scale, this is the amount of the scale.  Other types
+//               do not use this property.
+////////////////////////////////////////////////////////////////////
+INLINE double EggTransform::
+get_component_number(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), 0.0);
+  return _components[n]._number;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_vec2
+//       Access: Public
+//  Description: Returns the 2-component vector associated with the
+//               nth component.  This may be the translate vector,
+//               rotate axis, or non-uniform scale.  It is an error to
+//               call this if the component type does not use a 2-d
+//               vector property.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2d &EggTransform::
+get_component_vec2(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LVector2d::zero());
+  nassertr(_components[n]._vec2 != (LVecBase2d *)NULL, LVector2d::zero());
+  return *_components[n]._vec2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_vec3
+//       Access: Public
+//  Description: Returns the 3-component vector associated with the
+//               nth component.  This may be the translate vector,
+//               rotate axis, or non-uniform scale.  It is an error to
+//               call this if the component type does not use a 3-d
+//               vector property.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase3d &EggTransform::
+get_component_vec3(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LVector3d::zero());
+  nassertr(_components[n]._vec3 != (LVecBase3d *)NULL, LVector3d::zero());
+  return *_components[n]._vec3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_mat3
+//       Access: Public
+//  Description: Returns the 3x3 matrix associated with the nth
+//               component.  It is an error to call this if the
+//               component type is not CT_matrix3.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix3d &EggTransform::
+get_component_mat3(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LMatrix3d::ident_mat());
+  nassertr(_components[n]._mat3 != (LMatrix3d *)NULL, LMatrix3d::ident_mat());
+  return *_components[n]._mat3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::get_component_mat4
+//       Access: Public
+//  Description: Returns the 4x4 matrix associated with the nth
+//               component.  It is an error to call this if the
+//               component type is not CT_matrix4.
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4d &EggTransform::
+get_component_mat4(int n) const {
+  nassertr(n >= 0 && n < (int)_components.size(), LMatrix4d::ident_mat());
+  nassertr(_components[n]._mat4 != (LMatrix4d *)NULL, LMatrix4d::ident_mat());
+  return *_components[n]._mat4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::internal_set_transform
+//       Access: Protected
+//  Description: Sets the overall transform without calling
+//               transform_changed().
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+internal_set_transform(const LMatrix3d &mat) {
+  internal_clear_transform();
+  internal_add_matrix(mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::internal_set_transform
+//       Access: Protected
+//  Description: Sets the overall transform without calling
+//               transform_changed().
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform::
+internal_set_transform(const LMatrix4d &mat) {
+  internal_clear_transform();
+  internal_add_matrix(mat);
+}

+ 155 - 62
panda/src/egg/eggTransform3d.cxx → panda/src/egg/eggTransform.cxx

@@ -1,4 +1,4 @@
-// Filename: eggTransform3d.cxx
+// Filename: eggTransform.cxx
 // Created by:  drose (21Jun02)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,158 +16,211 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "eggTransform3d.h"
+#include "eggTransform.h"
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Constructor
+//     Function: EggTransform::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-EggTransform3d::
-EggTransform3d() :
+EggTransform::
+EggTransform() :
+  _is_transform_2d(true),
   _transform(LMatrix4d::ident_mat())
 {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Copy Constructor
+//     Function: EggTransform::Copy Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-EggTransform3d::
-EggTransform3d(const EggTransform3d &copy) :
+EggTransform::
+EggTransform(const EggTransform &copy) :
+  _is_transform_2d(copy._is_transform_2d),
   _components(copy._components),
   _transform(copy._transform)
 {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Copy assignment operator
+//     Function: EggTransform::Copy assignment operator
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-EggTransform3d &EggTransform3d::
-operator = (const EggTransform3d &copy) {
+EggTransform &EggTransform::
+operator = (const EggTransform &copy) {
+  _is_transform_2d = copy._is_transform_2d;
   _components = copy._components;
   _transform = copy._transform;
   return *this;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Destructor
+//     Function: EggTransform::Destructor
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-EggTransform3d::
-~EggTransform3d() {
+EggTransform::
+~EggTransform() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_translate
+//     Function: EggTransform::add_translate2d
 //       Access: Public
-//  Description: Appends a translation operation to the current
+//  Description: Appends a 2-d translation operation to the current
 //               transform.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-add_translate(const LVector3d &translate) {
-  _components.push_back(Component(CT_translate));
-  _components.back()._vector = new LVector3d(translate);
+void EggTransform::
+add_translate2d(const LVector2d &translate) {
+  _components.push_back(Component(CT_translate2d));
+  _components.back()._vec2 = new LVecBase2d(translate);
+  _transform *= LMatrix4d::translate_mat(LVector3d(translate[0], translate[1], 0.0));
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::add_translate3d
+//       Access: Public
+//  Description: Appends a 3-d translation operation to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+void EggTransform::
+add_translate3d(const LVector3d &translate) {
+  _is_transform_2d = false;
+  _components.push_back(Component(CT_translate3d));
+  _components.back()._vec3 = new LVecBase3d(translate);
   _transform *= LMatrix4d::translate_mat(translate);
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_rotx
+//     Function: EggTransform::add_rotate2d
+//       Access: Public
+//  Description: Appends a 2-d rotation to the current transform.  The
+//               rotation angle is specified in degrees
+//               counterclockwise about the origin.
+////////////////////////////////////////////////////////////////////
+void EggTransform::
+add_rotate2d(double angle) {
+  _components.push_back(Component(CT_rotate2d, angle));
+  _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 0.0, 1.0));
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::add_rotx
 //       Access: Public
 //  Description: Appends a rotation about the X axis to the current
 //               transform.  The rotation angle is specified in
 //               degrees counterclockwise about the axis.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 add_rotx(double angle) {
+  _is_transform_2d = false;
   _components.push_back(Component(CT_rotx, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(1.0, 0.0, 0.0));
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_roty
+//     Function: EggTransform::add_roty
 //       Access: Public
 //  Description: Appends a rotation about the Y axis to the current
 //               transform.  The rotation angle is specified in
 //               degrees counterclockwise about the axis.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 add_roty(double angle) {
+  _is_transform_2d = false;
   _components.push_back(Component(CT_roty, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 1.0, 0.0));
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_rotz
+//     Function: EggTransform::add_rotz
 //       Access: Public
 //  Description: Appends a rotation about the Z axis to the current
 //               transform.  The rotation angle is specified in
 //               degrees counterclockwise about the axis.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 add_rotz(double angle) {
+  _is_transform_2d = false;
   _components.push_back(Component(CT_rotz, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 0.0, 1.0));
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_rotate
+//     Function: EggTransform::add_rotate3d
 //       Access: Public
-//  Description: Appends a rotation about an arbitrary axis to the
+//  Description: Appends a 3-d rotation about an arbitrary axis to the
 //               current transform.  The rotation angle is specified
 //               in degrees counterclockwise about the axis.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-add_rotate(double angle, const LVector3d &axis) {
+void EggTransform::
+add_rotate3d(double angle, const LVector3d &axis) {
+  _is_transform_2d = false;
   LVector3d normaxis = normalize(axis);
-  _components.push_back(Component(CT_rotate, angle));
-  _components.back()._vector = new LVector3d(normaxis);
+  _components.push_back(Component(CT_rotate3d, angle));
+  _components.back()._vec3 = new LVecBase3d(normaxis);
   _transform *= LMatrix4d::rotate_mat(angle, normaxis);
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_rotate
+//     Function: EggTransform::add_rotate3d
 //       Access: Public
-//  Description: Appends an arbitrary rotation to the current
+//  Description: Appends an arbitrary 3-d rotation to the current
 //               transform, expressed as a quaternion.  This is
 //               converted to axis-angle notation for the egg file.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-add_rotate(const LQuaterniond &quat) {
-  add_rotate(quat.get_angle(), quat.get_axis());
+void EggTransform::
+add_rotate3d(const LQuaterniond &quat) {
+  _is_transform_2d = false;
+  add_rotate3d(quat.get_angle(), quat.get_axis());
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_scale
+//     Function: EggTransform::add_scale2d
 //       Access: Public
 //  Description: Appends a possibly non-uniform scale to the current
 //               transform.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-add_scale(const LVecBase3d &scale) {
-  _components.push_back(Component(CT_scale));
-  _components.back()._vector = new LVector3d(scale);
+void EggTransform::
+add_scale2d(const LVecBase2d &scale) {
+  _is_transform_2d = false;
+  _components.push_back(Component(CT_scale2d));
+  _components.back()._vec2 = new LVecBase2d(scale);
+  _transform *= LMatrix4d::scale_mat(LVecBase3d(scale[0], scale[1], 1.0));
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::add_scale3d
+//       Access: Public
+//  Description: Appends a possibly non-uniform scale to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+void EggTransform::
+add_scale3d(const LVecBase3d &scale) {
+  _is_transform_2d = false;
+  _components.push_back(Component(CT_scale3d));
+  _components.back()._vec3 = new LVecBase3d(scale);
   _transform *= LMatrix4d::scale_mat(scale);
   transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_uniform_scale
+//     Function: EggTransform::add_uniform_scale
 //       Access: Public
 //  Description: Appends a uniform scale to the current transform.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 add_uniform_scale(double scale) {
   _components.push_back(Component(CT_uniform_scale, scale));
   _transform *= LMatrix4d::scale_mat(scale);
@@ -175,21 +228,31 @@ add_uniform_scale(double scale) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::write
+//     Function: EggTransform::write
 //       Access: Public
 //  Description: Writes the transform to the indicated stream in Egg
 //               format.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 write(ostream &out, int indent_level) const {
   indent(out, indent_level) << "<Transform> {\n";
 
   int num_components = get_num_components();
   for (int i = 0; i < num_components; i++) {
     switch (get_component_type(i)) {
-    case CT_translate:
+    case CT_translate2d:
+      indent(out, indent_level + 2)
+        << "<Translate> { " << get_component_vec2(i) << " }\n";
+      break;
+
+    case CT_translate3d:
+      indent(out, indent_level + 2)
+        << "<Translate> { " << get_component_vec3(i) << " }\n";
+      break;
+
+    case CT_rotate2d:
       indent(out, indent_level + 2)
-        << "<Translate> { " << get_component_vector(i) << " }\n";
+        << "<Rotate> { " << get_component_number(i) << " }\n";
       break;
 
     case CT_rotx:
@@ -207,15 +270,20 @@ write(ostream &out, int indent_level) const {
         << "<RotZ> { " << get_component_number(i) << " }\n";
       break;
 
-    case CT_rotate:
+    case CT_rotate3d:
       indent(out, indent_level + 2)
         << "<Rotate> { " << get_component_number(i) << " " 
-        << get_component_vector(i) << " }\n";
+        << get_component_vec3(i) << " }\n";
+      break;
+
+    case CT_scale2d:
+      indent(out, indent_level + 2)
+        << "<Scale> { " << get_component_vec2(i) << " }\n";
       break;
 
-    case CT_scale:
+    case CT_scale3d:
       indent(out, indent_level + 2)
-        << "<Scale> { " << get_component_vector(i) << " }\n";
+        << "<Scale> { " << get_component_vec3(i) << " }\n";
       break;
 
     case CT_uniform_scale:
@@ -223,9 +291,15 @@ write(ostream &out, int indent_level) const {
         << "<Scale> { " << get_component_number(i) << " }\n";
       break;
 
-    case CT_matrix:
+    case CT_matrix3:
+      indent(out, indent_level + 2) << "<Matrix3> {\n";
+      get_component_mat3(i).write(out, indent_level + 4);
+      indent(out, indent_level + 2) << "}\n";
+      break;
+
+    case CT_matrix4:
       indent(out, indent_level + 2) << "<Matrix4> {\n";
-      get_component_matrix(i).write(out, indent_level + 4);
+      get_component_mat4(i).write(out, indent_level + 4);
       indent(out, indent_level + 2) << "}\n";
       break;
 
@@ -239,39 +313,58 @@ write(ostream &out, int indent_level) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::internal_clear_transform
+//     Function: EggTransform::internal_clear_transform
 //       Access: Public
 //  Description: Resets the transform to empty without calling
 //               transform_changed().
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 internal_clear_transform() {
+  _is_transform_2d = true;
   _components.clear();
   _transform = LMatrix4d::ident_mat();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::internal_add_matrix
+//     Function: EggTransform::internal_add_matrix
+//       Access: Public
+//  Description: Appends an arbitrary 4x4 matrix to the current
+//               transform, without calling transform_changed().
+////////////////////////////////////////////////////////////////////
+void EggTransform::
+internal_add_matrix(const LMatrix3d &mat) {
+  _components.push_back(Component(CT_matrix3));
+  _components.back()._mat3 = new LMatrix3d(mat);
+  LMatrix4d mat4(mat(0, 0), mat(0, 1), 0.0, mat(0, 2),
+                 mat(1, 0), mat(1, 1), 0.0, mat(1, 2),
+                 0.0, 0.0, 1.0, 0.0,
+                 mat(2, 0), mat(2, 1), 0.0, mat(2, 2));
+  _transform *= mat4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform::internal_add_matrix
 //       Access: Public
 //  Description: Appends an arbitrary 4x4 matrix to the current
 //               transform, without calling transform_changed().
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 internal_add_matrix(const LMatrix4d &mat) {
-  _components.push_back(Component(CT_matrix));
-  _components.back()._matrix = new LMatrix4d(mat);
+  _is_transform_2d = false;
+  _components.push_back(Component(CT_matrix4));
+  _components.back()._mat4 = new LMatrix4d(mat);
   _transform *= mat;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::transform_changed
+//     Function: EggTransform::transform_changed
 //       Access: Protected, Virtual
 //  Description: This virtual method is called whenever the transform
 //               is changed; it is intended to provide a hook for
 //               derived classes (e.g. EggGroup) to update their
 //               internal cache appropriately.
 ////////////////////////////////////////////////////////////////////
-void EggTransform3d::
+void EggTransform::
 transform_changed() {
 }
 

+ 48 - 27
panda/src/egg/eggTransform3d.h → panda/src/egg/eggTransform.h

@@ -1,4 +1,4 @@
-// Filename: eggTransform3d.h
+// Filename: eggTransform.h
 // Created by:  drose (21Jun02)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,67 +16,85 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef EGGTRANSFORM3D_H
-#define EGGTRANSFORM3D_H
+#ifndef EGGTRANSFORM_H
+#define EGGTRANSFORM_H
 
 #include "pandabase.h"
 #include "luse.h"
 
 ////////////////////////////////////////////////////////////////////
-//       Class : EggTransform3d
+//       Class : EggTransform
 // Description : This represents the <Transform> entry of a group
-//               node: a list of component transform operations,
-//               applied in order, that describe a net transform
-//               matrix.  This is a 3-d transform, and therefore
-//               computes a 4x4 matrix.
+//               or texture node: a list of component transform
+//               operations, applied in order, that describe a net
+//               transform matrix.  
+//
+//               This may be either a 3-d transform, and therefore
+//               described by a 4x4 matrix, or a 2-d transform,
+//               described by a 3x3 matrix.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEGG EggTransform3d {
+class EXPCL_PANDAEGG EggTransform {
 PUBLISHED:
-  EggTransform3d();
-  EggTransform3d(const EggTransform3d &copy);
-  EggTransform3d &operator = (const EggTransform3d &copy);
-  virtual ~EggTransform3d();
+  EggTransform();
+  EggTransform(const EggTransform &copy);
+  EggTransform &operator = (const EggTransform &copy);
+  virtual ~EggTransform();
 
   INLINE void clear_transform();
 
-  void add_translate(const LVector3d &translate);
+  void add_translate2d(const LVector2d &translate);
+  void add_translate3d(const LVector3d &translate);
+  void add_rotate2d(double angle);
   void add_rotx(double angle); 
   void add_roty(double angle); 
   void add_rotz(double angle); 
-  void add_rotate(double angle, const LVector3d &axis);
-  void add_rotate(const LQuaterniond &quat);
-  void add_scale(const LVecBase3d &scale);
+  void add_rotate3d(double angle, const LVector3d &axis);
+  void add_rotate3d(const LQuaterniond &quat);
+  void add_scale2d(const LVecBase2d &scale);
+  void add_scale3d(const LVecBase3d &scale);
   void add_uniform_scale(double scale);
-  INLINE void add_matrix(const LMatrix4d &mat);
+  INLINE void add_matrix3(const LMatrix3d &mat);
+  INLINE void add_matrix4(const LMatrix4d &mat);
 
   INLINE bool has_transform() const;
+  INLINE bool is_transform_2d() const;
+  INLINE void set_transform_2d(const LMatrix3d &mat);
   INLINE void set_transform(const LMatrix4d &mat);
+  INLINE LMatrix3d get_transform_2d() const;
   INLINE const LMatrix4d &get_transform() const;
   INLINE bool transform_is_identity() const;
 
   enum ComponentType {
     CT_invalid,
-    CT_translate,
+    CT_translate2d,
+    CT_translate3d,
+    CT_rotate2d,
     CT_rotx,
     CT_roty,
     CT_rotz,
-    CT_rotate,
-    CT_scale,
+    CT_rotate3d,
+    CT_scale2d,
+    CT_scale3d,
     CT_uniform_scale,
-    CT_matrix
+    CT_matrix3,
+    CT_matrix4
   };
 
   INLINE int get_num_components() const;
   INLINE ComponentType get_component_type(int n) const;
   INLINE double get_component_number(int n) const;
-  INLINE const LVector3d &get_component_vector(int n) const;
-  INLINE const LMatrix4d &get_component_matrix(int n) const;
+  INLINE const LVecBase2d &get_component_vec2(int n) const;
+  INLINE const LVecBase3d &get_component_vec3(int n) const;
+  INLINE const LMatrix3d &get_component_mat3(int n) const;
+  INLINE const LMatrix4d &get_component_mat4(int n) const;
 
   void write(ostream &out, int indent_level) const;
 
 protected:
   void internal_clear_transform();
+  void internal_add_matrix(const LMatrix3d &mat);
   void internal_add_matrix(const LMatrix4d &mat);
+  INLINE void internal_set_transform(const LMatrix3d &mat);
   INLINE void internal_set_transform(const LMatrix4d &mat);
 
   virtual void transform_changed();
@@ -91,15 +109,18 @@ private:
 
     ComponentType _type;
     double _number;
-    LVector3d *_vector;
-    LMatrix4d *_matrix;
+    LVecBase2d *_vec2;
+    LVecBase3d *_vec3;
+    LMatrix3d *_mat3;
+    LMatrix4d *_mat4;
   };
 
+  bool _is_transform_2d;
   typedef pvector<Component> Components;
   Components _components;
   LMatrix4d _transform;
 };
 
-#include "eggTransform3d.I"
+#include "eggTransform.I"
 
 #endif

+ 0 - 240
panda/src/egg/eggTransform3d.I

@@ -1,240 +0,0 @@
-// Filename: eggTransform3d.I
-// Created by:  drose (21Jun02)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Component::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE EggTransform3d::Component::
-Component(EggTransform3d::ComponentType type, double number) :
-  _type(type),
-  _number(number)
-{
-  _vector = (LVector3d *)NULL;
-  _matrix = (LMatrix4d *)NULL;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Component::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE EggTransform3d::Component::
-Component(const EggTransform3d::Component &copy) :
-  _type(copy._type),
-  _number(copy._number)
-{
-  _vector = (LVector3d *)NULL;
-  _matrix = (LMatrix4d *)NULL;
-  if (copy._vector != (LVector3d *)NULL) {
-    _vector = new LVector3d(*copy._vector);
-  }
-  if (copy._matrix != (LMatrix4d *)NULL) {
-    _matrix = new LMatrix4d(*copy._matrix);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Component::Copy Assignment Operator
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void EggTransform3d::Component::
-operator = (const EggTransform3d::Component &copy) {
-  _type = copy._type;
-  _number = copy._number;
-  if (_vector != (LVector3d *)NULL) {
-    delete _vector;
-    _vector = (LVector3d *)NULL;
-  }
-  if (_matrix != (LMatrix4d *)NULL) {
-    delete _matrix;
-    _matrix = (LMatrix4d *)NULL;
-  }
-  if (copy._vector != (LVector3d *)NULL) {
-    _vector = new LVector3d(*copy._vector);
-  }
-  if (copy._matrix != (LMatrix4d *)NULL) {
-    _matrix = new LMatrix4d(*copy._matrix);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::Component::Destructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE EggTransform3d::Component::
-~Component() {
-  if (_vector != (LVector3d *)NULL) {
-    delete _vector;
-  }
-  if (_matrix != (LMatrix4d *)NULL) {
-    delete _matrix;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::clear_transform
-//       Access: Public
-//  Description: Resets the transform to empty, identity.
-////////////////////////////////////////////////////////////////////
-INLINE void EggTransform3d::
-clear_transform() {
-  internal_clear_transform();
-  transform_changed();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_matrix
-//       Access: Public
-//  Description: Appends an arbitrary 4x4 matrix to the current
-//               transform.
-////////////////////////////////////////////////////////////////////
-INLINE void EggTransform3d::
-add_matrix(const LMatrix4d &mat) {
-  internal_add_matrix(mat);
-  transform_changed();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::has_transform
-//       Access: Public
-//  Description: Returns true if the transform is nonempty, false if
-//               it is empty (no transform components have been
-//               added).
-////////////////////////////////////////////////////////////////////
-INLINE bool EggTransform3d::
-has_transform() const {
-  return !_components.empty();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::set_transform
-//       Access: Public
-//  Description: Sets the overall transform as a 4x4 matrix.  This
-//               completely replaces whatever componentwise transform
-//               may have been defined.
-////////////////////////////////////////////////////////////////////
-INLINE void EggTransform3d::
-set_transform(const LMatrix4d &mat) {
-  internal_set_transform(mat);
-  transform_changed();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_transform
-//       Access: Public
-//  Description: Returns the overall transform as a 4x4 matrix.
-////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4d &EggTransform3d::
-get_transform() const {
-  return _transform;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::transform_is_identity
-//       Access: Public
-//  Description: Returns true if the described transform is identity,
-//               false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool EggTransform3d::
-transform_is_identity() const {
-  return _components.empty() ||
-    _transform.almost_equal(LMatrix4d::ident_mat(), 0.0001);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_num_components
-//       Access: Public
-//  Description: Returns the number of components that make up the
-//               transform.
-////////////////////////////////////////////////////////////////////
-INLINE int EggTransform3d::
-get_num_components() const {
-  return _components.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_component_type
-//       Access: Public
-//  Description: Returns the type of the nth component.
-////////////////////////////////////////////////////////////////////
-INLINE EggTransform3d::ComponentType EggTransform3d::
-get_component_type(int n) const {
-  nassertr(n >= 0 && n < (int)_components.size(), CT_invalid);
-  return _components[n]._type;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_component_number
-//       Access: Public
-//  Description: Returns the solitary number associated with the nth
-//               component.  In the case of a rotation, this is the
-//               angle in degrees to rotate; in the case of uniform
-//               scale, this is the amount of the scale.  Other types
-//               do not use this property.
-////////////////////////////////////////////////////////////////////
-INLINE double EggTransform3d::
-get_component_number(int n) const {
-  nassertr(n >= 0 && n < (int)_components.size(), 0.0);
-  return _components[n]._number;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_component_vector
-//       Access: Public
-//  Description: Returns the 3-component vector associated with the
-//               nth component.  This may be the translate vector,
-//               rotate axis, or non-uniform scale.  It is an error to
-//               call this if the component type does not use a vector
-//               property.
-////////////////////////////////////////////////////////////////////
-INLINE const LVector3d &EggTransform3d::
-get_component_vector(int n) const {
-  nassertr(n >= 0 && n < (int)_components.size(), LVector3d::zero());
-  nassertr(_components[n]._vector != (LVector3d *)NULL, LVector3d::zero());
-  return *_components[n]._vector;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::get_component_matrix
-//       Access: Public
-//  Description: Returns the 4x4 matrix associated with the nth
-//               component.  It is an error to call this if the
-//               component type is not CT_matrix.
-////////////////////////////////////////////////////////////////////
-INLINE const LMatrix4d &EggTransform3d::
-get_component_matrix(int n) const {
-  nassertr(n >= 0 && n < (int)_components.size(), LMatrix4d::ident_mat());
-  nassertr(_components[n]._matrix != (LMatrix4d *)NULL, LMatrix4d::ident_mat());
-  return *_components[n]._matrix;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::internal_set_transform
-//       Access: Protected
-//  Description: Sets the overall transform without calling
-//               transform_changed().
-////////////////////////////////////////////////////////////////////
-INLINE void EggTransform3d::
-internal_set_transform(const LMatrix4d &mat) {
-  internal_clear_transform();
-  internal_add_matrix(mat);
-}

+ 1 - 1
panda/src/egg/eggVertex.I

@@ -211,7 +211,7 @@ has_uv() const {
 //               multitexturing; see get_uv(name) for the interface
 //               that supports multitexturing.
 ////////////////////////////////////////////////////////////////////
-INLINE const TexCoordd &EggVertex::
+INLINE TexCoordd EggVertex::
 get_uv() const {
   nassertr(has_uv(), TexCoordd::zero());
   return get_uv("");

+ 62 - 4
panda/src/egg/eggVertex.cxx

@@ -117,12 +117,34 @@ EggVertex::
 //     Function: EggVertex::has_uv
 //       Access: Published
 //  Description: Returns true if the vertex has the named UV
-//               coordinate pair, false otherwise.
+//               coordinate pair, and the named UV coordinate pair is
+//               2-d, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool EggVertex::
 has_uv(const string &name) const {
   UVMap::const_iterator ui = _uv_map.find(name);
-  return (ui != _uv_map.end());
+  if (ui != _uv_map.end()) {
+    EggVertexUV *uv_obj = (*ui).second;
+    return !uv_obj->has_w();
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertex::has_uvw
+//       Access: Published
+//  Description: Returns true if the vertex has the named UV
+//               coordinate triple, and the named UV coordinate triple is
+//               3-d, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggVertex::
+has_uvw(const string &name) const {
+  UVMap::const_iterator ui = _uv_map.find(name);
+  if (ui != _uv_map.end()) {
+    EggVertexUV *uv_obj = (*ui).second;
+    return uv_obj->has_w();
+  }
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -132,13 +154,27 @@ has_uv(const string &name) const {
 //               vertex.  It is an error to call this if has_uv(name)
 //               returned false.
 ////////////////////////////////////////////////////////////////////
-const TexCoordd &EggVertex::
+TexCoordd EggVertex::
 get_uv(const string &name) const {
   UVMap::const_iterator ui = _uv_map.find(name);
   nassertr(ui != _uv_map.end(), TexCoordd::zero());
   return (*ui).second->get_uv();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertex::get_uvw
+//       Access: Published
+//  Description: Returns the named UV coordinate triple on the vertex.
+//               vertex.  It is an error to call this if has_uvw(name)
+//               returned false.
+////////////////////////////////////////////////////////////////////
+const TexCoord3d &EggVertex::
+get_uvw(const string &name) const {
+  UVMap::const_iterator ui = _uv_map.find(name);
+  nassertr(ui != _uv_map.end(), TexCoord3d::zero());
+  return (*ui).second->get_uvw();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggVertex::set_uv
 //       Access: Published
@@ -160,6 +196,28 @@ set_uv(const string &name, const TexCoordd &uv) {
   nassertv(get_uv(name) == uv);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertex::set_uvw
+//       Access: Published
+//  Description: Sets the indicated UV coordinate triple on the vertex.
+//               This replaces any UV coordinate pair or triple with
+//               the same name already on the vertex, but preserves UV
+//               morphs.
+////////////////////////////////////////////////////////////////////
+void EggVertex::
+set_uvw(const string &name, const TexCoord3d &uvw) {
+  PT(EggVertexUV) &uv_obj = _uv_map[name];
+
+  if (uv_obj.is_null()) {
+    uv_obj = new EggVertexUV(name, uvw);
+  } else {
+    uv_obj = new EggVertexUV(*uv_obj);
+    uv_obj->set_uvw(uvw);
+  }
+
+  nassertv(get_uvw(name) == uvw);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggVertex::get_uv_obj
 //       Access: Published
@@ -257,7 +315,7 @@ write(ostream &out, int indent_level) const {
 
   EggAttributes::write(out, indent_level+2);
 
-  _dxyzs.write(out, indent_level+2);
+  _dxyzs.write(out, indent_level + 2, "<Dxyz>", 3);
 
   // If the vertex is referenced by one or more groups, write that as
   // a helpful comment.

+ 5 - 2
panda/src/egg/eggVertex.h

@@ -82,12 +82,15 @@ PUBLISHED:
   INLINE LPoint4d get_pos4() const;
 
   INLINE bool has_uv() const;
-  INLINE const TexCoordd &get_uv() const;
+  INLINE TexCoordd get_uv() const;
   INLINE void set_uv(const TexCoordd &texCoord);
   INLINE void clear_uv();
   bool has_uv(const string &name) const;
-  const TexCoordd &get_uv(const string &name) const;
+  bool has_uvw(const string &name) const;
+  TexCoordd get_uv(const string &name) const;
+  const TexCoord3d &get_uvw(const string &name) const;
   void set_uv(const string &name, const TexCoordd &texCoord);
+  void set_uvw(const string &name, const TexCoord3d &texCoord);
   EggVertexUV *get_uv_obj(const string &name) const;
   void set_uv_obj(EggVertexUV *vertex_uv);
   void clear_uv(const string &name);

+ 15 - 6
panda/src/egg/eggVertexPool.cxx

@@ -295,14 +295,17 @@ has_uvs() const {
 //     Function: EggVertexPool::get_uv_names
 //       Access: Public
 //  Description: Returns the list of UV names that are defined by any
-//               vertices in the pool.  Also returns the subset of UV
-//               names that define the tangent and binormal.  It is
-//               the user's responsibility to clear both vectors
-//               before calling this method.
+//               vertices in the pool, as well as the subset of UV
+//               names that actually define 3-d texture coordinates
+//               ("uvw_names").  Also returns the subset of UV/UVW
+//               names that define a tangent and binormal.  It is the
+//               user's responsibility to clear both vectors before
+//               calling this method.
 ////////////////////////////////////////////////////////////////////
 void EggVertexPool::
-get_uv_names(vector_string &uv_names, vector_string &tbn_names) const {
-  pset<string> uv_names_set, tbn_names_set;
+get_uv_names(vector_string &uv_names, vector_string &uvw_names, 
+             vector_string &tbn_names) const {
+  pset<string> uv_names_set, uvw_names_set, tbn_names_set;
   IndexVertices::const_iterator ivi;
   for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
     EggVertex *vertex = (*ivi).second;
@@ -310,6 +313,9 @@ get_uv_names(vector_string &uv_names, vector_string &tbn_names) const {
     for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
       EggVertexUV *uv_obj = (*uvi);
       uv_names_set.insert(uv_obj->get_name());
+      if (uv_obj->has_w()) {
+        uvw_names_set.insert(uv_obj->get_name());
+      }
       if (uv_obj->has_tangent() && uv_obj->has_binormal()) {
         tbn_names_set.insert(uv_obj->get_name());
       }
@@ -320,6 +326,9 @@ get_uv_names(vector_string &uv_names, vector_string &tbn_names) const {
   for (si = uv_names_set.begin(); si != uv_names_set.end(); ++si) {
     uv_names.push_back(*si);
   }
+  for (si = uvw_names_set.begin(); si != uvw_names_set.end(); ++si) {
+    uvw_names.push_back(*si);
+  }
   for (si = tbn_names_set.begin(); si != tbn_names_set.end(); ++si) {
     tbn_names.push_back(*si);
   }

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

@@ -98,7 +98,8 @@ PUBLISHED:
   bool has_colors() const;
   bool has_nonwhite_colors() const;
   bool has_uvs() const;
-  void get_uv_names(vector_string &uv_names, vector_string &tbn_names) const;
+  void get_uv_names(vector_string &uv_names, vector_string &uvw_names, 
+                    vector_string &tbn_names) const;
 
 public:
   // Can be used to traverse all the vertices in index number order.

+ 73 - 5
panda/src/egg/eggVertexUV.I

@@ -17,24 +17,92 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::set_name
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggVertexUV::
+set_name(const string &name) {
+  if (name == "default") {
+    clear_name();
+  } else {
+    Namable::set_name(name);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::get_num_dimensions
+//       Access: Published
+//  Description: Returns the number of components of the texture
+//               coordinate set.  This is either 2 (the normal case)
+//               or 3 (for a 3-d texture coordinate).
+////////////////////////////////////////////////////////////////////
+INLINE int EggVertexUV::
+get_num_dimensions() const {
+  return has_w() ? 3 : 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::has_w
+//       Access: Published
+//  Description: Returns true if the texture coordinate has a third, w
+//               component, false if it is just a normal 2-d texture
+//               coordinate.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggVertexUV::
+has_w() const {
+  return (_flags & F_has_w) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggVertexUV::get_uv
 //       Access: Published
-//  Description: Returns the texture coordinate pair.
+//  Description: Returns the texture coordinate pair, if
+//               get_num_dimensions() is 2.
 ////////////////////////////////////////////////////////////////////
-INLINE const TexCoordd &EggVertexUV::
+INLINE TexCoordd EggVertexUV::
 get_uv() const {
-  return _uv;
+  nassertr(!has_w(), TexCoordd::zero());
+  return TexCoordd(_uvw[0], _uvw[1]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::get_uvw
+//       Access: Published
+//  Description: Returns the texture coordinate triple, if
+//               get_num_dimensions() is 3.  This is also legal to
+//               call if get_num_dimensions() is 2 (but the last
+//               dimension will be zero).
+////////////////////////////////////////////////////////////////////
+INLINE const TexCoord3d &EggVertexUV::
+get_uvw() const {
+  return _uvw;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggVertexUV::set_uv
 //       Access: Published
-//  Description: Sets the texture coordinate pair.
+//  Description: Sets the texture coordinate pair.  This makes the
+//               texture coordinate a 2-d texture coordinate, which is
+//               the usual case.
 ////////////////////////////////////////////////////////////////////
 INLINE void EggVertexUV::
 set_uv(const TexCoordd &uv) {
-  _uv = uv;
+  _uvw.set(uv[0], uv[1], 0.0);
+  _flags &= ~F_has_w;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::set_uvw
+//       Access: Published
+//  Description: Sets the texture coordinate triple.  This makes the
+//               texture coordinate a 3-d texture coordinate.
+////////////////////////////////////////////////////////////////////
+INLINE void EggVertexUV::
+set_uvw(const TexCoord3d &uvw) {
+  _uvw = uvw;
+  _flags |= F_has_w;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 37 - 9
panda/src/egg/eggVertexUV.cxx

@@ -32,8 +32,27 @@ EggVertexUV::
 EggVertexUV(const string &name, const TexCoordd &uv) :
   EggNamedObject(name),
   _flags(0),
-  _uv(uv)
+  _uvw(uv[0], uv[1], 0.0)
 {
+  if (get_name() == "default") {
+    clear_name();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexUV::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggVertexUV::
+EggVertexUV(const string &name, const TexCoord3d &uvw) :
+  EggNamedObject(name),
+  _flags(F_has_w),
+  _uvw(uvw)
+{
+  if (get_name() == "default") {
+    clear_name();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,7 +67,7 @@ EggVertexUV(const EggVertexUV &copy) :
   _flags(copy._flags),
   _tangent(copy._tangent),
   _binormal(copy._binormal),
-  _uv(copy._uv)
+  _uvw(copy._uvw)
 {
 }
 
@@ -64,7 +83,7 @@ operator = (const EggVertexUV &copy) {
   _flags = copy._flags;
   _tangent = copy._tangent;
   _binormal = copy._binormal;
-  _uv = copy._uv;
+  _uvw = copy._uvw;
 
   return (*this);
 }
@@ -109,12 +128,21 @@ write(ostream &out, int indent_level) const {
     inline_name += ' ';
   }
 
-  if (_duvs.empty() && _flags == 0) {
-    indent(out, indent_level)
-      << "<UV> " << inline_name << "{ " << get_uv() << " }\n";
+  if (_duvs.empty() && (_flags & ~F_has_w) == 0) {
+    if (has_w()) {
+      indent(out, indent_level)
+        << "<UV> " << inline_name << "{ " << get_uvw() << " }\n";
+    } else {
+      indent(out, indent_level)
+        << "<UV> " << inline_name << "{ " << get_uv() << " }\n";
+    }
   } else {
     indent(out, indent_level) << "<UV> " << inline_name << "{\n";
-    indent(out, indent_level+2) << get_uv() << "\n";
+    if (has_w()) {
+      indent(out, indent_level+2) << get_uvw() << "\n";
+    } else {
+      indent(out, indent_level+2) << get_uv() << "\n";
+    }
     if (has_tangent()) {
       indent(out, indent_level + 2)
         << "<Tangent> { " << get_tangent() << " }\n";
@@ -123,7 +151,7 @@ write(ostream &out, int indent_level) const {
       indent(out, indent_level + 2)
         << "<Binormal> { " << get_binormal() << " }\n";
     }
-    _duvs.write(out, indent_level+2);
+    _duvs.write(out, indent_level + 2, "<Duv>", get_num_dimensions());
     indent(out, indent_level) << "}\n";
   }
 }
@@ -141,7 +169,7 @@ compare_to(const EggVertexUV &other) const {
     return _flags - other._flags;
   }
   int compare;
-  compare = _uv.compare_to(other._uv, egg_parameters->_uv_threshold);
+  compare = _uvw.compare_to(other._uvw, egg_parameters->_uv_threshold);
   if (compare != 0) {
     return compare;
   }

+ 10 - 2
panda/src/egg/eggVertexUV.h

@@ -36,12 +36,19 @@
 class EXPCL_PANDAEGG EggVertexUV : public EggNamedObject {
 PUBLISHED:
   EggVertexUV(const string &name, const TexCoordd &uv);
+  EggVertexUV(const string &name, const TexCoord3d &uvw);
   EggVertexUV(const EggVertexUV &copy);
   EggVertexUV &operator = (const EggVertexUV &copy);
   virtual ~EggVertexUV();
 
-  INLINE const TexCoordd &get_uv() const;
+  INLINE void set_name(const string &name);
+
+  INLINE int get_num_dimensions() const;
+  INLINE bool has_w() const;
+  INLINE TexCoordd get_uv() const;
+  INLINE const TexCoord3d &get_uvw() const;
   INLINE void set_uv(const TexCoordd &texCoord);
+  INLINE void set_uvw(const TexCoord3d &texCoord);
 
   INLINE bool has_tangent() const;
   INLINE const Normald &get_tangent() const;
@@ -64,12 +71,13 @@ private:
   enum Flags {
     F_has_tangent   = 0x001,
     F_has_binormal  = 0x002,
+    F_has_w         = 0x004,
   };
 
   int _flags;
   Normald _tangent;
   Normald _binormal;
-  TexCoordd _uv;
+  TexCoord3d _uvw;
 
 public:
   static TypeHandle get_class_type() {

+ 1 - 1
panda/src/egg/egg_composite2.cxx

@@ -12,7 +12,7 @@
 #include "eggTable.cxx"
 #include "eggTexture.cxx"
 #include "eggTextureCollection.cxx"
-#include "eggTransform3d.cxx"
+#include "eggTransform.cxx"
 #include "eggTriangleFan.cxx"
 #include "eggTriangleStrip.cxx"
 #include "eggUserData.cxx"

+ 2944 - 2965
panda/src/egg/lexer.cxx.prebuilt

@@ -1,2965 +1,2944 @@
-#define yy_create_buffer eggyy_create_buffer
-#define yy_delete_buffer eggyy_delete_buffer
-#define yy_scan_buffer eggyy_scan_buffer
-#define yy_scan_string eggyy_scan_string
-#define yy_scan_bytes eggyy_scan_bytes
-#define yy_flex_debug eggyy_flex_debug
-#define yy_init_buffer eggyy_init_buffer
-#define yy_flush_buffer eggyy_flush_buffer
-#define yy_load_buffer_state eggyy_load_buffer_state
-#define yy_switch_to_buffer eggyy_switch_to_buffer
-#define yyin eggyyin
-#define yyleng eggyyleng
-#define yylex eggyylex
-#define yyout eggyyout
-#define yyrestart eggyyrestart
-#define yytext eggyytext
-#define yywrap eggyywrap
-
-#line 20 "lex.yy.c"
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header$
- */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-
-#include <stdio.h>
-#include <errno.h>
-
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
-#endif
-#endif
-
-
-#ifdef __cplusplus
-
-#include <stdlib.h>
-#ifndef _WIN32
-#endif
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else	/* ! __cplusplus */
-
-#if __STDC__
-
-#define YY_USE_PROTOS
-#define YY_USE_CONST
-
-#endif	/* __STDC__ */
-#endif	/* ! __cplusplus */
-
-#ifdef __TURBOC__
- #pragma warn -rch
- #pragma warn -use
-#include <io.h>
-#include <stdlib.h>
-#define YY_USE_CONST
-#define YY_USE_PROTOS
-#endif
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#define YY_BUF_SIZE 16384
-
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-
-extern int yyleng;
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator).  This
- * avoids problems with code like:
- *
- * 	if ( condition_holds )
- *		yyless( 5 );
- *	else
- *		do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
-#define yyless(n) \
-	do \
-		{ \
-		/* Undo effects of setting up yytext. */ \
-		*yy_cp = yy_hold_char; \
-		YY_RESTORE_YY_MORE_OFFSET \
-		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
-		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-		} \
-	while ( 0 )
-
-#define unput(c) yyunput( c, yytext_ptr )
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-typedef unsigned int yy_size_t;
-
-
-struct yy_buffer_state
-	{
-	FILE *yy_input_file;
-
-	char *yy_ch_buf;		/* input buffer */
-	char *yy_buf_pos;		/* current position in input buffer */
-
-	/* Size of input buffer in bytes, not including room for EOB
-	 * characters.
-	 */
-	yy_size_t yy_buf_size;
-
-	/* Number of characters read into yy_ch_buf, not including EOB
-	 * characters.
-	 */
-	int yy_n_chars;
-
-	/* Whether we "own" the buffer - i.e., we know we created it,
-	 * and can realloc() it to grow it, and should free() it to
-	 * delete it.
-	 */
-	int yy_is_our_buffer;
-
-	/* Whether this is an "interactive" input source; if so, and
-	 * if we're using stdio for input, then we want to use getc()
-	 * instead of fread(), to make sure we stop fetching input after
-	 * each newline.
-	 */
-	int yy_is_interactive;
-
-	/* Whether we're considered to be at the beginning of a line.
-	 * If so, '^' rules will be active on the next match, otherwise
-	 * not.
-	 */
-	int yy_at_bol;
-
-	/* Whether to try to fill the input buffer when we reach the
-	 * end of it.
-	 */
-	int yy_fill_buffer;
-
-	int yy_buffer_status;
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-	/* When an EOF's been seen but there's still some text to process
-	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-	 * shouldn't try reading from the input source any more.  We might
-	 * still have a bunch of tokens to match, though, because of
-	 * possible backing-up.
-	 *
-	 * When we actually see the EOF, we change the status to "new"
-	 * (via yyrestart()), so that the user can continue scanning by
-	 * just pointing yyin at a new input file.
-	 */
-#define YY_BUFFER_EOF_PENDING 2
-	};
-
-static YY_BUFFER_STATE yy_current_buffer = 0;
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- */
-#define YY_CURRENT_BUFFER yy_current_buffer
-
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-
-static int yy_n_chars;		/* number of characters read into yy_ch_buf */
-
-
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1;		/* whether we need to initialize */
-static int yy_start = 0;	/* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin.  A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart YY_PROTO(( FILE *input_file ));
-
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
-
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
-
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
-static void yy_flex_free YY_PROTO(( void * ));
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
-	{ \
-	if ( ! yy_current_buffer ) \
-		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-	yy_current_buffer->yy_is_interactive = is_interactive; \
-	}
-
-#define yy_set_bol(at_bol) \
-	{ \
-	if ( ! yy_current_buffer ) \
-		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-	yy_current_buffer->yy_at_bol = at_bol; \
-	}
-
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-typedef int yy_state_type;
-extern char *yytext;
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-	yytext_ptr = yy_bp; \
-	yyleng = (int) (yy_cp - yy_bp); \
-	yy_hold_char = *yy_cp; \
-	*yy_cp = '\0'; \
-	yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 98
-#define YY_END_OF_BUFFER 99
-static yyconst short int yy_accept[557] =
-    {   0,
-        0,    0,   99,   97,    2,    1,   96,   97,   97,   97,
-       97,   90,   90,   97,   97,   97,    5,   97,    1,   97,
-       90,   97,   90,    4,    3,   90,   92,   97,   91,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,    3,    3,   92,   97,   90,   91,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       66,   97,   97,   97,   94,   97,   95,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   18,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   32,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   81,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   24,   97,   97,   97,   97,
-
-       22,   97,   97,   97,   97,   97,   31,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   52,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   67,   97,   97,   97,
-       97,   97,   97,   97,   97,   78,   97,   97,   97,   97,
-       97,   97,   93,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   19,   97,   97,   97,   97,   23,
-       97,   28,   97,   97,   97,   97,   97,   97,   37,   38,
-       97,   97,   97,   43,   97,   97,   97,   97,   97,   97,
-       97,   53,   97,   55,   56,   57,   97,   97,   97,   97,
-
-       97,   97,   97,   97,   97,   97,   97,   97,   74,   97,
-       77,   97,   97,   97,   97,   97,   97,   93,   97,    7,
-       97,   97,   97,   12,   97,   97,   97,   97,   97,   97,
-       97,   21,   26,   97,   97,   30,   97,   97,   33,   34,
-       97,   97,   42,   97,   97,   97,   97,   48,   97,   97,
-       97,   97,   97,   97,   60,   97,   97,   97,   65,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   11,   13,   97,   97,   97,
-       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-       44,   97,   97,   97,   97,   97,   97,   54,   58,   59,
-
-       97,   97,   63,   97,   97,   97,   97,   97,   97,   97,
-       97,   97,   97,   97,   97,   84,   97,   97,   97,   97,
-       97,   97,   97,   14,   15,   97,   97,   97,   20,   97,
-       97,   35,   97,   97,   40,   41,   97,   97,   97,   97,
-       97,   51,   97,   62,   97,   68,   69,   70,   97,   97,
-       97,   97,   79,   80,   82,   83,   97,   97,   97,   97,
-       97,   97,   10,   97,   97,   25,   97,   97,   36,   39,
-       97,   97,   97,   97,   97,   61,   97,   71,   97,   97,
-       97,   97,   97,   97,   97,   88,   97,   97,    8,   97,
-       16,   97,   97,   97,   97,   97,   97,   97,   97,   97,
-
-       72,   73,   97,   97,   97,   97,   87,   97,   97,   97,
-       97,   97,   29,   45,   97,   47,   49,   50,   97,   97,
-       97,   85,   86,   97,    6,   97,   97,   97,   97,   97,
-       75,   97,   89,   97,   97,   97,   46,   97,   97,   97,
-       97,   97,   97,   76,   97,   97,   97,   97,    9,   97,
-       97,   64,   17,   97,   27,    0
-    } ;
-
-static yyconst int yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    1,    4,    1,    5,    1,    1,    1,    1,
-        1,    6,    7,    1,    8,    9,   10,   11,   12,   13,
-       14,   15,   13,   13,   13,   13,   13,    1,    1,   16,
-        1,   17,    1,    1,   19,   20,   21,   22,   23,   24,
-       25,   26,   27,   28,   29,   30,   31,   32,   33,   34,
-       35,   36,   37,   38,   39,   40,   41,   42,   43,   44,
-        1,    1,    1,    1,   18,    1,   19,   20,   21,   22,
-
-       23,   24,   25,   26,   27,   28,   29,   30,   31,   32,
-       33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
-       43,   44,   45,    1,   45,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1
-    } ;
-
-static yyconst int yy_meta[46] =
-    {   0,
-        1,    2,    3,    2,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    2
-    } ;
-
-static yyconst short int yy_base[562] =
-    {   0,
-        0,   44,  663,    0,  664,    0,  664,    8,   81,   22,
-       18,  100,   19,  123,  630,  642,  664,    0,    0,   29,
-       30,  628,   51,    0,   65,   68,   14,  159,  164,   61,
-       91,  170,   43,  623,  631,  625,  623,  623,   70,   68,
-       66,   86,  621,   93,  175,  181,  128,  111,  629,  628,
-      619,  626,  136,    0,   18,  207,  213,    0,  605,  629,
-       45,  615,  627,  612,  102,  627,  607,  605,  604,  607,
-      614,  602,  597,  593,  603,  604,  595,  599,  597,  173,
-      603,  596,  596,  594,  588,  603,  601,  587,  586,  593,
-      598,  581,  100,  594,  597,  578,  596,  595,  578,  593,
-
-      584,  209,  568,  586,  176,  570,  578,  577,  588,  575,
-        0,  574,  566,  570,    0,  589,    0,  572,  577,  567,
-      563,  573,  558,  556,  562,  199,  555,    0,  552,  572,
-      550,  551,  566,  562,  567,  539,  563,  558,  562,  540,
-      561,    0,  547,  538,  543,  536,  550,  538,  146,  548,
-      546,  538,  548,  544,  543,  527,  532,  520,  545,  542,
-      195,  528,  529,  519,  535,  518,  525,  537,  528,   48,
-      520,  519,  526,  174,  532,  516,  515,    0,  514,  513,
-      506,  538,  500,  518,  517,  519,  502,  507,  530,  512,
-      507,  510,  499,  509,  513,    0,  510,  497,  508,  502,
-
-        0,  508,  493,  506,  496,  487,    0,  481,  500,  480,
-      480,  499,  498,  478,  486,  482,  494,  491,  472,  487,
-      471,  487,  467,  479,    0,  486,  464,  484,  483,  482,
-      471,   79,  474,  469,  474,  471,    0,  470,  465,  452,
-      465,  452,  471,  455,  469,    0,  452,  451,  450,  449,
-      458,  461,  231,  443,  461,  444,  445,  452,  457,  451,
-      450,  439,  438,  442,    0,  436,  448,  449,  448,    0,
-      437,    0,  440,  445,  439,  428,  442,  441,    0,    0,
-      430,  414,  438,    0,  424,  194,  415,  435,  419,  420,
-      416,    0,  425,    0,    0,    0,  416,  410,  428,  412,
-
-      411,  416,  424,  408,  402,  402,  399,  134,    0,  411,
-        0,  397,  396,  395,  394,  389,  398,    0,  408,    0,
-      409,  408,  409,    0,  408,  401,  385,  399,  389,  399,
-      389,    0,    0,  397,  398,    0,  393,  394,    0,    0,
-      395,  221,    0,  396,  373,  372,  372,    0,  384,  381,
-      375,  389,  388,  387,    0,  382,  377,  120,    0,  363,
-      362,  376,  372,  364,  377,  365,  357,  356,  355,  354,
-      230,  363,  350,  352,  357,    0,    0,  369,  368,  352,
-      364,  359,  364,  340,  357,  361,  354,  346,  358,  357,
-        0,  337,  336,  328,  347,  344,  351,    0,    0,    0,
-
-      344,  349,    0,  332,  347,  346,  345,  324,  324,  321,
-      335,  340,  339,  338,  337,    0,  321,  319,  328,  319,
-      313,  326,  330,    0,    0,  308,  307,  327,    0,  320,
-      319,    0,  324,  323,    0,    0,  299,  314,  303,  304,
-      309,    0,  317,    0,  301,    0,    0,    0,  315,  300,
-      307,  224,    0,    0,    0,    0,  302,  295,  303,  239,
-      286,  241,    0,  308,  301,    0,  287,  286,    0,    0,
-      298,  301,  296,  280,  279,    0,  294,    0,  298,  297,
-      294,  274,  280,  280,  292,    0,  271,  284,    0,  283,
-        0,  268,  266,  286,  285,  280,  283,  282,  281,  270,
-
-        0,    0,  264,  259,  277,  276,    0,  287,  274,  258,
-      246,  265,    0,    0,  264,    0,    0,    0,  248,  268,
-      257,    0,    0,  266,    0,  244,  244,  238,  262,  251,
-        0,  243,    0,  253,  227,  229,    0,  227,  242,  204,
-      209,  174,  160,    0,  122,   76,   35,   32,    0,   21,
-        1,    0,    0,    1,    0,  664,  266,    0,  269,  271,
-      273
-    } ;
-
-static yyconst short int yy_def[562] =
-    {   0,
-      557,  557,  556,  558,  556,  559,  556,  558,  558,  558,
-      558,  558,   12,  558,  558,  558,  556,  558,  559,  558,
-       12,  558,  558,  558,  560,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  560,  561,  558,  558,  558,   29,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  253,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
-      558,  558,  558,  558,  558,    0,  556,  556,  556,  556,
-      556
-    } ;
-
-static yyconst short int yy_nxt[710] =
-    {   0,
-       18,    5,    6,    7,  556,  556,    8,    9,   10,   11,
-       12,   13,   13,   13,   13,   14,   20,  555,   21,   21,
-       21,   21,   21,   24,   55,   55,   15,   25,   55,   55,
-      554,   16,   23,   23,   23,   23,   23,  553,   18,   23,
-       23,   23,   23,   23,   17,    5,    6,    7,  552,   18,
-        8,    9,   10,   11,   12,   13,   13,   13,   13,   14,
-       18,   23,   23,   23,   23,   23,   54,  551,   54,   76,
-       15,   18,   77,   28,  120,   16,  121,  239,   23,   23,
-       23,   23,   23,   59,   60,  240,   85,   61,   17,   20,
-       28,   21,   21,   21,   21,   21,   83,  298,   88,   62,
-
-       86,  299,   84,   87,   89,   90,  550,   22,   26,   54,
-       21,   21,   21,   21,   21,   94,   63,   95,  110,   27,
-       64,   91,   28,   65,   92,   96,  157,  111,  112,  158,
-       66,  125,  126,  113,  127,  107,  403,   54,  549,   54,
-      404,   29,   30,   31,   32,  108,   33,   34,   35,   36,
-       37,   38,   39,   40,   41,   42,   43,  364,   44,   45,
-       46,   47,   48,  365,   49,   56,   56,  109,  214,   57,
-       57,   57,   57,   57,   58,   58,   58,   58,   58,   97,
-       54,  215,   58,   58,   58,   58,   58,   58,   67,  142,
-       68,  548,  244,  143,  172,   98,   69,   99,  173,  102,
-
-      100,   70,  174,  103,  245,   71,  547,   72,   73,  144,
-      104,   74,   75,  227,  345,  101,  105,   57,   57,   57,
-       57,   57,  106,   57,   57,   57,   57,   57,  167,  192,
-      346,  546,  193,  168,  389,  390,  228,  229,  230,  545,
-      169,  318,  318,  318,  318,  318,  416,  481,  417,  318,
-      318,  318,  318,  318,  318,  486,  487,  489,  544,  543,
-      482,  490,  542,  418,  541,  419,    4,    4,    4,   19,
-       19,   53,   53,   54,   54,  540,  539,  538,  537,  536,
-      535,  534,  533,  532,  531,  530,  529,  528,  527,  526,
-      525,  524,  523,  522,  521,  520,  519,  518,  517,  516,
-
-      515,  514,  513,  512,  511,  510,  509,  508,  507,  506,
-      505,  504,  503,  502,  501,  500,  499,  498,  497,  496,
-      495,  494,  493,  492,  491,  488,  485,  484,  483,  480,
-      479,  478,  477,  476,  475,  474,  473,  472,  471,  470,
-      469,  468,  467,  466,  465,  464,  463,  462,  461,  460,
-      459,  458,  457,  456,  455,  454,  453,  452,  451,  450,
-      449,  448,  447,  446,  445,  444,  443,  442,  441,  440,
-      439,  438,  437,  436,  435,  434,  433,  432,  431,  430,
-      429,  428,  427,  426,  425,  424,  423,  422,  421,  420,
-      415,  414,  413,  412,  411,  410,  409,  408,  407,  406,
-
-      405,  402,  401,  400,  399,  398,  397,  396,  395,  394,
-      393,  392,  391,  388,  387,  386,  385,  384,  383,  382,
-      381,  380,  379,  378,  377,  376,  375,  374,  373,  372,
-      371,  370,  369,  368,  367,  366,  363,  362,  361,  360,
-      359,  358,  357,  356,  355,  354,  353,  352,  351,  350,
-      349,  348,  347,  344,  343,  342,  341,  340,  339,  338,
-      337,  336,  335,  334,  333,  332,  331,  330,  329,  328,
-      327,  326,  325,  324,  323,  322,  321,  320,  319,  317,
-      316,  315,  314,  313,  312,  311,  310,  309,  308,  307,
-      306,  305,  304,  303,  302,  301,  300,  297,  296,  295,
-
-      294,  293,  292,  291,  290,  289,  288,  287,  286,  285,
-      284,  283,  282,  281,  280,  279,  278,  277,  276,  275,
-      274,  273,  272,  271,  270,  269,  268,  267,  266,  265,
-      264,  263,  262,  261,  260,  259,  258,  257,  256,  255,
-      254,  253,  252,  251,  250,  249,  248,  247,  246,  243,
-      242,  241,  238,  237,  236,  235,  234,  233,  232,  231,
-      226,  225,  224,  223,  222,  221,  220,  219,  218,  217,
-      216,  213,  212,  211,  210,  209,  208,  207,  206,  205,
-      204,  203,  202,  201,  200,  199,  198,  197,  196,  195,
-      194,  191,  190,  189,  188,  187,  186,  185,  184,  183,
-
-      182,  181,  180,  179,  178,  177,  176,  175,  171,  170,
-      166,  165,  164,  163,  162,  161,  160,  159,  156,  155,
-      154,  153,  152,  151,  150,  149,  148,  147,  146,  145,
-      141,  140,  139,  138,  137,  136,  135,  134,  133,  132,
-      131,  130,  129,  128,  124,  123,  122,  119,  118,  117,
-      116,  115,  114,   93,   82,   81,   80,   79,   78,   52,
-       51,   50,  556,    3,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-
-      556,  556,  556,  556,  556,  556,  556,  556,  556
-    } ;
-
-static yyconst short int yy_chk[710] =
-    {   0,
-      558,    1,    1,    1,    0,    0,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    8,  554,    8,    8,
-        8,    8,    8,   11,   27,   27,    1,   11,   55,   55,
-      551,    1,   10,   10,   10,   10,   10,  550,   13,   20,
-       20,   20,   20,   20,    1,    2,    2,    2,  548,   21,
-        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
-       13,   23,   23,   23,   23,   23,   25,  547,   25,   33,
-        2,   21,   33,   23,   61,    2,   61,  170,   26,   26,
-       26,   26,   26,   30,   30,  170,   40,   30,    2,    9,
-       26,    9,    9,    9,    9,    9,   39,  232,   41,   30,
-
-       40,  232,   39,   40,   41,   42,  546,    9,   12,   25,
-       12,   12,   12,   12,   12,   44,   31,   44,   48,   12,
-       31,   42,   12,   31,   42,   44,   93,   48,   48,   93,
-       31,   65,   65,   48,   65,   47,  358,   53,  545,   53,
-      358,   12,   14,   14,   14,   47,   14,   14,   14,   14,
-       14,   14,   14,   14,   14,   14,   14,  308,   14,   14,
-       14,   14,   14,  308,   14,   28,   28,   47,  149,   28,
-       28,   28,   28,   28,   29,   29,   29,   29,   29,   45,
-       53,  149,   29,   29,   29,   29,   29,   29,   32,   80,
-       32,  543,  174,   80,  105,   45,   32,   45,  105,   46,
-
-       45,   32,  105,   46,  174,   32,  542,   32,   32,   80,
-       46,   32,   32,  161,  286,   45,   46,   56,   56,   56,
-       56,   56,   46,   57,   57,   57,   57,   57,  102,  126,
-      286,  541,  126,  102,  342,  342,  161,  161,  161,  540,
-      102,  253,  253,  253,  253,  253,  371,  452,  371,  253,
-      253,  253,  253,  253,  253,  460,  460,  462,  539,  538,
-      452,  462,  536,  371,  535,  371,  557,  557,  557,  559,
-      559,  560,  560,  561,  561,  534,  532,  530,  529,  528,
-      527,  526,  524,  521,  520,  519,  515,  512,  511,  510,
-      509,  508,  506,  505,  504,  503,  500,  499,  498,  497,
-
-      496,  495,  494,  493,  492,  490,  488,  487,  485,  484,
-      483,  482,  481,  480,  479,  477,  475,  474,  473,  472,
-      471,  468,  467,  465,  464,  461,  459,  458,  457,  451,
-      450,  449,  445,  443,  441,  440,  439,  438,  437,  434,
-      433,  431,  430,  428,  427,  426,  423,  422,  421,  420,
-      419,  418,  417,  415,  414,  413,  412,  411,  410,  409,
-      408,  407,  406,  405,  404,  402,  401,  397,  396,  395,
-      394,  393,  392,  390,  389,  388,  387,  386,  385,  384,
-      383,  382,  381,  380,  379,  378,  375,  374,  373,  372,
-      370,  369,  368,  367,  366,  365,  364,  363,  362,  361,
-
-      360,  357,  356,  354,  353,  352,  351,  350,  349,  347,
-      346,  345,  344,  341,  338,  337,  335,  334,  331,  330,
-      329,  328,  327,  326,  325,  323,  322,  321,  319,  317,
-      316,  315,  314,  313,  312,  310,  307,  306,  305,  304,
-      303,  302,  301,  300,  299,  298,  297,  293,  291,  290,
-      289,  288,  287,  285,  283,  282,  281,  278,  277,  276,
-      275,  274,  273,  271,  269,  268,  267,  266,  264,  263,
-      262,  261,  260,  259,  258,  257,  256,  255,  254,  252,
-      251,  250,  249,  248,  247,  245,  244,  243,  242,  241,
-      240,  239,  238,  236,  235,  234,  233,  231,  230,  229,
-
-      228,  227,  226,  224,  223,  222,  221,  220,  219,  218,
-      217,  216,  215,  214,  213,  212,  211,  210,  209,  208,
-      206,  205,  204,  203,  202,  200,  199,  198,  197,  195,
-      194,  193,  192,  191,  190,  189,  188,  187,  186,  185,
-      184,  183,  182,  181,  180,  179,  177,  176,  175,  173,
-      172,  171,  169,  168,  167,  166,  165,  164,  163,  162,
-      160,  159,  158,  157,  156,  155,  154,  153,  152,  151,
-      150,  148,  147,  146,  145,  144,  143,  141,  140,  139,
-      138,  137,  136,  135,  134,  133,  132,  131,  130,  129,
-      127,  125,  124,  123,  122,  121,  120,  119,  118,  116,
-
-      114,  113,  112,  110,  109,  108,  107,  106,  104,  103,
-      101,  100,   99,   98,   97,   96,   95,   94,   92,   91,
-       90,   89,   88,   87,   86,   85,   84,   83,   82,   81,
-       79,   78,   77,   76,   75,   74,   73,   72,   71,   70,
-       69,   68,   67,   66,   64,   63,   62,   60,   59,   52,
-       51,   50,   49,   43,   38,   37,   36,   35,   34,   22,
-       16,   15,    3,  556,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
-
-      556,  556,  556,  556,  556,  556,  556,  556,  556
-    } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "lexer.lxx"
-#define INITIAL 0
-/*
-// Filename: lexer.l
-// Created by:  drose (16Jan99)
-// 
-////////////////////////////////////////////////////////////////////
-*/
-#line 9 "lexer.lxx"
-#include "lexerDefs.h"
-#include "parserDefs.h"
-#include "config_egg.h"
-#include "parser.h"
-
-#include <indent.h>
-#include <notify.h>
-
-#include <math.h>
-#include <pandabase.h>
-
-extern "C" int eggyywrap(void);  // declared below.
-
-static int yyinput(void);        // declared by flex.
-
-
-////////////////////////////////////////////////////////////////////
-// Static variables
-////////////////////////////////////////////////////////////////////
-
-// We'll increment line_number and col_number as we parse the file, so
-// that we can report the position of an error.
-static int line_number = 0;
-static int col_number = 0;
-
-// current_line holds as much of the current line as will fit.  Its
-// only purpose is for printing it out to report an error to the user.
-static const int max_error_width = 1024;
-static char current_line[max_error_width + 1];
-
-static int error_count = 0;
-static int warning_count = 0;
-
-// This is the pointer to the current input stream.
-static istream *inp = NULL;
-
-// This is the name of the egg file we're parsing.  We keep it so we
-// can print it out for error messages.
-static string egg_filename;
-
-// This is the initial token state returned by the lexer.  It allows
-// the yacc grammar to start from initial points.
-static int initial_token;
-
-
-////////////////////////////////////////////////////////////////////
-// Defining the interface to the lexer.
-////////////////////////////////////////////////////////////////////
-
-void
-egg_init_lexer(istream &in, const string &filename) {
-  inp = &in;
-  egg_filename = filename;
-  line_number = 0;
-  col_number = 0;
-  error_count = 0;
-  warning_count = 0;
-  initial_token = START_EGG;
-}
-
-void
-egg_start_group_body() {
-  /* Set the initial state to begin within a group_body context,
-     instead of at the beginning of the egg file. */
-  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
-egg_error_count() {
-  return error_count;
-}
-
-int
-egg_warning_count() {
-  return warning_count;
-}
-
-
-////////////////////////////////////////////////////////////////////
-// Internal support functions.
-////////////////////////////////////////////////////////////////////
-
-int
-eggyywrap(void) {
-  return 1;
-}
-
-void
-eggyyerror(const string &msg) {
-  if (egg_cat.is_error()) {
-    ostream &out = egg_cat.error(false);
-
-    out << "\nError";
-    if (!egg_filename.empty()) {
-      out << " in " << egg_filename;
-    }
-    out 
-      << " at line " << line_number << ", column " << col_number << ":\n"
-      << setiosflags(Notify::get_literal_flag())
-      << current_line << "\n";
-    indent(out, col_number-1) 
-      << "^\n" << msg << "\n\n" 
-      << resetiosflags(Notify::get_literal_flag()) << flush;
-  }
-  error_count++;
-}
-
-void
-eggyyerror(ostringstream &strm) {
-  string s = strm.str();
-  eggyyerror(s);
-}
-
-void
-eggyywarning(const string &msg) {
-  if (egg_cat.is_warning()) {
-    ostream &out = egg_cat.warning(false);
-
-    out << "\nWarning";
-    if (!egg_filename.empty()) {
-      out << " in " << egg_filename;
-    }
-    out 
-      << " at line " << line_number << ", column " << col_number << ":\n"
-      << setiosflags(Notify::get_literal_flag())
-      << current_line << "\n";
-    indent(out, col_number-1) 
-      << "^\n" << msg << "\n\n" 
-      << resetiosflags(Notify::get_literal_flag()) << flush;
-  }
-  warning_count++;
-}
-
-void
-eggyywarning(ostringstream &strm) {
-  string s = strm.str();
-  eggyywarning(s);
-}
-
-// Now define a function to take input from an istream instead of a
-// stdio FILE pointer.  This is flex-specific.
-static void
-input_chars(char *buffer, int &result, int max_size) {
-  nassertv(inp != NULL);
-  if (*inp) {
-    inp->read(buffer, max_size);
-    result = inp->gcount();
-
-    if (line_number == 0) {
-      // This is a special case.  If we are reading the very first bit
-      // from the stream, copy it into the current_line array.  This
-      // is because the \n.* rule below, which fills current_line
-      // normally, doesn't catch the first line.
-      int length = min(max_error_width, result);
-      strncpy(current_line, buffer, length);
-      current_line[length] = '\0';
-      line_number++;
-      col_number = 0;
-
-      // Truncate it at the newline.
-      char *end = strchr(current_line, '\n');
-      if (end != NULL) {
-        *end = '\0';
-      }
-    }
-
-  } else {
-    // End of file or I/O error.
-    result = 0;
-  }
-}
-#undef YY_INPUT
-#define YY_INPUT(buffer, result, max_size) input_chars(buffer, result, max_size)
-
-// read_char reads and returns a single character, incrementing the
-// supplied line and column numbers as appropriate.  A convenience
-// function for the scanning functions below.
-static int
-read_char(int &line, int &col) {
-  int c = yyinput();
-  if (c == '\n') {
-    line++;
-    col = 0;
-  } else {
-    col++;
-  }
-  return c;
-}
-
-// scan_quoted_string reads a string delimited by quotation marks and
-// returns it.
-static string
-scan_quoted_string() {
-  string result;
-
-  // We don't touch the current line number and column number during
-  // scanning, so that if we detect an error while scanning the string
-  // (e.g. an unterminated string), we'll report the error as
-  // occurring at the start of the string, not at the end--somewhat
-  // more convenient for the user.
-
-  // Instead of adjusting the global line_number and col_number
-  // variables, we'll operate on our own local variables for the
-  // interim.
-  int line = line_number;
-  int col = col_number;
-
-  int c;
-  c = read_char(line, col);
-  while (c != '"' && c != EOF) {
-    result += c;
-    c = read_char(line, col);
-  }
-
-  if (c == EOF) {
-    eggyyerror("This quotation mark is unterminated.");
-  }
-
-  line_number = line;
-  col_number = col;
-
-  return result;
-}
-
-// eat_c_comment scans past all characters up until the first */
-// encountered.
-static void
-eat_c_comment() {
-  // As above, we'll operate on our own local copies of line_number
-  // and col_number within this function.
-
-  int line = line_number;
-  int col = col_number;
-
-  int c, last_c;
-  
-  last_c = '\0';
-  c = read_char(line, col);
-  while (c != EOF && !(last_c == '*' && c == '/')) {
-    if (last_c == '/' && c == '*') {
-      ostringstream errmsg;
-      errmsg << "This comment contains a nested /* symbol at line "
-             << line << ", column " << col-1 << "--possibly unclosed?"
-             << ends;
-      eggyywarning(errmsg);
-    }
-    last_c = c;
-    c = read_char(line, col);
-  }
-
-  if (c == EOF) {
-    eggyyerror("This comment marker is unclosed.");
-  }
-
-  line_number = line;
-  col_number = col;
-}
-
-
-// accept() is called below as each piece is pulled off and
-// accepted by the lexer; it increments the current column number.
-INLINE void accept() {
-  col_number += yyleng;
-}
-
-#line 1007 "lex.yy.c"
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap YY_PROTO(( void ));
-#else
-extern int yywrap YY_PROTO(( void ));
-#endif
-#endif
-
-#ifndef YY_NO_UNPUT
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
-#else
-static int input YY_PROTO(( void ));
-#endif
-#endif
-
-#if YY_STACK_USED
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-#ifndef YY_NO_PUSH_STATE
-static void yy_push_state YY_PROTO(( int new_state ));
-#endif
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state YY_PROTO(( void ));
-#endif
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state YY_PROTO(( void ));
-#endif
-
-#else
-#define YY_NO_PUSH_STATE 1
-#define YY_NO_POP_STATE 1
-#define YY_NO_TOP_STATE 1
-#endif
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#if __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines.  This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-	if ( yy_current_buffer->yy_is_interactive ) \
-		{ \
-		int c = '*', n; \
-		for ( n = 0; n < max_size && \
-			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-			buf[n] = (char) c; \
-		if ( c == '\n' ) \
-			buf[n++] = (char) c; \
-		if ( c == EOF && ferror( yyin ) ) \
-			YY_FATAL_ERROR( "input in flex scanner failed" ); \
-		result = n; \
-		} \
-	else \
-		{ \
-		errno=0; \
-		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
-			{ \
-			if( errno != EINTR) \
-				{ \
-				YY_FATAL_ERROR( "input in flex scanner failed" ); \
-				break; \
-				} \
-			errno=0; \
-			clearerr(yyin); \
-			} \
-		}
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
-	YY_USER_ACTION
-
-YY_DECL
-	{
-	register yy_state_type yy_current_state;
-	register char *yy_cp, *yy_bp;
-	register int yy_act;
-
-#line 290 "lexer.lxx"
-
-
-
-  if (initial_token != 0) {
-    int t = initial_token;
-    initial_token = 0;
-    return t;
-  }
-
-
-#line 1180 "lex.yy.c"
-
-	if ( yy_init )
-		{
-		yy_init = 0;
-
-#ifdef YY_USER_INIT
-		YY_USER_INIT;
-#endif
-
-		if ( ! yy_start )
-			yy_start = 1;	/* first start state */
-
-		if ( ! yyin )
-			yyin = stdin;
-
-		if ( ! yyout )
-			yyout = stdout;
-
-		if ( ! yy_current_buffer )
-			yy_current_buffer =
-				yy_create_buffer( yyin, YY_BUF_SIZE );
-
-		yy_load_buffer_state();
-		}
-
-	while ( 1 )		/* loops until end-of-file is reached */
-		{
-		yy_cp = yy_c_buf_p;
-
-		/* Support of yytext. */
-		*yy_cp = yy_hold_char;
-
-		/* yy_bp points to the position in yy_ch_buf of the start of
-		 * the current run.
-		 */
-		yy_bp = yy_cp;
-
-		yy_current_state = yy_start;
-yy_match:
-		do
-			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-			if ( yy_accept[yy_current_state] )
-				{
-				yy_last_accepting_state = yy_current_state;
-				yy_last_accepting_cpos = yy_cp;
-				}
-			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-				{
-				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 557 )
-					yy_c = yy_meta[(unsigned int) yy_c];
-				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-			++yy_cp;
-			}
-		while ( yy_base[yy_current_state] != 664 );
-
-yy_find_action:
-		yy_act = yy_accept[yy_current_state];
-		if ( yy_act == 0 )
-			{ /* have to back up */
-			yy_cp = yy_last_accepting_cpos;
-			yy_current_state = yy_last_accepting_state;
-			yy_act = yy_accept[yy_current_state];
-			}
-
-		YY_DO_BEFORE_ACTION;
-
-
-do_action:	/* This label is used only to access EOF actions. */
-
-
-		switch ( yy_act )
-	{ /* beginning of action switch */
-			case 0: /* must back up */
-			/* undo the effects of YY_DO_BEFORE_ACTION */
-			*yy_cp = yy_hold_char;
-			yy_cp = yy_last_accepting_cpos;
-			yy_current_state = yy_last_accepting_state;
-			goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 300 "lexer.lxx"
-{
-  // New line.  Save a copy of the line so we can print it out for the
-  // benefit of the user in case we get an error.
-
-  strncpy(current_line, yytext+1, max_error_width);
-  current_line[max_error_width] = '\0';
-  line_number++;
-  col_number=0;
-
-  // Return the whole line to the lexer, except the newline character,
-  // which we eat.
-  yyless(1);
-}
-	YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 314 "lexer.lxx"
-{ 
-  // Eat whitespace.
-  accept();
-}
-	YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 319 "lexer.lxx"
-{ 
-  // Eat C++-style comments.
-  accept();
-}
-	YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 324 "lexer.lxx"
-{
-  // Eat C-style comments.
-  accept();
-  eat_c_comment(); 
-}
-	YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 330 "lexer.lxx"
-{
-  // Send curly braces as themselves.
-  accept(); 
-  return eggyytext[0];
-}
-	YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 338 "lexer.lxx"
-{
-  accept();
-  return BEZIERCURVE;
-}
-	YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 342 "lexer.lxx"
-{
-  accept();
-  return BFACE;
-}
-	YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 346 "lexer.lxx"
-{
-  accept();
-  return BILLBOARD;
-}
-	YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 350 "lexer.lxx"
-{
-  accept();
-  return BILLBOARDCENTER;
-}
-	YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 354 "lexer.lxx"
-{
-  accept();
-  return BINORMAL;
-}
-	YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 358 "lexer.lxx"
-{
-  accept();
-  return BUNDLE;
-}
-	YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 362 "lexer.lxx"
-{
-  accept();
-  return SCALAR;
-}
-	YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 366 "lexer.lxx"
-{
-  accept();
-  return CLOSED;
-}
-	YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 370 "lexer.lxx"
-{
-  accept();
-  return COLLIDE;
-}
-	YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 374 "lexer.lxx"
-{
-  accept();
-  return COMMENT;
-}
-	YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 378 "lexer.lxx"
-{
-  accept();
-  return COMPONENT;
-}
-	YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 382 "lexer.lxx"
-{
-  accept();
-  return COORDSYSTEM;
-}
-	YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 386 "lexer.lxx"
-{
-  accept();
-  return CV;
-}
-	YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 390 "lexer.lxx"
-{
-  accept();
-  return DART;
-}
-	YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 394 "lexer.lxx"
-{
-  accept();
-  return DNORMAL;
-}
-	YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 398 "lexer.lxx"
-{
-  accept();
-  return DRGBA;
-}
-	YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 402 "lexer.lxx"
-{
-  accept();
-  return DUV;
-}
-	YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 406 "lexer.lxx"
-{
-  accept();
-  return DXYZ;
-}
-	YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 410 "lexer.lxx"
-{
-  accept();
-  return DCS;
-}
-	YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 414 "lexer.lxx"
-{
-  accept();
-  return DISTANCE;
-}
-	YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 418 "lexer.lxx"
-{
-  accept();
-  return DTREF;
-}
-	YY_BREAK
-case 27:
-YY_RULE_SETUP
-#line 422 "lexer.lxx"
-{
-  accept();
-  return DYNAMICVERTEXPOOL;
-}
-	YY_BREAK
-case 28:
-YY_RULE_SETUP
-#line 426 "lexer.lxx"
-{
-  accept();
-  return EXTERNAL_FILE;
-}
-	YY_BREAK
-case 29:
-YY_RULE_SETUP
-#line 430 "lexer.lxx"
-{
-  accept();
-  return FLIGHT;
-}
-	YY_BREAK
-case 30:
-YY_RULE_SETUP
-#line 434 "lexer.lxx"
-{
-  accept();
-  return GROUP;
-}
-	YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 438 "lexer.lxx"
-{
-  accept();
-  return HIP;
-}
-	YY_BREAK
-case 32:
-YY_RULE_SETUP
-#line 442 "lexer.lxx"
-{
-  accept();
-  return INTANGENT;
-}
-	YY_BREAK
-case 33:
-YY_RULE_SETUP
-#line 446 "lexer.lxx"
-{
-  accept();
-  return JOINT;
-}
-	YY_BREAK
-case 34:
-YY_RULE_SETUP
-#line 450 "lexer.lxx"
-{
-  accept();
-  return KNOTS;
-}
-	YY_BREAK
-case 35:
-YY_RULE_SETUP
-#line 454 "lexer.lxx"
-{
-  accept();
-  return INCLUDE;
-}
-	YY_BREAK
-case 36:
-YY_RULE_SETUP
-#line 458 "lexer.lxx"
-{
-  accept();
-  return INSTANCE;
-}
-	YY_BREAK
-case 37:
-YY_RULE_SETUP
-#line 462 "lexer.lxx"
-{
-  accept();
-  return LINE;
-}
-	YY_BREAK
-case 38:
-YY_RULE_SETUP
-#line 466 "lexer.lxx"
-{
-  accept();
-  return LOOP;
-}
-	YY_BREAK
-case 39:
-YY_RULE_SETUP
-#line 470 "lexer.lxx"
-{
-  accept();
-  return MATERIAL;
-}
-	YY_BREAK
-case 40:
-YY_RULE_SETUP
-#line 474 "lexer.lxx"
-{
-  accept();
-  return MATRIX3;
-}
-	YY_BREAK
-case 41:
-YY_RULE_SETUP
-#line 478 "lexer.lxx"
-{
-  accept();
-  return MATRIX4;
-}
-	YY_BREAK
-case 42:
-YY_RULE_SETUP
-#line 482 "lexer.lxx"
-{
-  accept();
-  return MODEL;
-}
-	YY_BREAK
-case 43:
-YY_RULE_SETUP
-#line 486 "lexer.lxx"
-{
-  accept();
-  return MREF;
-}
-	YY_BREAK
-case 44:
-YY_RULE_SETUP
-#line 490 "lexer.lxx"
-{
-  accept();
-  return NORMAL;
-}
-	YY_BREAK
-case 45:
-YY_RULE_SETUP
-#line 494 "lexer.lxx"
-{
-  accept();
-  return NURBSCURVE;
-}
-	YY_BREAK
-case 46:
-YY_RULE_SETUP
-#line 498 "lexer.lxx"
-{
-  accept();
-  return NURBSSURFACE;
-}
-	YY_BREAK
-case 47:
-YY_RULE_SETUP
-#line 502 "lexer.lxx"
-{
-  accept();
-  return OBJECTTYPE;
-}
-	YY_BREAK
-case 48:
-YY_RULE_SETUP
-#line 506 "lexer.lxx"
-{
-  accept();
-  return ORDER;
-}
-	YY_BREAK
-case 49:
-YY_RULE_SETUP
-#line 510 "lexer.lxx"
-{
-  accept();
-  return OUTTANGENT;
-}
-	YY_BREAK
-case 50:
-YY_RULE_SETUP
-#line 514 "lexer.lxx"
-{
-  accept();
-  return POINTLIGHT;
-}
-	YY_BREAK
-case 51:
-YY_RULE_SETUP
-#line 518 "lexer.lxx"
-{
-  accept();
-  return POLYGON;
-}
-	YY_BREAK
-case 52:
-YY_RULE_SETUP
-#line 522 "lexer.lxx"
-{
-  accept();
-  return REF;
-}
-	YY_BREAK
-case 53:
-YY_RULE_SETUP
-#line 526 "lexer.lxx"
-{
-  accept();
-  return RGBA;
-}
-	YY_BREAK
-case 54:
-YY_RULE_SETUP
-#line 530 "lexer.lxx"
-{
-  accept();
-  return ROTATE;
-}
-	YY_BREAK
-case 55:
-YY_RULE_SETUP
-#line 534 "lexer.lxx"
-{
-  accept();
-  return ROTX;
-}
-	YY_BREAK
-case 56:
-YY_RULE_SETUP
-#line 538 "lexer.lxx"
-{
-  accept();
-  return ROTY;
-}
-	YY_BREAK
-case 57:
-YY_RULE_SETUP
-#line 542 "lexer.lxx"
-{
-  accept();
-  return ROTZ;
-}
-	YY_BREAK
-case 58:
-YY_RULE_SETUP
-#line 546 "lexer.lxx"
-{
-  accept();
-  return SANIM;
-}
-	YY_BREAK
-case 59:
-YY_RULE_SETUP
-#line 550 "lexer.lxx"
-{
-  accept();
-  return SCALAR;
-}
-	YY_BREAK
-case 60:
-YY_RULE_SETUP
-#line 554 "lexer.lxx"
-{
-  accept();
-  return SCALE;
-}
-	YY_BREAK
-case 61:
-YY_RULE_SETUP
-#line 558 "lexer.lxx"
-{
-  accept();
-  return SEQUENCE;
-}
-	YY_BREAK
-case 62:
-YY_RULE_SETUP
-#line 562 "lexer.lxx"
-{
-  accept();
-  return SHADING;
-}
-	YY_BREAK
-case 63:
-YY_RULE_SETUP
-#line 566 "lexer.lxx"
-{
-  accept();
-  return SWITCH;
-}
-	YY_BREAK
-case 64:
-YY_RULE_SETUP
-#line 570 "lexer.lxx"
-{
-  accept();
-  return SWITCHCONDITION;
-}
-	YY_BREAK
-case 65:
-YY_RULE_SETUP
-#line 574 "lexer.lxx"
-{
-  accept();
-  return TABLE;
-}
-	YY_BREAK
-case 66:
-YY_RULE_SETUP
-#line 578 "lexer.lxx"
-{
-  accept();
-  return TABLE_V;
-}
-	YY_BREAK
-case 67:
-YY_RULE_SETUP
-#line 582 "lexer.lxx"
-{
-  accept();
-  return TAG;
-}
-	YY_BREAK
-case 68:
-YY_RULE_SETUP
-#line 586 "lexer.lxx"
-{
-  accept();
-  return TANGENT;
-}
-	YY_BREAK
-case 69:
-YY_RULE_SETUP
-#line 590 "lexer.lxx"
-{
-  accept();
-  return TEXLIST;
-}
-	YY_BREAK
-case 70:
-YY_RULE_SETUP
-#line 594 "lexer.lxx"
-{
-  accept();
-  return TEXTURE;
-}
-	YY_BREAK
-case 71:
-YY_RULE_SETUP
-#line 598 "lexer.lxx"
-{
-  accept();
-  return TLENGTHS;
-}
-	YY_BREAK
-case 72:
-YY_RULE_SETUP
-#line 602 "lexer.lxx"
-{
-  accept();
-  return TRANSFORM;
-}
-	YY_BREAK
-case 73:
-YY_RULE_SETUP
-#line 606 "lexer.lxx"
-{
-  accept();
-  return TRANSLATE;
-}
-	YY_BREAK
-case 74:
-YY_RULE_SETUP
-#line 610 "lexer.lxx"
-{
-  accept();
-  return TREF;
-}
-	YY_BREAK
-case 75:
-YY_RULE_SETUP
-#line 614 "lexer.lxx"
-{
-  accept();
-  return TRIANGLEFAN;
-}
-	YY_BREAK
-case 76:
-YY_RULE_SETUP
-#line 618 "lexer.lxx"
-{
-  accept();
-  return TRIANGLESTRIP;
-}
-	YY_BREAK
-case 77:
-YY_RULE_SETUP
-#line 622 "lexer.lxx"
-{
-  accept();
-  return TRIM;
-}
-	YY_BREAK
-case 78:
-YY_RULE_SETUP
-#line 626 "lexer.lxx"
-{
-  accept();
-  return TXT;
-}
-	YY_BREAK
-case 79:
-YY_RULE_SETUP
-#line 630 "lexer.lxx"
-{
-  accept();
-  return UKNOTS;
-}
-	YY_BREAK
-case 80:
-YY_RULE_SETUP
-#line 634 "lexer.lxx"
-{
-  accept();
-  return UKNOTS;
-}
-	YY_BREAK
-case 81:
-YY_RULE_SETUP
-#line 638 "lexer.lxx"
-{
-  accept();
-  return UV;
-}
-	YY_BREAK
-case 82:
-YY_RULE_SETUP
-#line 642 "lexer.lxx"
-{
-  accept();
-  return VKNOTS;
-}
-	YY_BREAK
-case 83:
-YY_RULE_SETUP
-#line 646 "lexer.lxx"
-{
-  accept();
-  return VKNOTS;
-}
-	YY_BREAK
-case 84:
-YY_RULE_SETUP
-#line 650 "lexer.lxx"
-{
-  accept();
-  return VERTEX;
-}
-	YY_BREAK
-case 85:
-YY_RULE_SETUP
-#line 654 "lexer.lxx"
-{
-  accept();
-  return VERTEXANIM;
-}
-	YY_BREAK
-case 86:
-YY_RULE_SETUP
-#line 658 "lexer.lxx"
-{
-  accept();
-  return VERTEXPOOL;
-}
-	YY_BREAK
-case 87:
-YY_RULE_SETUP
-#line 662 "lexer.lxx"
-{
-  accept();
-  return VERTEXREF;
-}
-	YY_BREAK
-case 88:
-YY_RULE_SETUP
-#line 666 "lexer.lxx"
-{
-  accept();
-  return XFMANIM;
-}
-	YY_BREAK
-case 89:
-YY_RULE_SETUP
-#line 670 "lexer.lxx"
-{
-  accept();
-  return XFMSANIM;
-}
-	YY_BREAK
-case 90:
-YY_RULE_SETUP
-#line 677 "lexer.lxx"
-{ 
-  // An integer or floating-point number.
-  accept(); 
-  eggyylval._number = atof(eggyytext); 
-  eggyylval._string = yytext;
-  return NUMBER; 
-}
-	YY_BREAK
-case 91:
-YY_RULE_SETUP
-#line 685 "lexer.lxx"
-{
-  // A hexadecimal integer number.
-  accept(); 
-  eggyylval._ulong = strtoul(yytext+2, NULL, 16);
-  eggyylval._string = yytext;
-  return ULONG; 
-}
-	YY_BREAK
-case 92:
-YY_RULE_SETUP
-#line 693 "lexer.lxx"
-{
-  // A binary integer number.
-  accept(); 
-  eggyylval._ulong = strtoul(yytext+2, NULL, 2);
-  eggyylval._string = yytext;
-  return ULONG; 
-}
-	YY_BREAK
-case 93:
-YY_RULE_SETUP
-#line 701 "lexer.lxx"
-{
-  // not-a-number.  These sometimes show up in egg files accidentally.
-  accept(); 
-  memset(&eggyylval._number, 0, sizeof(eggyylval._number));
-  *(unsigned long *)&eggyylval._number = strtoul(yytext+3, NULL, 0);
-  eggyylval._string = yytext;
-  return NUMBER;
-}
-	YY_BREAK
-case 94:
-YY_RULE_SETUP
-#line 710 "lexer.lxx"
-{ 
-  // infinity.  As above.
-  accept(); 
-  eggyylval._number = HUGE_VAL;
-  eggyylval._string = yytext;
-  return NUMBER; 
-}
-	YY_BREAK
-case 95:
-YY_RULE_SETUP
-#line 718 "lexer.lxx"
-{
-  // minus infinity.  As above.
-  accept(); 
-  eggyylval._number = -HUGE_VAL;
-  eggyylval._string = yytext;
-  return NUMBER; 
-}
-	YY_BREAK
-case 96:
-YY_RULE_SETUP
-#line 727 "lexer.lxx"
-{
-  // Quoted string.
-  accept();
-  eggyylval._string = scan_quoted_string();
-  return STRING;
-}
-	YY_BREAK
-case 97:
-YY_RULE_SETUP
-#line 734 "lexer.lxx"
-{ 
-  // Unquoted string.
-  accept();
-  eggyylval._string = yytext;
-  return STRING;
-}
-	YY_BREAK
-case 98:
-YY_RULE_SETUP
-#line 740 "lexer.lxx"
-ECHO;
-	YY_BREAK
-#line 2078 "lex.yy.c"
-case YY_STATE_EOF(INITIAL):
-	yyterminate();
-
-	case YY_END_OF_BUFFER:
-		{
-		/* Amount of text matched not including the EOB char. */
-		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
-
-		/* Undo the effects of YY_DO_BEFORE_ACTION. */
-		*yy_cp = yy_hold_char;
-		YY_RESTORE_YY_MORE_OFFSET
-
-		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
-			{
-			/* We're scanning a new file or input source.  It's
-			 * possible that this happened because the user
-			 * just pointed yyin at a new source and called
-			 * yylex().  If so, then we have to assure
-			 * consistency between yy_current_buffer and our
-			 * globals.  Here is the right place to do so, because
-			 * this is the first action (other than possibly a
-			 * back-up) that will match for the new input source.
-			 */
-			yy_n_chars = yy_current_buffer->yy_n_chars;
-			yy_current_buffer->yy_input_file = yyin;
-			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
-			}
-
-		/* Note that here we test for yy_c_buf_p "<=" to the position
-		 * of the first EOB in the buffer, since yy_c_buf_p will
-		 * already have been incremented past the NUL character
-		 * (since all states make transitions on EOB to the
-		 * end-of-buffer state).  Contrast this with the test
-		 * in input().
-		 */
-		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
-			{ /* This was really a NUL. */
-			yy_state_type yy_next_state;
-
-			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
-
-			yy_current_state = yy_get_previous_state();
-
-			/* Okay, we're now positioned to make the NUL
-			 * transition.  We couldn't have
-			 * yy_get_previous_state() go ahead and do it
-			 * for us because it doesn't know how to deal
-			 * with the possibility of jamming (and we don't
-			 * want to build jamming into it because then it
-			 * will run more slowly).
-			 */
-
-			yy_next_state = yy_try_NUL_trans( yy_current_state );
-
-			yy_bp = yytext_ptr + YY_MORE_ADJ;
-
-			if ( yy_next_state )
-				{
-				/* Consume the NUL. */
-				yy_cp = ++yy_c_buf_p;
-				yy_current_state = yy_next_state;
-				goto yy_match;
-				}
-
-			else
-				{
-				yy_cp = yy_c_buf_p;
-				goto yy_find_action;
-				}
-			}
-
-		else switch ( yy_get_next_buffer() )
-			{
-			case EOB_ACT_END_OF_FILE:
-				{
-				yy_did_buffer_switch_on_eof = 0;
-
-				if ( yywrap() )
-					{
-					/* Note: because we've taken care in
-					 * yy_get_next_buffer() to have set up
-					 * yytext, we can now set up
-					 * yy_c_buf_p so that if some total
-					 * hoser (like flex itself) wants to
-					 * call the scanner after we return the
-					 * YY_NULL, it'll still work - another
-					 * YY_NULL will get returned.
-					 */
-					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
-
-					yy_act = YY_STATE_EOF(YY_START);
-					goto do_action;
-					}
-
-				else
-					{
-					if ( ! yy_did_buffer_switch_on_eof )
-						YY_NEW_FILE;
-					}
-				break;
-				}
-
-			case EOB_ACT_CONTINUE_SCAN:
-				yy_c_buf_p =
-					yytext_ptr + yy_amount_of_matched_text;
-
-				yy_current_state = yy_get_previous_state();
-
-				yy_cp = yy_c_buf_p;
-				yy_bp = yytext_ptr + YY_MORE_ADJ;
-				goto yy_match;
-
-			case EOB_ACT_LAST_MATCH:
-				yy_c_buf_p =
-				&yy_current_buffer->yy_ch_buf[yy_n_chars];
-
-				yy_current_state = yy_get_previous_state();
-
-				yy_cp = yy_c_buf_p;
-				yy_bp = yytext_ptr + YY_MORE_ADJ;
-				goto yy_find_action;
-			}
-		break;
-		}
-
-	default:
-		YY_FATAL_ERROR(
-			"fatal flex scanner internal error--no action found" );
-	} /* end of action switch */
-		} /* end of scanning one token */
-	} /* end of yylex */
-
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *	EOB_ACT_LAST_MATCH -
- *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *	EOB_ACT_END_OF_FILE - end of file
- */
-
-static int yy_get_next_buffer()
-	{
-	register char *dest = yy_current_buffer->yy_ch_buf;
-	register char *source = yytext_ptr;
-	register int number_to_move, i;
-	int ret_val;
-
-	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
-		YY_FATAL_ERROR(
-		"fatal flex scanner internal error--end of buffer missed" );
-
-	if ( yy_current_buffer->yy_fill_buffer == 0 )
-		{ /* Don't try to fill the buffer, so this is an EOF. */
-		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
-			{
-			/* We matched a single character, the EOB, so
-			 * treat this as a final EOF.
-			 */
-			return EOB_ACT_END_OF_FILE;
-			}
-
-		else
-			{
-			/* We matched some text prior to the EOB, first
-			 * process it.
-			 */
-			return EOB_ACT_LAST_MATCH;
-			}
-		}
-
-	/* Try to read more data. */
-
-	/* First move last chars to start of buffer. */
-	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
-
-	for ( i = 0; i < number_to_move; ++i )
-		*(dest++) = *(source++);
-
-	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-		/* don't do the read, it's not guaranteed to return an EOF,
-		 * just force an EOF
-		 */
-		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
-
-	else
-		{
-		int num_to_read =
-			yy_current_buffer->yy_buf_size - number_to_move - 1;
-
-		while ( num_to_read <= 0 )
-			{ /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
-			YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
-
-			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = yy_current_buffer;
-
-			int yy_c_buf_p_offset =
-				(int) (yy_c_buf_p - b->yy_ch_buf);
-
-			if ( b->yy_is_our_buffer )
-				{
-				int new_size = b->yy_buf_size * 2;
-
-				if ( new_size <= 0 )
-					b->yy_buf_size += b->yy_buf_size / 8;
-				else
-					b->yy_buf_size *= 2;
-
-				b->yy_ch_buf = (char *)
-					/* Include room in for 2 EOB chars. */
-					yy_flex_realloc( (void *) b->yy_ch_buf,
-							 b->yy_buf_size + 2 );
-				}
-			else
-				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = 0;
-
-			if ( ! b->yy_ch_buf )
-				YY_FATAL_ERROR(
-				"fatal error - scanner input buffer overflow" );
-
-			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-			num_to_read = yy_current_buffer->yy_buf_size -
-						number_to_move - 1;
-#endif
-			}
-
-		if ( num_to_read > YY_READ_BUF_SIZE )
-			num_to_read = YY_READ_BUF_SIZE;
-
-		/* Read in more data. */
-		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
-			yy_n_chars, num_to_read );
-
-		yy_current_buffer->yy_n_chars = yy_n_chars;
-		}
-
-	if ( yy_n_chars == 0 )
-		{
-		if ( number_to_move == YY_MORE_ADJ )
-			{
-			ret_val = EOB_ACT_END_OF_FILE;
-			yyrestart( yyin );
-			}
-
-		else
-			{
-			ret_val = EOB_ACT_LAST_MATCH;
-			yy_current_buffer->yy_buffer_status =
-				YY_BUFFER_EOF_PENDING;
-			}
-		}
-
-	else
-		ret_val = EOB_ACT_CONTINUE_SCAN;
-
-	yy_n_chars += number_to_move;
-	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
-	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
-	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
-
-	return ret_val;
-	}
-
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-static yy_state_type yy_get_previous_state()
-	{
-	register yy_state_type yy_current_state;
-	register char *yy_cp;
-
-	yy_current_state = yy_start;
-
-	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
-		{
-		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-		if ( yy_accept[yy_current_state] )
-			{
-			yy_last_accepting_state = yy_current_state;
-			yy_last_accepting_cpos = yy_cp;
-			}
-		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-			{
-			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 557 )
-				yy_c = yy_meta[(unsigned int) yy_c];
-			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-		}
-
-	return yy_current_state;
-	}
-
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *	next_state = yy_try_NUL_trans( current_state );
- */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
-	{
-	register int yy_is_jam;
-	register char *yy_cp = yy_c_buf_p;
-
-	register YY_CHAR yy_c = 1;
-	if ( yy_accept[yy_current_state] )
-		{
-		yy_last_accepting_state = yy_current_state;
-		yy_last_accepting_cpos = yy_cp;
-		}
-	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-		{
-		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 557 )
-			yy_c = yy_meta[(unsigned int) yy_c];
-		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 556);
-
-	return yy_is_jam ? 0 : yy_current_state;
-	}
-
-
-#ifndef YY_NO_UNPUT
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
-	{
-	register char *yy_cp = yy_c_buf_p;
-
-	/* undo effects of setting up yytext */
-	*yy_cp = yy_hold_char;
-
-	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-		{ /* need to shift things up to make room */
-		/* +2 for EOB chars. */
-		register int number_to_move = yy_n_chars + 2;
-		register char *dest = &yy_current_buffer->yy_ch_buf[
-					yy_current_buffer->yy_buf_size + 2];
-		register char *source =
-				&yy_current_buffer->yy_ch_buf[number_to_move];
-
-		while ( source > yy_current_buffer->yy_ch_buf )
-			*--dest = *--source;
-
-		yy_cp += (int) (dest - source);
-		yy_bp += (int) (dest - source);
-		yy_current_buffer->yy_n_chars =
-			yy_n_chars = yy_current_buffer->yy_buf_size;
-
-		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-			YY_FATAL_ERROR( "flex scanner push-back overflow" );
-		}
-
-	*--yy_cp = (char) c;
-
-
-	yytext_ptr = yy_bp;
-	yy_hold_char = *yy_cp;
-	yy_c_buf_p = yy_cp;
-	}
-#endif	/* ifndef YY_NO_UNPUT */
-
-
-#ifdef __cplusplus
-static int yyinput()
-#else
-static int input()
-#endif
-	{
-	int c;
-
-	*yy_c_buf_p = yy_hold_char;
-
-	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
-		{
-		/* yy_c_buf_p now points to the character we want to return.
-		 * If this occurs *before* the EOB characters, then it's a
-		 * valid NUL; if not, then we've hit the end of the buffer.
-		 */
-		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
-			/* This was really a NUL. */
-			*yy_c_buf_p = '\0';
-
-		else
-			{ /* need more input */
-			int offset = yy_c_buf_p - yytext_ptr;
-			++yy_c_buf_p;
-
-			switch ( yy_get_next_buffer() )
-				{
-				case EOB_ACT_LAST_MATCH:
-					/* This happens because yy_g_n_b()
-					 * sees that we've accumulated a
-					 * token and flags that we need to
-					 * try matching the token before
-					 * proceeding.  But for input(),
-					 * there's no matching to consider.
-					 * So convert the EOB_ACT_LAST_MATCH
-					 * to EOB_ACT_END_OF_FILE.
-					 */
-
-					/* Reset buffer status. */
-					yyrestart( yyin );
-
-					/* fall through */
-
-				case EOB_ACT_END_OF_FILE:
-					{
-					if ( yywrap() )
-						return EOF;
-
-					if ( ! yy_did_buffer_switch_on_eof )
-						YY_NEW_FILE;
-#ifdef __cplusplus
-					return yyinput();
-#else
-					return input();
-#endif
-					}
-
-				case EOB_ACT_CONTINUE_SCAN:
-					yy_c_buf_p = yytext_ptr + offset;
-					break;
-				}
-			}
-		}
-
-	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
-	*yy_c_buf_p = '\0';	/* preserve yytext */
-	yy_hold_char = *++yy_c_buf_p;
-
-
-	return c;
-	}
-
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
-	{
-	if ( ! yy_current_buffer )
-		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
-
-	yy_init_buffer( yy_current_buffer, input_file );
-	yy_load_buffer_state();
-	}
-
-
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
-	{
-	if ( yy_current_buffer == new_buffer )
-		return;
-
-	if ( yy_current_buffer )
-		{
-		/* Flush out information for old buffer. */
-		*yy_c_buf_p = yy_hold_char;
-		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
-		yy_current_buffer->yy_n_chars = yy_n_chars;
-		}
-
-	yy_current_buffer = new_buffer;
-	yy_load_buffer_state();
-
-	/* We don't actually know whether we did this switch during
-	 * EOF (yywrap()) processing, but the only time this flag
-	 * is looked at is after yywrap() is called, so it's safe
-	 * to go ahead and always set it.
-	 */
-	yy_did_buffer_switch_on_eof = 1;
-	}
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
-	{
-	yy_n_chars = yy_current_buffer->yy_n_chars;
-	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
-	yyin = yy_current_buffer->yy_input_file;
-	yy_hold_char = *yy_c_buf_p;
-	}
-
-
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
-	{
-	YY_BUFFER_STATE b;
-
-	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
-	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-	b->yy_buf_size = size;
-
-	/* yy_ch_buf has to be 2 characters longer than the size given because
-	 * we need to put in 2 end-of-buffer characters.
-	 */
-	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
-	if ( ! b->yy_ch_buf )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-	b->yy_is_our_buffer = 1;
-
-	yy_init_buffer( b, file );
-
-	return b;
-	}
-
-
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-	{
-	if ( ! b )
-		return;
-
-	if ( b == yy_current_buffer )
-		yy_current_buffer = (YY_BUFFER_STATE) 0;
-
-	if ( b->yy_is_our_buffer )
-		yy_flex_free( (void *) b->yy_ch_buf );
-
-	yy_flex_free( (void *) b );
-	}
-
-
-#ifndef _WIN32
-#else
-#ifndef YY_ALWAYS_INTERACTIVE
-#ifndef YY_NEVER_INTERACTIVE
-extern int isatty YY_PROTO(( int ));
-#endif
-#endif
-#endif
-
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
-
-
-	{
-	yy_flush_buffer( b );
-
-	b->yy_input_file = file;
-	b->yy_fill_buffer = 1;
-
-#if YY_ALWAYS_INTERACTIVE
-	b->yy_is_interactive = 1;
-#else
-#if YY_NEVER_INTERACTIVE
-	b->yy_is_interactive = 0;
-#else
-	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-#endif
-#endif
-	}
-
-
-#ifdef YY_USE_PROTOS
-void yy_flush_buffer( YY_BUFFER_STATE b )
-#else
-void yy_flush_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-
-	{
-	if ( ! b )
-		return;
-
-	b->yy_n_chars = 0;
-
-	/* We always need two end-of-buffer characters.  The first causes
-	 * a transition to the end-of-buffer state.  The second causes
-	 * a jam in that state.
-	 */
-	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-	b->yy_buf_pos = &b->yy_ch_buf[0];
-
-	b->yy_at_bol = 1;
-	b->yy_buffer_status = YY_BUFFER_NEW;
-
-	if ( b == yy_current_buffer )
-		yy_load_buffer_state();
-	}
-
-
-#ifndef YY_NO_SCAN_BUFFER
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
-#else
-YY_BUFFER_STATE yy_scan_buffer( base, size )
-char *base;
-yy_size_t size;
-#endif
-	{
-	YY_BUFFER_STATE b;
-
-	if ( size < 2 ||
-	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
-	     base[size-1] != YY_END_OF_BUFFER_CHAR )
-		/* They forgot to leave room for the EOB's. */
-		return 0;
-
-	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
-	if ( ! b )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
-	b->yy_buf_pos = b->yy_ch_buf = base;
-	b->yy_is_our_buffer = 0;
-	b->yy_input_file = 0;
-	b->yy_n_chars = b->yy_buf_size;
-	b->yy_is_interactive = 0;
-	b->yy_at_bol = 1;
-	b->yy_fill_buffer = 0;
-	b->yy_buffer_status = YY_BUFFER_NEW;
-
-	yy_switch_to_buffer( b );
-
-	return b;
-	}
-#endif
-
-
-#ifndef YY_NO_SCAN_STRING
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
-#else
-YY_BUFFER_STATE yy_scan_string( yy_str )
-yyconst char *yy_str;
-#endif
-	{
-	int len;
-	for ( len = 0; yy_str[len]; ++len )
-		;
-
-	return yy_scan_bytes( yy_str, len );
-	}
-#endif
-
-
-#ifndef YY_NO_SCAN_BYTES
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
-#else
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )
-yyconst char *bytes;
-int len;
-#endif
-	{
-	YY_BUFFER_STATE b;
-	char *buf;
-	yy_size_t n;
-	int i;
-
-	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = len + 2;
-	buf = (char *) yy_flex_alloc( n );
-	if ( ! buf )
-		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
-	for ( i = 0; i < len; ++i )
-		buf[i] = bytes[i];
-
-	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
-
-	b = yy_scan_buffer( buf, n );
-	if ( ! b )
-		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
-	/* It's okay to grow etc. this buffer, and we should throw it
-	 * away when we're done.
-	 */
-	b->yy_is_our_buffer = 1;
-
-	return b;
-	}
-#endif
-
-
-#ifndef YY_NO_PUSH_STATE
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
-	{
-	if ( yy_start_stack_ptr >= yy_start_stack_depth )
-		{
-		yy_size_t new_size;
-
-		yy_start_stack_depth += YY_START_STACK_INCR;
-		new_size = yy_start_stack_depth * sizeof( int );
-
-		if ( ! yy_start_stack )
-			yy_start_stack = (int *) yy_flex_alloc( new_size );
-
-		else
-			yy_start_stack = (int *) yy_flex_realloc(
-					(void *) yy_start_stack, new_size );
-
-		if ( ! yy_start_stack )
-			YY_FATAL_ERROR(
-			"out of memory expanding start-condition stack" );
-		}
-
-	yy_start_stack[yy_start_stack_ptr++] = YY_START;
-
-	BEGIN(new_state);
-	}
-#endif
-
-
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state()
-	{
-	if ( --yy_start_stack_ptr < 0 )
-		YY_FATAL_ERROR( "start-condition stack underflow" );
-
-	BEGIN(yy_start_stack[yy_start_stack_ptr]);
-	}
-#endif
-
-
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state()
-	{
-	return yy_start_stack[yy_start_stack_ptr - 1];
-	}
-#endif
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( yyconst char msg[] )
-#else
-static void yy_fatal_error( msg )
-char msg[];
-#endif
-	{
-	(void) fprintf( stderr, "%s\n", msg );
-	exit( YY_EXIT_FAILURE );
-	}
-
-
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-	do \
-		{ \
-		/* Undo effects of setting up yytext. */ \
-		yytext[yyleng] = yy_hold_char; \
-		yy_c_buf_p = yytext + n; \
-		yy_hold_char = *yy_c_buf_p; \
-		*yy_c_buf_p = '\0'; \
-		yyleng = n; \
-		} \
-	while ( 0 )
-
-
-/* Internal utility routines. */
-
-#ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-yyconst char *s2;
-int n;
-#endif
-	{
-	register int i;
-	for ( i = 0; i < n; ++i )
-		s1[i] = s2[i];
-	}
-#endif
-
-#ifdef YY_NEED_STRLEN
-#ifdef YY_USE_PROTOS
-static int yy_flex_strlen( yyconst char *s )
-#else
-static int yy_flex_strlen( s )
-yyconst char *s;
-#endif
-	{
-	register int n;
-	for ( n = 0; s[n]; ++n )
-		;
-
-	return n;
-	}
-#endif
-
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( yy_size_t size )
-#else
-static void *yy_flex_alloc( size )
-yy_size_t size;
-#endif
-	{
-	return (void *) malloc( size );
-	}
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, yy_size_t size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-yy_size_t size;
-#endif
-	{
-	/* The cast to (char *) in the following accommodates both
-	 * implementations that use char* generic pointers, and those
-	 * that use void* generic pointers.  It works with the latter
-	 * because both ANSI C and C++ allow castless assignment from
-	 * any pointer type to void*, and deal with argument conversions
-	 * as though doing an assignment.
-	 */
-	return (void *) realloc( (char *) ptr, size );
-	}
-
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
-	{
-	free( ptr );
-	}
-
-#if YY_MAIN
-int main()
-	{
-	yylex();
-	return 0;
-	}
-#endif
-#line 740 "lexer.lxx"
+#define yy_create_buffer eggyy_create_buffer
+#define yy_delete_buffer eggyy_delete_buffer
+#define yy_scan_buffer eggyy_scan_buffer
+#define yy_scan_string eggyy_scan_string
+#define yy_scan_bytes eggyy_scan_bytes
+#define yy_flex_debug eggyy_flex_debug
+#define yy_init_buffer eggyy_init_buffer
+#define yy_flush_buffer eggyy_flush_buffer
+#define yy_load_buffer_state eggyy_load_buffer_state
+#define yy_switch_to_buffer eggyy_switch_to_buffer
+#define yyin eggyyin
+#define yyleng eggyyleng
+#define yylex eggyylex
+#define yyout eggyyout
+#define yyrestart eggyyrestart
+#define yytext eggyytext
+#define yywrap eggyywrap
+
+#line 20 "lex.yy.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 98
+#define YY_END_OF_BUFFER 99
+static yyconst short int yy_accept[557] =
+    {   0,
+        0,    0,   99,   97,    2,    1,   96,   97,   97,   97,
+       97,   90,   90,   97,   97,   97,    5,   97,    1,   97,
+       90,   97,   90,    4,    3,   90,   92,   97,   91,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,    3,    3,   92,   97,   90,   91,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       66,   97,   97,   97,   94,   97,   95,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   18,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   32,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   81,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   24,   97,   97,   97,   97,
+
+       22,   97,   97,   97,   97,   97,   31,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   52,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   67,   97,   97,   97,
+       97,   97,   97,   97,   97,   78,   97,   97,   97,   97,
+       97,   97,   93,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   19,   97,   97,   97,   97,   23,
+       97,   28,   97,   97,   97,   97,   97,   97,   37,   38,
+       97,   97,   97,   43,   97,   97,   97,   97,   97,   97,
+       97,   53,   97,   55,   56,   57,   97,   97,   97,   97,
+
+       97,   97,   97,   97,   97,   97,   97,   97,   74,   97,
+       77,   97,   97,   97,   97,   97,   97,   93,   97,    7,
+       97,   97,   97,   12,   97,   97,   97,   97,   97,   97,
+       97,   21,   26,   97,   97,   30,   97,   97,   33,   34,
+       97,   97,   42,   97,   97,   97,   97,   48,   97,   97,
+       97,   97,   97,   97,   60,   97,   97,   97,   65,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   11,   13,   97,   97,   97,
+       97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+       44,   97,   97,   97,   97,   97,   97,   54,   58,   59,
+
+       97,   97,   63,   97,   97,   97,   97,   97,   97,   97,
+       97,   97,   97,   97,   97,   84,   97,   97,   97,   97,
+       97,   97,   97,   14,   15,   97,   97,   97,   20,   97,
+       97,   35,   97,   97,   40,   41,   97,   97,   97,   97,
+       97,   51,   97,   62,   97,   68,   69,   70,   97,   97,
+       97,   97,   79,   80,   82,   83,   97,   97,   97,   97,
+       97,   97,   10,   97,   97,   25,   97,   97,   36,   39,
+       97,   97,   97,   97,   97,   61,   97,   71,   97,   97,
+       97,   97,   97,   97,   97,   88,   97,   97,    8,   97,
+       16,   97,   97,   97,   97,   97,   97,   97,   97,   97,
+
+       72,   73,   97,   97,   97,   97,   87,   97,   97,   97,
+       97,   97,   29,   45,   97,   47,   49,   50,   97,   97,
+       97,   85,   86,   97,    6,   97,   97,   97,   97,   97,
+       75,   97,   89,   97,   97,   97,   46,   97,   97,   97,
+       97,   97,   97,   76,   97,   97,   97,   97,    9,   97,
+       97,   64,   17,   97,   27,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    4,    1,    5,    1,    1,    1,    1,
+        1,    6,    7,    1,    8,    9,   10,   11,   12,   13,
+       14,   15,   13,   13,   13,   13,   13,    1,    1,   16,
+        1,   17,    1,    1,   19,   20,   21,   22,   23,   24,
+       25,   26,   27,   28,   29,   30,   31,   32,   33,   34,
+       35,   36,   37,   38,   39,   40,   41,   42,   43,   44,
+        1,    1,    1,    1,   18,    1,   19,   20,   21,   22,
+
+       23,   24,   25,   26,   27,   28,   29,   30,   31,   32,
+       33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
+       43,   44,   45,    1,   45,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[46] =
+    {   0,
+        1,    2,    3,    2,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    2
+    } ;
+
+static yyconst short int yy_base[562] =
+    {   0,
+        0,   44,  663,    0,  664,    0,  664,    8,   81,   22,
+       18,  100,   19,  123,  630,  642,  664,    0,    0,   29,
+       30,  628,   51,    0,   65,   68,   14,  159,  164,   61,
+       91,  170,   43,  623,  631,  625,  623,  623,   70,   68,
+       66,   86,  621,   93,  175,  181,  128,  111,  629,  628,
+      619,  626,  136,    0,   18,  207,  213,    0,  605,  629,
+       45,  615,  627,  612,  102,  627,  607,  605,  604,  607,
+      614,  602,  597,  593,  603,  604,  595,  599,  597,  173,
+      603,  596,  596,  594,  588,  603,  601,  587,  586,  593,
+      598,  581,  100,  594,  597,  578,  596,  595,  578,  593,
+
+      584,  209,  568,  586,  176,  570,  578,  577,  588,  575,
+        0,  574,  566,  570,    0,  589,    0,  572,  577,  567,
+      563,  573,  558,  556,  562,  199,  555,    0,  552,  572,
+      550,  551,  566,  562,  567,  539,  563,  558,  562,  540,
+      561,    0,  547,  538,  543,  536,  550,  538,  146,  548,
+      546,  538,  548,  544,  543,  527,  532,  520,  545,  542,
+      195,  528,  529,  519,  535,  518,  525,  537,  528,   48,
+      520,  519,  526,  174,  532,  516,  515,    0,  514,  513,
+      506,  538,  500,  518,  517,  519,  502,  507,  530,  512,
+      507,  510,  499,  509,  513,    0,  510,  497,  508,  502,
+
+        0,  508,  493,  506,  496,  487,    0,  481,  500,  480,
+      480,  499,  498,  478,  486,  482,  494,  491,  472,  487,
+      471,  487,  467,  479,    0,  486,  464,  484,  483,  482,
+      471,   79,  474,  469,  474,  471,    0,  470,  465,  452,
+      465,  452,  471,  455,  469,    0,  452,  451,  450,  449,
+      458,  461,  231,  443,  461,  444,  445,  452,  457,  451,
+      450,  439,  438,  442,    0,  436,  448,  449,  448,    0,
+      437,    0,  440,  445,  439,  428,  442,  441,    0,    0,
+      430,  414,  438,    0,  424,  194,  415,  435,  419,  420,
+      416,    0,  425,    0,    0,    0,  416,  410,  428,  412,
+
+      411,  416,  424,  408,  402,  402,  399,  134,    0,  411,
+        0,  397,  396,  395,  394,  389,  398,    0,  408,    0,
+      409,  408,  409,    0,  408,  401,  385,  399,  389,  399,
+      389,    0,    0,  397,  398,    0,  393,  394,    0,    0,
+      395,  221,    0,  396,  373,  372,  372,    0,  384,  381,
+      375,  389,  388,  387,    0,  382,  377,  120,    0,  363,
+      362,  376,  372,  364,  377,  365,  357,  356,  355,  354,
+      230,  363,  350,  352,  357,    0,    0,  369,  368,  352,
+      364,  359,  364,  340,  357,  361,  354,  346,  358,  357,
+        0,  337,  336,  328,  347,  344,  351,    0,    0,    0,
+
+      344,  349,    0,  332,  347,  346,  345,  324,  324,  321,
+      335,  340,  339,  338,  337,    0,  321,  319,  328,  319,
+      313,  326,  330,    0,    0,  308,  307,  327,    0,  320,
+      319,    0,  324,  323,    0,    0,  299,  314,  303,  304,
+      309,    0,  317,    0,  301,    0,    0,    0,  315,  300,
+      307,  224,    0,    0,    0,    0,  302,  295,  303,  239,
+      286,  241,    0,  308,  301,    0,  287,  286,    0,    0,
+      298,  301,  296,  280,  279,    0,  294,    0,  298,  297,
+      294,  274,  280,  280,  292,    0,  271,  284,    0,  283,
+        0,  268,  266,  286,  285,  280,  283,  282,  281,  270,
+
+        0,    0,  264,  259,  277,  276,    0,  287,  274,  258,
+      246,  265,    0,    0,  264,    0,    0,    0,  248,  268,
+      257,    0,    0,  266,    0,  244,  244,  238,  262,  251,
+        0,  243,    0,  253,  227,  229,    0,  227,  242,  204,
+      209,  174,  160,    0,  122,   76,   35,   32,    0,   21,
+        1,    0,    0,    1,    0,  664,  266,    0,  269,  271,
+      273
+    } ;
+
+static yyconst short int yy_def[562] =
+    {   0,
+      557,  557,  556,  558,  556,  559,  556,  558,  558,  558,
+      558,  558,   12,  558,  558,  558,  556,  558,  559,  558,
+       12,  558,  558,  558,  560,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  560,  561,  558,  558,  558,   29,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  253,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,  558,  558,  558,  558,  558,
+      558,  558,  558,  558,  558,    0,  556,  556,  556,  556,
+      556
+    } ;
+
+static yyconst short int yy_nxt[710] =
+    {   0,
+       18,    5,    6,    7,  556,  556,    8,    9,   10,   11,
+       12,   13,   13,   13,   13,   14,   20,  555,   21,   21,
+       21,   21,   21,   24,   55,   55,   15,   25,   55,   55,
+      554,   16,   23,   23,   23,   23,   23,  553,   18,   23,
+       23,   23,   23,   23,   17,    5,    6,    7,  552,   18,
+        8,    9,   10,   11,   12,   13,   13,   13,   13,   14,
+       18,   23,   23,   23,   23,   23,   54,  551,   54,   76,
+       15,   18,   77,   28,  120,   16,  121,  239,   23,   23,
+       23,   23,   23,   59,   60,  240,   85,   61,   17,   20,
+       28,   21,   21,   21,   21,   21,   83,  298,   88,   62,
+
+       86,  299,   84,   87,   89,   90,  550,   22,   26,   54,
+       21,   21,   21,   21,   21,   94,   63,   95,  110,   27,
+       64,   91,   28,   65,   92,   96,  157,  111,  112,  158,
+       66,  125,  126,  113,  127,  107,  403,   54,  549,   54,
+      404,   29,   30,   31,   32,  108,   33,   34,   35,   36,
+       37,   38,   39,   40,   41,   42,   43,  364,   44,   45,
+       46,   47,   48,  365,   49,   56,   56,  109,  214,   57,
+       57,   57,   57,   57,   58,   58,   58,   58,   58,   97,
+       54,  215,   58,   58,   58,   58,   58,   58,   67,  142,
+       68,  548,  244,  143,  172,   98,   69,   99,  173,  102,
+
+      100,   70,  174,  103,  245,   71,  547,   72,   73,  144,
+      104,   74,   75,  227,  345,  101,  105,   57,   57,   57,
+       57,   57,  106,   57,   57,   57,   57,   57,  167,  192,
+      346,  546,  193,  168,  389,  390,  228,  229,  230,  545,
+      169,  318,  318,  318,  318,  318,  416,  481,  417,  318,
+      318,  318,  318,  318,  318,  486,  487,  489,  544,  543,
+      482,  490,  542,  418,  541,  419,    4,    4,    4,   19,
+       19,   53,   53,   54,   54,  540,  539,  538,  537,  536,
+      535,  534,  533,  532,  531,  530,  529,  528,  527,  526,
+      525,  524,  523,  522,  521,  520,  519,  518,  517,  516,
+
+      515,  514,  513,  512,  511,  510,  509,  508,  507,  506,
+      505,  504,  503,  502,  501,  500,  499,  498,  497,  496,
+      495,  494,  493,  492,  491,  488,  485,  484,  483,  480,
+      479,  478,  477,  476,  475,  474,  473,  472,  471,  470,
+      469,  468,  467,  466,  465,  464,  463,  462,  461,  460,
+      459,  458,  457,  456,  455,  454,  453,  452,  451,  450,
+      449,  448,  447,  446,  445,  444,  443,  442,  441,  440,
+      439,  438,  437,  436,  435,  434,  433,  432,  431,  430,
+      429,  428,  427,  426,  425,  424,  423,  422,  421,  420,
+      415,  414,  413,  412,  411,  410,  409,  408,  407,  406,
+
+      405,  402,  401,  400,  399,  398,  397,  396,  395,  394,
+      393,  392,  391,  388,  387,  386,  385,  384,  383,  382,
+      381,  380,  379,  378,  377,  376,  375,  374,  373,  372,
+      371,  370,  369,  368,  367,  366,  363,  362,  361,  360,
+      359,  358,  357,  356,  355,  354,  353,  352,  351,  350,
+      349,  348,  347,  344,  343,  342,  341,  340,  339,  338,
+      337,  336,  335,  334,  333,  332,  331,  330,  329,  328,
+      327,  326,  325,  324,  323,  322,  321,  320,  319,  317,
+      316,  315,  314,  313,  312,  311,  310,  309,  308,  307,
+      306,  305,  304,  303,  302,  301,  300,  297,  296,  295,
+
+      294,  293,  292,  291,  290,  289,  288,  287,  286,  285,
+      284,  283,  282,  281,  280,  279,  278,  277,  276,  275,
+      274,  273,  272,  271,  270,  269,  268,  267,  266,  265,
+      264,  263,  262,  261,  260,  259,  258,  257,  256,  255,
+      254,  253,  252,  251,  250,  249,  248,  247,  246,  243,
+      242,  241,  238,  237,  236,  235,  234,  233,  232,  231,
+      226,  225,  224,  223,  222,  221,  220,  219,  218,  217,
+      216,  213,  212,  211,  210,  209,  208,  207,  206,  205,
+      204,  203,  202,  201,  200,  199,  198,  197,  196,  195,
+      194,  191,  190,  189,  188,  187,  186,  185,  184,  183,
+
+      182,  181,  180,  179,  178,  177,  176,  175,  171,  170,
+      166,  165,  164,  163,  162,  161,  160,  159,  156,  155,
+      154,  153,  152,  151,  150,  149,  148,  147,  146,  145,
+      141,  140,  139,  138,  137,  136,  135,  134,  133,  132,
+      131,  130,  129,  128,  124,  123,  122,  119,  118,  117,
+      116,  115,  114,   93,   82,   81,   80,   79,   78,   52,
+       51,   50,  556,    3,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+
+      556,  556,  556,  556,  556,  556,  556,  556,  556
+    } ;
+
+static yyconst short int yy_chk[710] =
+    {   0,
+      558,    1,    1,    1,    0,    0,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    8,  554,    8,    8,
+        8,    8,    8,   11,   27,   27,    1,   11,   55,   55,
+      551,    1,   10,   10,   10,   10,   10,  550,   13,   20,
+       20,   20,   20,   20,    1,    2,    2,    2,  548,   21,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+       13,   23,   23,   23,   23,   23,   25,  547,   25,   33,
+        2,   21,   33,   23,   61,    2,   61,  170,   26,   26,
+       26,   26,   26,   30,   30,  170,   40,   30,    2,    9,
+       26,    9,    9,    9,    9,    9,   39,  232,   41,   30,
+
+       40,  232,   39,   40,   41,   42,  546,    9,   12,   25,
+       12,   12,   12,   12,   12,   44,   31,   44,   48,   12,
+       31,   42,   12,   31,   42,   44,   93,   48,   48,   93,
+       31,   65,   65,   48,   65,   47,  358,   53,  545,   53,
+      358,   12,   14,   14,   14,   47,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,  308,   14,   14,
+       14,   14,   14,  308,   14,   28,   28,   47,  149,   28,
+       28,   28,   28,   28,   29,   29,   29,   29,   29,   45,
+       53,  149,   29,   29,   29,   29,   29,   29,   32,   80,
+       32,  543,  174,   80,  105,   45,   32,   45,  105,   46,
+
+       45,   32,  105,   46,  174,   32,  542,   32,   32,   80,
+       46,   32,   32,  161,  286,   45,   46,   56,   56,   56,
+       56,   56,   46,   57,   57,   57,   57,   57,  102,  126,
+      286,  541,  126,  102,  342,  342,  161,  161,  161,  540,
+      102,  253,  253,  253,  253,  253,  371,  452,  371,  253,
+      253,  253,  253,  253,  253,  460,  460,  462,  539,  538,
+      452,  462,  536,  371,  535,  371,  557,  557,  557,  559,
+      559,  560,  560,  561,  561,  534,  532,  530,  529,  528,
+      527,  526,  524,  521,  520,  519,  515,  512,  511,  510,
+      509,  508,  506,  505,  504,  503,  500,  499,  498,  497,
+
+      496,  495,  494,  493,  492,  490,  488,  487,  485,  484,
+      483,  482,  481,  480,  479,  477,  475,  474,  473,  472,
+      471,  468,  467,  465,  464,  461,  459,  458,  457,  451,
+      450,  449,  445,  443,  441,  440,  439,  438,  437,  434,
+      433,  431,  430,  428,  427,  426,  423,  422,  421,  420,
+      419,  418,  417,  415,  414,  413,  412,  411,  410,  409,
+      408,  407,  406,  405,  404,  402,  401,  397,  396,  395,
+      394,  393,  392,  390,  389,  388,  387,  386,  385,  384,
+      383,  382,  381,  380,  379,  378,  375,  374,  373,  372,
+      370,  369,  368,  367,  366,  365,  364,  363,  362,  361,
+
+      360,  357,  356,  354,  353,  352,  351,  350,  349,  347,
+      346,  345,  344,  341,  338,  337,  335,  334,  331,  330,
+      329,  328,  327,  326,  325,  323,  322,  321,  319,  317,
+      316,  315,  314,  313,  312,  310,  307,  306,  305,  304,
+      303,  302,  301,  300,  299,  298,  297,  293,  291,  290,
+      289,  288,  287,  285,  283,  282,  281,  278,  277,  276,
+      275,  274,  273,  271,  269,  268,  267,  266,  264,  263,
+      262,  261,  260,  259,  258,  257,  256,  255,  254,  252,
+      251,  250,  249,  248,  247,  245,  244,  243,  242,  241,
+      240,  239,  238,  236,  235,  234,  233,  231,  230,  229,
+
+      228,  227,  226,  224,  223,  222,  221,  220,  219,  218,
+      217,  216,  215,  214,  213,  212,  211,  210,  209,  208,
+      206,  205,  204,  203,  202,  200,  199,  198,  197,  195,
+      194,  193,  192,  191,  190,  189,  188,  187,  186,  185,
+      184,  183,  182,  181,  180,  179,  177,  176,  175,  173,
+      172,  171,  169,  168,  167,  166,  165,  164,  163,  162,
+      160,  159,  158,  157,  156,  155,  154,  153,  152,  151,
+      150,  148,  147,  146,  145,  144,  143,  141,  140,  139,
+      138,  137,  136,  135,  134,  133,  132,  131,  130,  129,
+      127,  125,  124,  123,  122,  121,  120,  119,  118,  116,
+
+      114,  113,  112,  110,  109,  108,  107,  106,  104,  103,
+      101,  100,   99,   98,   97,   96,   95,   94,   92,   91,
+       90,   89,   88,   87,   86,   85,   84,   83,   82,   81,
+       79,   78,   77,   76,   75,   74,   73,   72,   71,   70,
+       69,   68,   67,   66,   64,   63,   62,   60,   59,   52,
+       51,   50,   49,   43,   38,   37,   36,   35,   34,   22,
+       16,   15,    3,  556,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+      556,  556,  556,  556,  556,  556,  556,  556,  556,  556,
+
+      556,  556,  556,  556,  556,  556,  556,  556,  556
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer.lxx"
+#define INITIAL 0
+/*
+// Filename: lexer.l
+// Created by:  drose (16Jan99)
+// 
+////////////////////////////////////////////////////////////////////
+*/
+#line 9 "lexer.lxx"
+#include "lexerDefs.h"
+#include "parserDefs.h"
+#include "config_egg.h"
+#include "parser.h"
+
+#include <indent.h>
+#include <notify.h>
+
+#include <math.h>
+#include <pandabase.h>
+
+extern "C" int eggyywrap(void);  // declared below.
+
+static int yyinput(void);        // declared by flex.
+
+
+////////////////////////////////////////////////////////////////////
+// Static variables
+////////////////////////////////////////////////////////////////////
+
+// We'll increment line_number and col_number as we parse the file, so
+// that we can report the position of an error.
+static int line_number = 0;
+static int col_number = 0;
+
+// current_line holds as much of the current line as will fit.  Its
+// only purpose is for printing it out to report an error to the user.
+static const int max_error_width = 1024;
+static char current_line[max_error_width + 1];
+
+static int error_count = 0;
+static int warning_count = 0;
+
+// This is the pointer to the current input stream.
+static istream *inp = NULL;
+
+// This is the name of the egg file we're parsing.  We keep it so we
+// can print it out for error messages.
+static string egg_filename;
+
+// This is the initial token state returned by the lexer.  It allows
+// the yacc grammar to start from initial points.
+static int initial_token;
+
+
+////////////////////////////////////////////////////////////////////
+// Defining the interface to the lexer.
+////////////////////////////////////////////////////////////////////
+
+void
+egg_init_lexer(istream &in, const string &filename) {
+  inp = &in;
+  egg_filename = filename;
+  line_number = 0;
+  col_number = 0;
+  error_count = 0;
+  warning_count = 0;
+  initial_token = START_EGG;
+}
+
+void
+egg_start_group_body() {
+  /* Set the initial state to begin within a group_body context,
+     instead of at the beginning of the egg file. */
+  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
+egg_error_count() {
+  return error_count;
+}
+
+int
+egg_warning_count() {
+  return warning_count;
+}
+
+
+////////////////////////////////////////////////////////////////////
+// Internal support functions.
+////////////////////////////////////////////////////////////////////
+
+int
+eggyywrap(void) {
+  return 1;
+}
+
+void
+eggyyerror(const string &msg) {
+  if (egg_cat.is_error()) {
+    ostream &out = egg_cat.error(false);
+
+    out << "\nError";
+    if (!egg_filename.empty()) {
+      out << " in " << egg_filename;
+    }
+    out 
+      << " at line " << line_number << ", column " << col_number << ":\n"
+      << setiosflags(Notify::get_literal_flag())
+      << current_line << "\n";
+    indent(out, col_number-1) 
+      << "^\n" << msg << "\n\n" 
+      << resetiosflags(Notify::get_literal_flag()) << flush;
+  }
+  error_count++;
+}
+
+void
+eggyyerror(ostringstream &strm) {
+  string s = strm.str();
+  eggyyerror(s);
+}
+
+void
+eggyywarning(const string &msg) {
+  if (egg_cat.is_warning()) {
+    ostream &out = egg_cat.warning(false);
+
+    out << "\nWarning";
+    if (!egg_filename.empty()) {
+      out << " in " << egg_filename;
+    }
+    out 
+      << " at line " << line_number << ", column " << col_number << ":\n"
+      << setiosflags(Notify::get_literal_flag())
+      << current_line << "\n";
+    indent(out, col_number-1) 
+      << "^\n" << msg << "\n\n" 
+      << resetiosflags(Notify::get_literal_flag()) << flush;
+  }
+  warning_count++;
+}
+
+void
+eggyywarning(ostringstream &strm) {
+  string s = strm.str();
+  eggyywarning(s);
+}
+
+// Now define a function to take input from an istream instead of a
+// stdio FILE pointer.  This is flex-specific.
+static void
+input_chars(char *buffer, int &result, int max_size) {
+  nassertv(inp != NULL);
+  if (*inp) {
+    inp->read(buffer, max_size);
+    result = inp->gcount();
+
+    if (line_number == 0) {
+      // This is a special case.  If we are reading the very first bit
+      // from the stream, copy it into the current_line array.  This
+      // is because the \n.* rule below, which fills current_line
+      // normally, doesn't catch the first line.
+      int length = min(max_error_width, result);
+      strncpy(current_line, buffer, length);
+      current_line[length] = '\0';
+      line_number++;
+      col_number = 0;
+
+      // Truncate it at the newline.
+      char *end = strchr(current_line, '\n');
+      if (end != NULL) {
+        *end = '\0';
+      }
+    }
+
+  } else {
+    // End of file or I/O error.
+    result = 0;
+  }
+}
+#undef YY_INPUT
+#define YY_INPUT(buffer, result, max_size) input_chars(buffer, result, max_size)
+
+// read_char reads and returns a single character, incrementing the
+// supplied line and column numbers as appropriate.  A convenience
+// function for the scanning functions below.
+static int
+read_char(int &line, int &col) {
+  int c = yyinput();
+  if (c == '\n') {
+    line++;
+    col = 0;
+  } else {
+    col++;
+  }
+  return c;
+}
+
+// scan_quoted_string reads a string delimited by quotation marks and
+// returns it.
+static string
+scan_quoted_string() {
+  string result;
+
+  // We don't touch the current line number and column number during
+  // scanning, so that if we detect an error while scanning the string
+  // (e.g. an unterminated string), we'll report the error as
+  // occurring at the start of the string, not at the end--somewhat
+  // more convenient for the user.
+
+  // Instead of adjusting the global line_number and col_number
+  // variables, we'll operate on our own local variables for the
+  // interim.
+  int line = line_number;
+  int col = col_number;
+
+  int c;
+  c = read_char(line, col);
+  while (c != '"' && c != EOF) {
+    result += c;
+    c = read_char(line, col);
+  }
+
+  if (c == EOF) {
+    eggyyerror("This quotation mark is unterminated.");
+  }
+
+  line_number = line;
+  col_number = col;
+
+  return result;
+}
+
+// eat_c_comment scans past all characters up until the first */
+// encountered.
+static void
+eat_c_comment() {
+  // As above, we'll operate on our own local copies of line_number
+  // and col_number within this function.
+
+  int line = line_number;
+  int col = col_number;
+
+  int c, last_c;
+  
+  last_c = '\0';
+  c = read_char(line, col);
+  while (c != EOF && !(last_c == '*' && c == '/')) {
+    if (last_c == '/' && c == '*') {
+      ostringstream errmsg;
+      errmsg << "This comment contains a nested /* symbol at line "
+             << line << ", column " << col-1 << "--possibly unclosed?"
+             << ends;
+      eggyywarning(errmsg);
+    }
+    last_c = c;
+    c = read_char(line, col);
+  }
+
+  if (c == EOF) {
+    eggyyerror("This comment marker is unclosed.");
+  }
+
+  line_number = line;
+  col_number = col;
+}
+
+
+// accept() is called below as each piece is pulled off and
+// accepted by the lexer; it increments the current column number.
+INLINE void accept() {
+  col_number += yyleng;
+}
+
+#line 1004 "lex.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp = NULL, *yy_bp = NULL;
+	register int yy_act;
+
+#line 290 "lexer.lxx"
+
+
+
+  if (initial_token != 0) {
+    int t = initial_token;
+    initial_token = 0;
+    return t;
+  }
+
+
+#line 1166 "lex.yy.c"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 557 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 664 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 300 "lexer.lxx"
+{
+  // New line.  Save a copy of the line so we can print it out for the
+  // benefit of the user in case we get an error.
+
+  strncpy(current_line, yytext+1, max_error_width);
+  current_line[max_error_width] = '\0';
+  line_number++;
+  col_number=0;
+
+  // Return the whole line to the lexer, except the newline character,
+  // which we eat.
+  yyless(1);
+}
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 314 "lexer.lxx"
+{ 
+  // Eat whitespace.
+  accept();
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 319 "lexer.lxx"
+{ 
+  // Eat C++-style comments.
+  accept();
+}
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 324 "lexer.lxx"
+{
+  // Eat C-style comments.
+  accept();
+  eat_c_comment(); 
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 330 "lexer.lxx"
+{
+  // Send curly braces as themselves.
+  accept(); 
+  return eggyytext[0];
+}
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 338 "lexer.lxx"
+{
+  accept();
+  return BEZIERCURVE;
+}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 342 "lexer.lxx"
+{
+  accept();
+  return BFACE;
+}
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 346 "lexer.lxx"
+{
+  accept();
+  return BILLBOARD;
+}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 350 "lexer.lxx"
+{
+  accept();
+  return BILLBOARDCENTER;
+}
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 354 "lexer.lxx"
+{
+  accept();
+  return BINORMAL;
+}
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 358 "lexer.lxx"
+{
+  accept();
+  return BUNDLE;
+}
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 362 "lexer.lxx"
+{
+  accept();
+  return SCALAR;
+}
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 366 "lexer.lxx"
+{
+  accept();
+  return CLOSED;
+}
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 370 "lexer.lxx"
+{
+  accept();
+  return COLLIDE;
+}
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 374 "lexer.lxx"
+{
+  accept();
+  return COMMENT;
+}
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 378 "lexer.lxx"
+{
+  accept();
+  return COMPONENT;
+}
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 382 "lexer.lxx"
+{
+  accept();
+  return COORDSYSTEM;
+}
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 386 "lexer.lxx"
+{
+  accept();
+  return CV;
+}
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 390 "lexer.lxx"
+{
+  accept();
+  return DART;
+}
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 394 "lexer.lxx"
+{
+  accept();
+  return DNORMAL;
+}
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 398 "lexer.lxx"
+{
+  accept();
+  return DRGBA;
+}
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 402 "lexer.lxx"
+{
+  accept();
+  return DUV;
+}
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 406 "lexer.lxx"
+{
+  accept();
+  return DXYZ;
+}
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 410 "lexer.lxx"
+{
+  accept();
+  return DCS;
+}
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 414 "lexer.lxx"
+{
+  accept();
+  return DISTANCE;
+}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 418 "lexer.lxx"
+{
+  accept();
+  return DTREF;
+}
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 422 "lexer.lxx"
+{
+  accept();
+  return DYNAMICVERTEXPOOL;
+}
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 426 "lexer.lxx"
+{
+  accept();
+  return EXTERNAL_FILE;
+}
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 430 "lexer.lxx"
+{
+  accept();
+  return FLIGHT;
+}
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 434 "lexer.lxx"
+{
+  accept();
+  return GROUP;
+}
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 438 "lexer.lxx"
+{
+  accept();
+  return HIP;
+}
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 442 "lexer.lxx"
+{
+  accept();
+  return INTANGENT;
+}
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 446 "lexer.lxx"
+{
+  accept();
+  return JOINT;
+}
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 450 "lexer.lxx"
+{
+  accept();
+  return KNOTS;
+}
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 454 "lexer.lxx"
+{
+  accept();
+  return INCLUDE;
+}
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 458 "lexer.lxx"
+{
+  accept();
+  return INSTANCE;
+}
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 462 "lexer.lxx"
+{
+  accept();
+  return LINE;
+}
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 466 "lexer.lxx"
+{
+  accept();
+  return LOOP;
+}
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 470 "lexer.lxx"
+{
+  accept();
+  return MATERIAL;
+}
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 474 "lexer.lxx"
+{
+  accept();
+  return MATRIX3;
+}
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 478 "lexer.lxx"
+{
+  accept();
+  return MATRIX4;
+}
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 482 "lexer.lxx"
+{
+  accept();
+  return MODEL;
+}
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 486 "lexer.lxx"
+{
+  accept();
+  return MREF;
+}
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 490 "lexer.lxx"
+{
+  accept();
+  return NORMAL;
+}
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 494 "lexer.lxx"
+{
+  accept();
+  return NURBSCURVE;
+}
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 498 "lexer.lxx"
+{
+  accept();
+  return NURBSSURFACE;
+}
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 502 "lexer.lxx"
+{
+  accept();
+  return OBJECTTYPE;
+}
+	YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 506 "lexer.lxx"
+{
+  accept();
+  return ORDER;
+}
+	YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 510 "lexer.lxx"
+{
+  accept();
+  return OUTTANGENT;
+}
+	YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 514 "lexer.lxx"
+{
+  accept();
+  return POINTLIGHT;
+}
+	YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 518 "lexer.lxx"
+{
+  accept();
+  return POLYGON;
+}
+	YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 522 "lexer.lxx"
+{
+  accept();
+  return REF;
+}
+	YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 526 "lexer.lxx"
+{
+  accept();
+  return RGBA;
+}
+	YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 530 "lexer.lxx"
+{
+  accept();
+  return ROTATE;
+}
+	YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 534 "lexer.lxx"
+{
+  accept();
+  return ROTX;
+}
+	YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 538 "lexer.lxx"
+{
+  accept();
+  return ROTY;
+}
+	YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 542 "lexer.lxx"
+{
+  accept();
+  return ROTZ;
+}
+	YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 546 "lexer.lxx"
+{
+  accept();
+  return SANIM;
+}
+	YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 550 "lexer.lxx"
+{
+  accept();
+  return SCALAR;
+}
+	YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 554 "lexer.lxx"
+{
+  accept();
+  return SCALE;
+}
+	YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 558 "lexer.lxx"
+{
+  accept();
+  return SEQUENCE;
+}
+	YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 562 "lexer.lxx"
+{
+  accept();
+  return SHADING;
+}
+	YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 566 "lexer.lxx"
+{
+  accept();
+  return SWITCH;
+}
+	YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 570 "lexer.lxx"
+{
+  accept();
+  return SWITCHCONDITION;
+}
+	YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 574 "lexer.lxx"
+{
+  accept();
+  return TABLE;
+}
+	YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 578 "lexer.lxx"
+{
+  accept();
+  return TABLE_V;
+}
+	YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 582 "lexer.lxx"
+{
+  accept();
+  return TAG;
+}
+	YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 586 "lexer.lxx"
+{
+  accept();
+  return TANGENT;
+}
+	YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 590 "lexer.lxx"
+{
+  accept();
+  return TEXLIST;
+}
+	YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 594 "lexer.lxx"
+{
+  accept();
+  return TEXTURE;
+}
+	YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 598 "lexer.lxx"
+{
+  accept();
+  return TLENGTHS;
+}
+	YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 602 "lexer.lxx"
+{
+  accept();
+  return TRANSFORM;
+}
+	YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 606 "lexer.lxx"
+{
+  accept();
+  return TRANSLATE;
+}
+	YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 610 "lexer.lxx"
+{
+  accept();
+  return TREF;
+}
+	YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 614 "lexer.lxx"
+{
+  accept();
+  return TRIANGLEFAN;
+}
+	YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 618 "lexer.lxx"
+{
+  accept();
+  return TRIANGLESTRIP;
+}
+	YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 622 "lexer.lxx"
+{
+  accept();
+  return TRIM;
+}
+	YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 626 "lexer.lxx"
+{
+  accept();
+  return TXT;
+}
+	YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 630 "lexer.lxx"
+{
+  accept();
+  return UKNOTS;
+}
+	YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 634 "lexer.lxx"
+{
+  accept();
+  return UKNOTS;
+}
+	YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 638 "lexer.lxx"
+{
+  accept();
+  return UV;
+}
+	YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 642 "lexer.lxx"
+{
+  accept();
+  return VKNOTS;
+}
+	YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 646 "lexer.lxx"
+{
+  accept();
+  return VKNOTS;
+}
+	YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 650 "lexer.lxx"
+{
+  accept();
+  return VERTEX;
+}
+	YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 654 "lexer.lxx"
+{
+  accept();
+  return VERTEXANIM;
+}
+	YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 658 "lexer.lxx"
+{
+  accept();
+  return VERTEXPOOL;
+}
+	YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 662 "lexer.lxx"
+{
+  accept();
+  return VERTEXREF;
+}
+	YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 666 "lexer.lxx"
+{
+  accept();
+  return XFMANIM;
+}
+	YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 670 "lexer.lxx"
+{
+  accept();
+  return XFMSANIM;
+}
+	YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 677 "lexer.lxx"
+{ 
+  // An integer or floating-point number.
+  accept(); 
+  eggyylval._number = atof(eggyytext); 
+  eggyylval._string = yytext;
+  return NUMBER; 
+}
+	YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 685 "lexer.lxx"
+{
+  // A hexadecimal integer number.
+  accept(); 
+  eggyylval._ulong = strtoul(yytext+2, NULL, 16);
+  eggyylval._string = yytext;
+  return ULONG; 
+}
+	YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 693 "lexer.lxx"
+{
+  // A binary integer number.
+  accept(); 
+  eggyylval._ulong = strtoul(yytext+2, NULL, 2);
+  eggyylval._string = yytext;
+  return ULONG; 
+}
+	YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 701 "lexer.lxx"
+{
+  // not-a-number.  These sometimes show up in egg files accidentally.
+  accept(); 
+  memset(&eggyylval._number, 0, sizeof(eggyylval._number));
+  *(unsigned long *)&eggyylval._number = strtoul(yytext+3, NULL, 0);
+  eggyylval._string = yytext;
+  return NUMBER;
+}
+	YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 710 "lexer.lxx"
+{ 
+  // infinity.  As above.
+  accept(); 
+  eggyylval._number = HUGE_VAL;
+  eggyylval._string = yytext;
+  return NUMBER; 
+}
+	YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 718 "lexer.lxx"
+{
+  // minus infinity.  As above.
+  accept(); 
+  eggyylval._number = -HUGE_VAL;
+  eggyylval._string = yytext;
+  return NUMBER; 
+}
+	YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 727 "lexer.lxx"
+{
+  // Quoted string.
+  accept();
+  eggyylval._string = scan_quoted_string();
+  return STRING;
+}
+	YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 734 "lexer.lxx"
+{ 
+  // Unquoted string.
+  accept();
+  eggyylval._string = yytext;
+  return STRING;
+}
+	YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 740 "lexer.lxx"
+ECHO;
+	YY_BREAK
+#line 2064 "lex.yy.c"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 557 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 557 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 556);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+#endif /* YY_NO_INPUT */
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 740 "lexer.lxx"

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 440 - 435
panda/src/egg/parser.cxx.prebuilt


+ 2 - 2
panda/src/egg/parser.h.prebuilt

@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875b.  */
+/* A Bison parser, made by GNU Bison 2.0.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by

+ 104 - 99
panda/src/egg/parser.yxx

@@ -622,7 +622,7 @@ texture_body:
     eggyywarning("Unsupported texture scalar: " + name);
   }
 }
-        | texture_body transform_2d
+        | texture_body transform
         ;
 
 /*
@@ -955,6 +955,10 @@ vertex_uv_body:
         real real
 {
   DCAST(EggVertexUV, egg_stack.back())->set_uv(TexCoordd($1, $2));
+}
+        | real real real
+{
+  DCAST(EggVertexUV, egg_stack.back())->set_uvw(LVecBase3d($1, $2, $3));
 }
         | vertex_uv_body TANGENT '{' real real real '}'
 {
@@ -975,15 +979,31 @@ vertex_uv_body:
         | vertex_uv_body DUV string '{' real real '}'
 {
   bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
-    insert(EggMorphTexCoord($3, LVector2d($5, $6))).second;
+    insert(EggMorphTexCoord($3, LVector3d($5, $6, 0.0))).second;
+  if (!inserted) {
+    eggyywarning("Ignoring repeated morph name " + $3);
+  }
+}
+        | vertex_uv_body DUV string '{' real real real '}'
+{
+  bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
+    insert(EggMorphTexCoord($3, LVector3d($5, $6, $7))).second;
   if (!inserted) {
     eggyywarning("Ignoring repeated morph name " + $3);
   }
 }
-       | vertex_uv_body DUV '{' string real real '}'
+        | vertex_uv_body DUV '{' string real real '}'
+{
+  bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
+    insert(EggMorphTexCoord($4, LVector3d($5, $6, 0.0))).second;
+  if (!inserted) {
+    eggyywarning("Ignoring repeated morph name " + $4);
+  }
+}
+        | vertex_uv_body DUV '{' string real real real '}'
 {
   bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
-    insert(EggMorphTexCoord($4, LVector2d($5, $6))).second;
+    insert(EggMorphTexCoord($4, LVector3d($5, $6, $7))).second;
   if (!inserted) {
     eggyywarning("Ignoring repeated morph name " + $4);
   }
@@ -1343,7 +1363,7 @@ group_body:
   int value = (int)$4;
   group->set_texlist_flag(value!=0);
 }
-        | group_body transform_3d
+        | group_body transform
         | group_body group_vertex_ref
         | group_body switchcondition
         | group_body node
@@ -1406,163 +1426,148 @@ collide_flags:
         ;
 
 /*
- * transform_3d
+ * transform
  *
- * enter: TOS is EggGroup.
- * exit: group's transform matrix has been set.
+ * enter: TOS is some kind of EggTransform.
+ * exit: transform matrix has been set.
  *
  */
-transform_3d:
+transform:
         TRANSFORM
 {
-  DCAST(EggGroup, egg_stack.back())->clear_transform();
+  egg_stack.back()->as_transform()->clear_transform();
 }
-        '{' transform_3d_body '}'
+        '{' transform_body '}'
         ;
 
 
 /*
- * transform_3d_body
+ * transform_body
  *
- * enter: matrix_3d contains some sensible value.
- * exit: matrix_3d has been transformed by the parsed transformation.
+ * enter: TOS is some kind of EggTransform.
+ * exit: transform has been filled in.
  *
  */
-transform_3d_body:
+transform_body:
           empty
-        | transform_3d_body translate_3d
-        | transform_3d_body rotx_3d
-        | transform_3d_body roty_3d
-        | transform_3d_body rotz_3d
-        | transform_3d_body rotate_3d
-        | transform_3d_body scale_3d
-        | transform_3d_body matrix4_3d
+        | transform_body translate2d
+        | transform_body translate3d
+        | transform_body rotate2d
+        | transform_body rotx
+        | transform_body roty
+        | transform_body rotz
+        | transform_body rotate3d
+        | transform_body scale2d
+        | transform_body scale3d
+        | transform_body uniform_scale
+        | transform_body matrix3
+        | transform_body matrix4
         ;
 
-translate_3d: TRANSLATE '{' real real real '}'
+translate2d:
+        TRANSLATE '{' real real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_translate(LVector3d($3, $4, $5));
+  egg_stack.back()->as_transform()->add_translate2d(LVector2d($3, $4));
 }
         ;
 
-rotx_3d: ROTX '{' real '}'
+translate3d:
+        TRANSLATE '{' real real real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_rotx($3);
+  egg_stack.back()->as_transform()->add_translate3d(LVector3d($3, $4, $5));
 }
         ;
 
-roty_3d: ROTY '{' real '}'
+rotate2d:
+        ROTATE '{' real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_roty($3);
+  egg_stack.back()->as_transform()->add_rotate2d($3);
 }
         ;
 
-rotz_3d: ROTZ '{' real '}'
+rotx:
+        ROTX '{' real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_rotz($3);
+  egg_stack.back()->as_transform()->add_rotx($3);
 }
         ;
 
-rotate_3d: ROTATE '{' real real real real '}'
+roty:
+        ROTY '{' real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_rotate($3, LVector3d($4, $5, $6));
+  egg_stack.back()->as_transform()->add_roty($3);
 }
         ;
 
-scale_3d: SCALE '{' real real real '}'
+rotz:
+        ROTZ '{' real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_scale(LVecBase3d($3, $4, $5));
+  egg_stack.back()->as_transform()->add_rotz($3);
 }
-	| SCALE '{' real '}'
-{
-  DCAST(EggGroup, egg_stack.back())->add_uniform_scale($3);
-}
-        ;
-
-matrix4_3d:
-        MATRIX4 '{' matrix4_3d_body '}'
         ;
 
-matrix4_3d_body: 
-          empty
-        | real real real real
-          real real real real 
-          real real real real 
-          real real real real 
+rotate3d:
+	ROTATE '{' real real real real '}'
 {
-  DCAST(EggGroup, egg_stack.back())->add_matrix
-    (LMatrix4d($1, $2, $3, $4,
-               $5, $6, $7, $8,
-               $9, $10, $11, $12,
-               $13, $14, $15, $16));
+  egg_stack.back()->as_transform()->add_rotate3d($3, LVector3d($4, $5, $6));
 }
         ;
 
-
-/*
- * transform_2d
- *
- * enter: TOS is EggTexture.
- * exit: texture's transform matrix has been set.
- *
- */
-transform_2d:
-        TRANSFORM
+scale2d:
+        SCALE '{' real real '}'
 {
-  matrix_2d = LMatrix3d::ident_mat();
+  egg_stack.back()->as_transform()->add_scale2d(LVecBase2d($3, $4));
 }
-        '{' transform_2d_body '}'
-{
-  DCAST(EggTexture, egg_stack.back())->set_transform(matrix_2d);
-}
-        ;
-
-
-/*
- * transform_2d_body
- *
- * enter: matrix contains some sensible value.
- * exit: matrix has been transformed by the parsed transformation.
- *
- */
-transform_2d_body:
-          empty
-        | transform_2d_body matrix3_2d
-        | transform_2d_body translate_2d
-        | transform_2d_body rotate_2d
-        | transform_2d_body scale_2d
         ;
 
-translate_2d: TRANSLATE '{' real real '}'
+scale3d:
+	SCALE '{' real real real '}'
 {
-  matrix_2d *= LMatrix3d::translate_mat($3, $4);
+  egg_stack.back()->as_transform()->add_scale3d(LVecBase3d($3, $4, $5));
 }
-        ;
+	;
 
-rotate_2d: ROTATE '{' real '}'
+uniform_scale:
+	SCALE '{' real '}'
 {
-  matrix_2d *= LMatrix3d::rotate_mat($3);
+  egg_stack.back()->as_transform()->add_uniform_scale($3);
 }
         ;
 
-scale_2d: SCALE '{' real real '}'
+matrix3:
+        MATRIX3 '{' matrix3_body '}'
+        ;
+
+matrix3_body: 
+          empty
+        | real real real real
+          real real real real 
+          real real real real 
+          real real real real 
 {
-  matrix_2d *= LMatrix3d::scale_mat($3, $4);
+  egg_stack.back()->as_transform()->add_matrix3
+    (LMatrix3d($1, $2, $3,
+               $4, $5, $6,
+               $7, $8, $9));
 }
         ;
 
-matrix3_2d: MATRIX3 '{' matrix3_2d_body '}'
+matrix4:
+        MATRIX4 '{' matrix4_body '}'
         ;
 
-matrix3_2d_body: 
+matrix4_body: 
           empty
-        | real real real
-          real real real
-          real real real
+        | real real real real
+          real real real real 
+          real real real real 
+          real real real real 
 {
-  matrix_2d *= LMatrix3d($1, $2, $3,
-                         $4, $5, $6,
-                         $7, $8, $9);
+  egg_stack.back()->as_transform()->add_matrix4
+    (LMatrix4d($1, $2, $3, $4,
+               $5, $6, $7, $8,
+               $9, $10, $11, $12,
+               $13, $14, $15, $16));
 }
         ;
 

+ 144 - 112
panda/src/egg2pg/eggLoader.cxx

@@ -391,6 +391,126 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggLoader::make_transform
+//       Access: Public, Static
+//  Description: Creates a TransformState object corresponding to the
+//               indicated EggTransform.
+////////////////////////////////////////////////////////////////////
+CPT(TransformState) EggLoader::
+make_transform(const EggTransform *egg_transform) {
+  // We'll build up the transform componentwise, so we preserve any
+  // componentwise properties of the egg transform.
+
+  CPT(TransformState) ts = TransformState::make_identity();
+  int num_components = egg_transform->get_num_components();
+  for (int i = 0; i < num_components; i++) {
+    switch (egg_transform->get_component_type(i)) {
+    case EggTransform::CT_translate2d:
+      {
+        LVecBase2f trans2d(LCAST(float, egg_transform->get_component_vec2(i)));
+        LVecBase3f trans3d(trans2d[0], trans2d[1], 0.0f);
+        ts = TransformState::make_pos(trans3d)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_translate3d:
+      {
+        LVecBase3f trans3d(LCAST(float, egg_transform->get_component_vec3(i)));
+        ts = TransformState::make_pos(trans3d)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_rotate2d:
+      {
+        LRotationf rot(LVector3f(0.0f, 0.0f, 1.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_rotx:
+      {
+        LRotationf rot(LVector3f(1.0f, 0.0f, 0.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_roty:
+      {
+        LRotationf rot(LVector3f(0.0f, 1.0f, 0.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_rotz:
+      {
+        LRotationf rot(LVector3f(0.0f, 0.0f, 1.0f),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_rotate3d:
+      {
+        LRotationf rot(LCAST(float, egg_transform->get_component_vec3(i)),
+                       (float)egg_transform->get_component_number(i));
+        ts = TransformState::make_quat(rot)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_scale2d:
+      {
+        LVecBase2f scale2d(LCAST(float, egg_transform->get_component_vec2(i)));
+        LVecBase3f scale3d(scale2d[0], scale2d[1], 1.0f);
+        ts = TransformState::make_scale(scale3d)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_scale3d:
+      {
+        LVecBase3f scale3d(LCAST(float, egg_transform->get_component_vec3(i)));
+        ts = TransformState::make_scale(scale3d)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_uniform_scale:
+      {
+        float scale = (float)egg_transform->get_component_number(i);
+        ts = TransformState::make_scale(scale)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_matrix3:
+      {
+        LMatrix3f m(LCAST(float, egg_transform->get_component_mat3(i)));
+        LMatrix4f mat4(m(0, 0), m(0, 1), 0.0, m(0, 2),
+                       m(1, 0), m(1, 1), 0.0, m(1, 2),
+                       0.0, 0.0, 1.0, 0.0,
+                       m(2, 0), m(2, 1), 0.0, m(2, 2));
+
+        ts = TransformState::make_mat(mat4)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_matrix4:
+      {
+        LMatrix4f mat4(LCAST(float, egg_transform->get_component_mat4(i)));
+        ts = TransformState::make_mat(mat4)->compose(ts);
+      }
+      break;
+
+    case EggTransform::CT_invalid:
+      nassertr(false, ts);
+      break;
+    }
+  }
+
+  return ts;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLoader::show_normals
 //       Access: Private
@@ -1183,8 +1303,7 @@ make_texture_stage(const EggTexture *egg_tex) {
   }
 
 
-  if (egg_tex->has_uv_name() && !egg_tex->get_uv_name().empty() &&
-      egg_tex->get_uv_name() != string("default")) {
+  if (egg_tex->has_uv_name()) {
     CPT(InternalName) name = 
       InternalName::get_texcoord_name(egg_tex->get_uv_name());
     stage->set_texcoord_name(name);
@@ -1725,23 +1844,26 @@ make_vertex_data(const EggRenderState *render_state,
        Geom::NT_packed_dabc, Geom::C_color);
   }
 
-  vector_string uv_names, tbn_names;
-  vertex_pool->get_uv_names(uv_names, tbn_names);
+  vector_string uv_names, uvw_names, tbn_names;
+  vertex_pool->get_uv_names(uv_names, uvw_names, tbn_names);
   vector_string::const_iterator ni;
   for (ni = uv_names.begin(); ni != uv_names.end(); ++ni) {
     string name = (*ni);
-    if (name == "default") {
-      name = string();
-    }
+
     PT(InternalName) iname = InternalName::get_texcoord_name(name);
-    array_format->add_column
-      (iname, 2, Geom::NT_float32, Geom::C_texcoord);
+
+    if (find(uvw_names.begin(), uvw_names.end(), name) != uvw_names.end()) {
+      // This one actually represents 3-d texture coordinates.
+      array_format->add_column
+        (iname, 3, Geom::NT_float32, Geom::C_texcoord);
+    } else {
+      array_format->add_column
+        (iname, 2, Geom::NT_float32, Geom::C_texcoord);
+    }
   }
   for (ni = tbn_names.begin(); ni != tbn_names.end(); ++ni) {
     string name = (*ni);
-    if (name == "default") {
-      name = string();
-    }
+
     PT(InternalName) iname = InternalName::get_tangent_name(name);
     array_format->add_column
       (iname, 3, Geom::NT_float32, Geom::C_vector);
@@ -1807,16 +1929,14 @@ make_vertex_data(const EggRenderState *render_state,
       for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
         EggVertexUV *egg_uv = (*uvi);
         string name = egg_uv->get_name();
-        if (name == "default") {
-          name = string();
-        }
+        bool has_w = (find(uvw_names.begin(), uvw_names.end(), name) != uvw_names.end());
         PT(InternalName) iname = InternalName::get_texcoord_name(name);
 
         EggMorphTexCoordList::const_iterator mti;
         for (mti = egg_uv->_duvs.begin(); mti != egg_uv->_duvs.end(); ++mti) {
           slider_names.insert((*mti).get_name());
           record_morph(anim_array_format, character_maker, (*mti).get_name(),
-                       iname, 2);
+                       iname, has_w ? 3 : 2);
         }
       }
     }
@@ -1910,23 +2030,20 @@ make_vertex_data(const EggRenderState *render_state,
     EggVertex::const_uv_iterator uvi;
     for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
       EggVertexUV *egg_uv = (*uvi);
-      TexCoordd orig_uv = egg_uv->get_uv();
-      TexCoordd uv = egg_uv->get_uv();
+      TexCoord3d orig_uvw = egg_uv->get_uvw();
+      TexCoord3d uvw = egg_uv->get_uvw();
 
       string name = egg_uv->get_name();
-      if (name == "default") {
-        name = string();
-      }
       PT(InternalName) iname = InternalName::get_texcoord_name(name);
       gvw.set_column(iname);
 
       BakeInUVs::const_iterator buv = render_state->_bake_in_uvs.find(iname);
       if (buv != render_state->_bake_in_uvs.end()) {
         // If we are to bake in a texture matrix, do so now.
-        uv = uv * (*buv).second->get_transform();
+        uvw = uvw * (*buv).second->get_transform();
       }
 
-      gvw.set_data2f(LCAST(float, uv));
+      gvw.set_data3f(LCAST(float, uvw));
 
       if (is_dynamic) {
         EggMorphTexCoordList::const_iterator mti;
@@ -1935,13 +2052,13 @@ make_vertex_data(const EggRenderState *render_state,
           CPT(InternalName) delta_name = 
             InternalName::get_morph(iname, morph.get_name());
           gvw.set_column(delta_name);
-          TexCoordd duv = morph.get_offset();
+          TexCoord3d duvw = morph.get_offset();
           if (buv != render_state->_bake_in_uvs.end()) {
-            TexCoordd new_uv = orig_uv + duv;
-            duv = (new_uv * (*buv).second->get_transform()) - uv;
+            TexCoord3d new_uvw = orig_uvw + duvw;
+            duvw = (new_uvw * (*buv).second->get_transform()) - uvw;
           }
           
-          gvw.add_data2f(LCAST(float, duv));
+          gvw.add_data3f(LCAST(float, duvw));
         }
       }
 
@@ -2994,91 +3111,6 @@ do_expand_object_type(EggGroup *egg_group, const pset<string> &expanded,
   return true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggLoader::make_transform
-//       Access: Private
-//  Description: Walks back over the tree and applies the
-//               DeferredNodeProperties that were saved up along the
-//               way.
-////////////////////////////////////////////////////////////////////
-CPT(TransformState) EggLoader::
-make_transform(const EggTransform3d *egg_transform) {
-  // We'll build up the transform componentwise, so we preserve any
-  // componentwise properties of the egg transform.
-
-  CPT(TransformState) ts = TransformState::make_identity();
-  int num_components = egg_transform->get_num_components();
-  for (int i = 0; i < num_components; i++) {
-    switch (egg_transform->get_component_type(i)) {
-    case EggTransform3d::CT_translate:
-      {
-        LVector3f trans(LCAST(float, egg_transform->get_component_vector(i)));
-        ts = TransformState::make_pos(trans)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_rotx:
-      {
-        LRotationf rot(LVector3f(1.0f, 0.0f, 0.0f),
-                       (float)egg_transform->get_component_number(i));
-        ts = TransformState::make_quat(rot)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_roty:
-      {
-        LRotationf rot(LVector3f(0.0f, 1.0f, 0.0f),
-                       (float)egg_transform->get_component_number(i));
-        ts = TransformState::make_quat(rot)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_rotz:
-      {
-        LRotationf rot(LVector3f(0.0f, 0.0f, 1.0f),
-                       (float)egg_transform->get_component_number(i));
-        ts = TransformState::make_quat(rot)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_rotate:
-      {
-        LRotationf rot(LCAST(float, egg_transform->get_component_vector(i)),
-                       (float)egg_transform->get_component_number(i));
-        ts = TransformState::make_quat(rot)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_scale:
-      {
-        LVecBase3f scale(LCAST(float, egg_transform->get_component_vector(i)));
-        ts = TransformState::make_scale(scale)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_uniform_scale:
-      {
-        float scale = (float)egg_transform->get_component_number(i);
-        ts = TransformState::make_scale(scale)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_matrix:
-      {
-        LMatrix4f mat(LCAST(float, egg_transform->get_component_matrix(i)));
-        ts = TransformState::make_mat(mat)->compose(ts);
-      }
-      break;
-
-    case EggTransform3d::CT_invalid:
-      nassertr(false, ts);
-      break;
-    }
-  }
-
-  return ts;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLoader::get_combine_mode
 //       Access: Private, Static

+ 3 - 3
panda/src/egg2pg/eggLoader.h

@@ -38,7 +38,7 @@
 #include "textureStage.h"
 #include "texGenAttrib.h"
 #include "colorBlendAttrib.h"
-#include "eggTransform3d.h"
+#include "eggTransform.h"
 #include "geomVertexData.h"
 #include "geomPrimitive.h"
 
@@ -80,6 +80,8 @@ public:
                     const LMatrix4d *transform, bool is_dynamic,
                     CharacterMaker *character_maker);
 
+  static CPT(TransformState) make_transform(const EggTransform *egg_transform);
+
 private:
   class TextureDef {
   public:
@@ -185,8 +187,6 @@ private:
                              const pvector<string> &expanded_history,
                              const string &object_type);
 
-  CPT(TransformState) make_transform(const EggTransform3d *egg_transform);
-
   static TextureStage::CombineMode 
   get_combine_mode(const EggTexture *egg_tex, 
                    EggTexture::CombineChannel channel);

+ 1 - 18
panda/src/egg2pg/eggRenderState.cxx

@@ -536,24 +536,7 @@ CPT(RenderAttrib) EggRenderState::
 apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib, 
               TextureStage *stage, const EggTexture *egg_tex) {
   if (egg_tex->has_transform()) {
-    const LMatrix3d &tex_mat = egg_tex->get_transform();
-    LMatrix4f mat4(tex_mat(0, 0), tex_mat(0, 1), 0.0f, tex_mat(0, 2),
-                   tex_mat(1, 0), tex_mat(1, 1), 0.0f, tex_mat(1, 2),
-                   0.0f, 0.0f, 1.0f, 0.0f,
-                   tex_mat(2, 0), tex_mat(2, 1), 0.0f, tex_mat(2, 2));
-    CPT(TransformState) transform;
-
-    LVecBase3f scale, shear, hpr, translate;
-    if (decompose_matrix(mat4, scale, shear, hpr, translate)) {
-      // If the texture matrix can be represented componentwise, do
-      // so.
-      transform = TransformState::make_pos_hpr_scale_shear
-        (translate, hpr, scale, shear);
-
-    } else {
-      // Otherwise, make a matrix transform.
-      transform = TransformState::make_mat(mat4);
-    }
+    CPT(TransformState) transform = EggLoader::make_transform(egg_tex);
   
     if (tex_mat_attrib == (const RenderAttrib *)NULL) {
       tex_mat_attrib = TexMatrixAttrib::make();

+ 1 - 1
panda/src/egg2pg/eggRenderState.h

@@ -77,7 +77,7 @@ private:
   EggLoader &_loader;
 
   typedef pvector<const TextureDef *> TexMatTextures;
-  typedef pmap<LMatrix3d, TexMatTextures> TexMatTransforms;
+  typedef pmap<LMatrix4d, TexMatTextures> TexMatTransforms;
   typedef pmap<CPT(InternalName), TexMatTransforms> TexMats;
 };
 

+ 2 - 0
panda/src/linmath/aa_luse.h

@@ -53,12 +53,14 @@
 typedef LPoint3f Vertexf;
 typedef LVector3f Normalf;
 typedef LPoint2f TexCoordf;
+typedef LPoint3f TexCoord3f;
 typedef LVecBase4f Colorf;
 typedef LVecBase3f RGBColorf;
 
 typedef LPoint3d Vertexd;
 typedef LVector3d Normald;
 typedef LPoint2d TexCoordd;
+typedef LPoint3d TexCoord3d;
 typedef LVecBase4d Colord;
 typedef LVecBase3d RGBColord;
 

+ 3 - 3
pandatool/src/bam/bamToEgg.cxx

@@ -429,13 +429,13 @@ apply_node_properties(EggGroup *egg_group, PandaNode *node) {
       const LQuaternionf &quat = transform->get_quat();
       const LVecBase3f &pos = transform->get_pos();
       if (!scale.almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
-        egg_group->add_scale(LCAST(double, scale));
+        egg_group->add_scale3d(LCAST(double, scale));
       }
       if (!quat.is_identity()) {
-        egg_group->add_rotate(LCAST(double, quat));
+        egg_group->add_rotate3d(LCAST(double, quat));
       }
       if (!pos.almost_equal(LVecBase3f::zero())) {
-        egg_group->add_translate(LCAST(double, pos));
+        egg_group->add_translate3d(LCAST(double, pos));
       }
 
     } else if (transform->has_mat()) {

+ 13 - 13
pandatool/src/fltegg/fltToEggLevelState.cxx

@@ -161,7 +161,7 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           const FltTransformTranslate *trans;
           DCAST_INTO_V(trans, step);
           if (!trans->get_delta().almost_equal(LVector3d::zero())) {
-            egg_group->add_translate(trans->get_delta());
+            egg_group->add_translate3d(trans->get_delta());
           }
 
         } else if (step->is_exact_type(FltTransformRotateAboutPoint::get_class_type())) {
@@ -169,12 +169,12 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           DCAST_INTO_V(rap, step); 
           if (!IS_NEARLY_ZERO(rap->get_angle())) {
             if (!rap->get_center().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(-rap->get_center());
+              egg_group->add_translate3d(-rap->get_center());
             }
             LVector3d axis = LCAST(double, rap->get_axis());
-            egg_group->add_rotate(rap->get_angle(), axis);
+            egg_group->add_rotate3d(rap->get_angle(), axis);
             if (!rap->get_center().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(rap->get_center());
+              egg_group->add_translate3d(rap->get_center());
             }
           }
 
@@ -183,12 +183,12 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           DCAST_INTO_V(rae, step);
           if (!IS_NEARLY_ZERO(rae->get_angle())) {
             if (!rae->get_point_a().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(-rae->get_point_a());
+              egg_group->add_translate3d(-rae->get_point_a());
             }
             LVector3d axis = rae->get_point_b() - rae->get_point_a();
-            egg_group->add_rotate(rae->get_angle(), axis);
+            egg_group->add_rotate3d(rae->get_angle(), axis);
             if (!rae->get_point_a().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(rae->get_point_a());
+              egg_group->add_translate3d(rae->get_point_a());
             }
           }
 
@@ -198,12 +198,12 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           if (!scale->get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
             if (scale->has_center() && 
                 !scale->get_center().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(-scale->get_center());
+              egg_group->add_translate3d(-scale->get_center());
             }
-            egg_group->add_scale(LCAST(double, scale->get_scale()));
+            egg_group->add_scale3d(LCAST(double, scale->get_scale()));
             if (scale->has_center() && 
                 !scale->get_center().almost_equal(LVector3d::zero())) {
-              egg_group->add_translate(scale->get_center());
+              egg_group->add_translate3d(scale->get_center());
             }
           }
 
@@ -212,7 +212,7 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           DCAST_INTO_V(put, step);
 
           if (!put->get_from_origin().almost_equal(LVector3d::zero())) {
-            egg_group->add_translate(-put->get_from_origin());
+            egg_group->add_translate3d(-put->get_from_origin());
           }
           LQuaterniond q1, q2;
           look_at(q1, put->get_from_align() - put->get_from_origin(),
@@ -225,10 +225,10 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
           LQuaterniond q = invert(q1) * q2;
 
           if (!q.is_identity()) {
-            egg_group->add_rotate(q);
+            egg_group->add_rotate3d(q);
           }
           if (!put->get_to_origin().almost_equal(LVector3d::zero())) {
-            egg_group->add_translate(put->get_to_origin());
+            egg_group->add_translate3d(put->get_to_origin());
           }
 
         } else {

+ 56 - 13
pandatool/src/fltprogs/eggToFlt.cxx

@@ -317,23 +317,43 @@ convert_group(EggGroup *egg_group, FltBead *flt_node,
 //               flt bead.
 ////////////////////////////////////////////////////////////////////
 void EggToFlt::
-apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
+apply_transform(EggTransform *egg_transform, FltBead *flt_node) {
   flt_node->clear_transform();
 
   bool components_ok = true;
   int num_components = egg_transform->get_num_components();
   for (int i = num_components - 1; i >= 0 && components_ok; i--) {
     switch (egg_transform->get_component_type(i)) {
-    case EggTransform3d::CT_translate:
+    case EggTransform::CT_translate2d:
       {
         FltTransformTranslate *translate = 
           new FltTransformTranslate(_flt_header);
-        translate->set(LPoint3d::zero(), egg_transform->get_component_vector(i));
+        LVector2d v2 = egg_transform->get_component_vec2(i);
+        translate->set(LPoint3d::zero(), LVector3d(v2[0], v2[1], 0.0));
         flt_node->add_transform_step(translate);
       }
       break;
 
-    case EggTransform3d::CT_rotx:
+    case EggTransform::CT_translate3d:
+      {
+        FltTransformTranslate *translate = 
+          new FltTransformTranslate(_flt_header);
+        translate->set(LPoint3d::zero(), egg_transform->get_component_vec3(i));
+        flt_node->add_transform_step(translate);
+      }
+      break;
+
+    case EggTransform::CT_rotate2d:
+      {
+        FltTransformRotateAboutEdge *rotate = 
+          new FltTransformRotateAboutEdge(_flt_header);
+        rotate->set(LPoint3d::zero(), LPoint3d(0.0, 0.0, 1.0),
+                    egg_transform->get_component_number(i));
+        flt_node->add_transform_step(rotate);
+      }
+      break;
+
+    case EggTransform::CT_rotx:
       {
         FltTransformRotateAboutEdge *rotate = 
           new FltTransformRotateAboutEdge(_flt_header);
@@ -343,7 +363,7 @@ apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
       }
       break;
 
-    case EggTransform3d::CT_roty:
+    case EggTransform::CT_roty:
       {
         FltTransformRotateAboutEdge *rotate = 
           new FltTransformRotateAboutEdge(_flt_header);
@@ -353,7 +373,7 @@ apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
       }
       break;
 
-    case EggTransform3d::CT_rotz:
+    case EggTransform::CT_rotz:
       {
         FltTransformRotateAboutEdge *rotate = 
           new FltTransformRotateAboutEdge(_flt_header);
@@ -363,25 +383,34 @@ apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
       }
       break;
 
-    case EggTransform3d::CT_rotate:
+    case EggTransform::CT_rotate3d:
       {
         FltTransformRotateAboutEdge *rotate = 
           new FltTransformRotateAboutEdge(_flt_header);
-        rotate->set(LPoint3d::zero(), egg_transform->get_component_vector(i),
+        rotate->set(LPoint3d::zero(), egg_transform->get_component_vec3(i),
                     egg_transform->get_component_number(i));
         flt_node->add_transform_step(rotate);
       }
       break;
 
-    case EggTransform3d::CT_scale:
+    case EggTransform::CT_scale2d:
+      {
+        FltTransformScale *scale = new FltTransformScale(_flt_header);
+        LVector2d v2 = egg_transform->get_component_vec2(i);
+        scale->set(LPoint3d::zero(), LVector3f(v2[0], v2[1], 1.0f));
+        flt_node->add_transform_step(scale);
+      }
+      break;
+
+    case EggTransform::CT_scale3d:
       {
         FltTransformScale *scale = new FltTransformScale(_flt_header);
-        scale->set(LPoint3d::zero(), LCAST(float, egg_transform->get_component_vector(i)));
+        scale->set(LPoint3d::zero(), LCAST(float, egg_transform->get_component_vec3(i)));
         flt_node->add_transform_step(scale);
       }
       break;
 
-    case EggTransform3d::CT_uniform_scale:
+    case EggTransform::CT_uniform_scale:
       {
         FltTransformScale *scale = new FltTransformScale(_flt_header);
         float factor = (float)egg_transform->get_component_number(i);
@@ -390,11 +419,25 @@ apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
       }
       break;
 
-    case EggTransform3d::CT_matrix:
+    case EggTransform::CT_matrix3:
+      {
+        FltTransformGeneralMatrix *matrix = 
+          new FltTransformGeneralMatrix(_flt_header);
+        const LMatrix3d &m = egg_transform->get_component_mat3(i);
+        LMatrix4d mat4(m(0, 0), m(0, 1), 0.0, m(0, 2),
+                       m(1, 0), m(1, 1), 0.0, m(1, 2),
+                       0.0, 0.0, 1.0, 0.0,
+                       m(2, 0), m(2, 1), 0.0, m(2, 2));
+        matrix->set_matrix(mat4);
+        flt_node->add_transform_step(matrix);
+      }
+      break;
+
+    case EggTransform::CT_matrix4:
       {
         FltTransformGeneralMatrix *matrix = 
           new FltTransformGeneralMatrix(_flt_header);
-        matrix->set_matrix(egg_transform->get_component_matrix(i));
+        matrix->set_matrix(egg_transform->get_component_mat4(i));
         flt_node->add_transform_step(matrix);
       }
       break;

+ 2 - 2
pandatool/src/fltprogs/eggToFlt.h

@@ -32,7 +32,7 @@ class EggGroup;
 class EggVertex;
 class EggPrimitive;
 class EggTexture;
-class EggTransform3d;
+class EggTransform;
 class FltVertex;
 class FltBead;
 class FltTexture;
@@ -56,7 +56,7 @@ private:
                          FltGeometry::BillboardType billboard);
   void convert_group(EggGroup *egg_group, FltBead *flt_node,
                      FltGeometry::BillboardType billboard);
-  void apply_transform(EggTransform3d *egg_transform, FltBead *flt_node);
+  void apply_transform(EggTransform *egg_transform, FltBead *flt_node);
   void apply_egg_syntax(const string &egg_syntax, FltRecord *flt_record);
   FltVertex *get_flt_vertex(EggVertex *egg_vertex, EggNode *context);
   FltTexture *get_flt_texture(EggTexture *egg_texture);

+ 2 - 2
pandatool/src/palettizer/textureReference.cxx

@@ -86,8 +86,8 @@ from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex) {
   _egg_data = data;
   _tref_name = egg_tex->get_name();
 
-  if (_egg_tex->has_transform()) {
-    _tex_mat = _egg_tex->get_transform();
+  if (_egg_tex->has_transform() && egg_tex->is_transform_2d()) {
+    _tex_mat = _egg_tex->get_transform_2d();
     if (!_inv_tex_mat.invert_from(_tex_mat)) {
       _inv_tex_mat = LMatrix3d::ident_mat();
     }

+ 2 - 2
pandatool/src/xfileegg/xFileVertex.cxx

@@ -60,8 +60,8 @@ set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
     if (egg_prim->has_texture()) {
       // Check if there's a texture matrix on the texture.
       EggTexture *egg_tex = egg_prim->get_texture();
-      if (egg_tex->has_transform()) {
-        uv = uv * egg_tex->get_transform();
+      if (egg_tex->has_transform() && egg_tex->is_transform_2d()) {
+        uv = uv * egg_tex->get_transform_2d();
       }
     }
 

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác