Bläddra i källkod

explicit mipmap control

David Rose 20 år sedan
förälder
incheckning
f803ef85ce

+ 8 - 7
direct/src/showbase/Loader.py

@@ -192,7 +192,8 @@ class Loader:
         return font
         return font
 
 
     # texture loading funcs
     # texture loading funcs
-    def loadTexture(self, texturePath, alphaPath = None):
+    def loadTexture(self, texturePath, alphaPath = None,
+                    readMipmaps = False):
         """
         """
         texturePath is a string.
         texturePath is a string.
 
 
@@ -203,15 +204,15 @@ class Loader:
             assert Loader.notify.debug("Loading texture: %s" % (texturePath))
             assert Loader.notify.debug("Loading texture: %s" % (texturePath))
             if phaseChecker:
             if phaseChecker:
                 phaseChecker(texturePath)
                 phaseChecker(texturePath)
-            texture = TexturePool.loadTexture(texturePath)
+            texture = TexturePool.loadTexture(texturePath, 0, readMipmaps)
         else:
         else:
             assert Loader.notify.debug("Loading texture: %s %s" % (texturePath, alphaPath))
             assert Loader.notify.debug("Loading texture: %s %s" % (texturePath, alphaPath))
             if phaseChecker:
             if phaseChecker:
                 phaseChecker(texturePath)
                 phaseChecker(texturePath)
-            texture = TexturePool.loadTexture(texturePath, alphaPath)
+            texture = TexturePool.loadTexture(texturePath, alphaPath, 0, 0, readMipmaps)
         return texture
         return texture
 
 
-    def load3DTexture(self, texturePattern):
+    def load3DTexture(self, texturePattern, readMipmaps = False):
         """
         """
         texturePattern is a string that contains a sequence of one or
         texturePattern is a string that contains a sequence of one or
         more '#' characters, which will be filled in with the sequence
         more '#' characters, which will be filled in with the sequence
@@ -223,10 +224,10 @@ class Loader:
         assert Loader.notify.debug("Loading 3-D texture: %s" % (texturePattern))
         assert Loader.notify.debug("Loading 3-D texture: %s" % (texturePattern))
         if phaseChecker:
         if phaseChecker:
             phaseChecker(texturePattern)
             phaseChecker(texturePattern)
-        texture = TexturePool.load3dTexture(texturePattern)
+        texture = TexturePool.load3dTexture(texturePattern, readMipmaps)
         return texture
         return texture
 
 
-    def loadCubeMap(self, texturePattern):
+    def loadCubeMap(self, texturePattern, readMipmaps = False):
         """
         """
         texturePattern is a string that contains a sequence of one or
         texturePattern is a string that contains a sequence of one or
         more '#' characters, which will be filled in with the sequence
         more '#' characters, which will be filled in with the sequence
@@ -239,7 +240,7 @@ class Loader:
         assert Loader.notify.debug("Loading cube map: %s" % (texturePattern))
         assert Loader.notify.debug("Loading cube map: %s" % (texturePattern))
         if phaseChecker:
         if phaseChecker:
             phaseChecker(texturePattern)
             phaseChecker(texturePattern)
-        texture = TexturePool.loadCubeMap(texturePattern)
+        texture = TexturePool.loadCubeMap(texturePattern, readMipmaps)
         return texture
         return texture
 
 
     def unloadTexture(self, texture):
     def unloadTexture(self, texture):

+ 32 - 0
panda/src/doc/eggSyntax.txt

@@ -139,6 +139,16 @@ appear before they are referenced.
     alpha channels along with image file formats like JPEG that don't
     alpha channels along with image file formats like JPEG that don't
     traditionally support alpha channels.
     traditionally support alpha channels.
 
 
+  <Scalar> alpha-file-channel { channel }
+
+    This defines the channel that should be extracted from the file
+    named by alpha-file to determine the alpha channel for the
+    resulting channel.  The default is 0, which means the grayscale
+    combination of r, g, b.  Otherwise, this should be the 1-based
+    channel number, for instance 1, 2, or 3 for r, g, or b,
+    respectively, or 4 for the alpha channel of a four-component
+    image.
+
   <Scalar> format { format-definition }
   <Scalar> format { format-definition }
 
 
     This defines the load format of the image file.  The
     This defines the load format of the image file.  The
@@ -223,6 +233,22 @@ appear before they are referenced.
     present, must be included in the same image with the color
     present, must be included in the same image with the color
     channel(s).
     channel(s).
 
 
+  <Scalar> read-mipmaps { flag }
+
+    If this flag is nonzero, then pre-generated mipmap levels will be
+    loaded along with the texture.  In this case, the filename should
+    contain a sequence of one or more hash mark ("#") characters,
+    which will be filled in with the mipmap level number; the texture
+    filename thus determines a series of images, one for each mipmap
+    level.  The base texture image is mipmap level 0.
+
+    If this flag is specified in conjunction with a 3D or cube map
+    texture (as specified above), then the filename should contain two
+    hash mark sequences, separated by a character such as an
+    underscore, hyphen, or dot.  The first sequence will be filled in
+    with the mipmap level index, and the second sequence will be
+    filled in with the 3D sequence or cube map face.
+
   <Scalar> minfilter { filter-type }
   <Scalar> minfilter { filter-type }
   <Scalar> magfilter { filter-type }
   <Scalar> magfilter { filter-type }
   <Scalar> magfilteralpha { filter-type }
   <Scalar> magfilteralpha { filter-type }
@@ -327,6 +353,12 @@ appear before they are referenced.
       <Scalar> combine-alpha-source2 { constant }
       <Scalar> combine-alpha-source2 { constant }
       <Scalar> combine-alpha-operand2 { src-alpha }
       <Scalar> combine-alpha-operand2 { src-alpha }
 
 
+  <Scalar> saved-result { flag }
+ 
+    If flag is nonzero, then it indicates that this particular texture
+    stage will be supplied as the "last_saved_result" source for any
+    future texture stages.
+
   <Scalar> tex-gen { mode }
   <Scalar> tex-gen { mode }
 
 
     This specifies that texture coordinates for the primitives that
     This specifies that texture coordinates for the primitives that

+ 33 - 0
panda/src/egg/eggTexture.I

@@ -929,6 +929,39 @@ get_alpha_file_channel() const {
   return _alpha_file_channel;
   return _alpha_file_channel;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::set_read_mipmaps
+//       Access: Published
+//  Description: Sets the read_mipmaps flag.
+//
+//               If read_mipmaps is true, the filename should contain
+//               a hash mark ('#'), which will be filled in with the
+//               mipmap level number; and the texture will be defined
+//               with a series of images, one for each mipmap level.
+//
+//               If the filename is of a time that already requires a
+//               hash mark, such as a cube map or a 3-d texture, then
+//               the filename should now require two hash marks, and
+//               the first one indicates the mipmap level number,
+//               while the second indicates the face number or 3-d
+//               level number.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTexture::
+set_read_mipmaps(bool read_mipmaps) {
+  _read_mipmaps = read_mipmaps;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTexture::get_read_mipmaps
+//       Access: Published
+//  Description: Returns the current setting of the read_mipmaps flag.
+//               See set_read_mipmaps().
+////////////////////////////////////////////////////////////////////
+INLINE bool EggTexture::
+get_read_mipmaps() const {
+  return _read_mipmaps;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTexture::get_multitexture_sort
 //     Function: EggTexture::get_multitexture_sort
 //       Access: Published
 //       Access: Published

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

@@ -53,6 +53,7 @@ EggTexture(const string &tref_name, const string &filename)
   _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _flags = 0;
   _flags = 0;
   _alpha_file_channel = 0;
   _alpha_file_channel = 0;
+  _read_mipmaps = false;
   _multitexture_sort = 0;
   _multitexture_sort = 0;
 }
 }
 
 
@@ -103,6 +104,7 @@ operator = (const EggTexture &copy) {
   _alpha_filename = copy._alpha_filename;
   _alpha_filename = copy._alpha_filename;
   _alpha_fullpath = copy._alpha_fullpath;
   _alpha_fullpath = copy._alpha_fullpath;
   _alpha_file_channel = copy._alpha_file_channel;
   _alpha_file_channel = copy._alpha_file_channel;
+  _read_mipmaps = copy._read_mipmaps;
   _multitexture_sort = 0;
   _multitexture_sort = 0;
   _combiner[0] = copy._combiner[0];
   _combiner[0] = copy._combiner[0];
   _combiner[1] = copy._combiner[1];
   _combiner[1] = copy._combiner[1];
@@ -144,6 +146,11 @@ write(ostream &out, int indent_level) const {
       << get_alpha_file_channel() << " }\n";
       << get_alpha_file_channel() << " }\n";
   }
   }
 
 
+  if (get_read_mipmaps()) {
+    indent(out, indent_level + 2)
+      << "<Scalar> read-mipmaps { 1 }\n";
+  }
+
   if (get_texture_type() != TT_unspecified) {
   if (get_texture_type() != TT_unspecified) {
     indent(out, indent_level + 2)
     indent(out, indent_level + 2)
       << "<Scalar> texture_type { " << get_texture_type() << " }\n";
       << "<Scalar> texture_type { " << get_texture_type() << " }\n";

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

@@ -254,6 +254,10 @@ PUBLISHED:
   INLINE bool has_alpha_file_channel() const;
   INLINE bool has_alpha_file_channel() const;
   INLINE int get_alpha_file_channel() const;
   INLINE int get_alpha_file_channel() const;
 
 
+  INLINE void set_read_mipmaps(bool read_mipmaps);
+  INLINE bool get_read_mipmaps() const;
+
+
   void clear_multitexture();
   void clear_multitexture();
   bool multitexture_over(EggTexture *other);
   bool multitexture_over(EggTexture *other);
   INLINE int get_multitexture_sort() const;
   INLINE int get_multitexture_sort() const;
@@ -312,6 +316,7 @@ private:
   Filename _alpha_filename;
   Filename _alpha_filename;
   Filename _alpha_fullpath;
   Filename _alpha_fullpath;
   int _alpha_file_channel;
   int _alpha_file_channel;
+  bool _read_mipmaps;
   int _multitexture_sort;
   int _multitexture_sort;
 
 
   class SourceAndOperand {
   class SourceAndOperand {

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

@@ -1,2944 +1,2965 @@
-#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 "pnotify.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 EGG_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 EGG_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 EGG_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 EGG_NUMBER;
-}
-	YY_BREAK
-case 94:
-YY_RULE_SETUP
-#line 710 "lexer.lxx"
-{ 
-  // infinity.  As above.
-  accept(); 
-  eggyylval._number = HUGE_VAL;
-  eggyylval._string = yytext;
-  return EGG_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 EGG_NUMBER; 
-}
-	YY_BREAK
-case 96:
-YY_RULE_SETUP
-#line 727 "lexer.lxx"
-{
-  // Quoted string.
-  accept();
-  eggyylval._string = scan_quoted_string();
-  return EGG_STRING;
-}
-	YY_BREAK
-case 97:
-YY_RULE_SETUP
-#line 734 "lexer.lxx"
-{ 
-  // Unquoted string.
-  accept();
-  eggyylval._string = yytext;
-  return EGG_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"
+#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 "pnotify.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 EGG_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 EGG_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 EGG_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 EGG_NUMBER;
+}
+	YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 710 "lexer.lxx"
+{ 
+  // infinity.  As above.
+  accept(); 
+  eggyylval._number = HUGE_VAL;
+  eggyylval._string = yytext;
+  return EGG_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 EGG_NUMBER; 
+}
+	YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 727 "lexer.lxx"
+{
+  // Quoted string.
+  accept();
+  eggyylval._string = scan_quoted_string();
+  return EGG_STRING;
+}
+	YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 734 "lexer.lxx"
+{ 
+  // Unquoted string.
+  accept();
+  eggyylval._string = yytext;
+  return EGG_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"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 135 - 132
panda/src/egg/parser.cxx.prebuilt


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

@@ -654,6 +654,9 @@ texture_body:
   } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) {
   } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) {
     texture->set_alpha_file_channel((int)value);
     texture->set_alpha_file_channel((int)value);
 
 
+  } else if (cmp_nocase_uh(name, "read_mipmaps") == 0) {
+    texture->set_read_mipmaps(((int)value) != 0);
+
   } else {
   } else {
     eggyywarning("Unsupported texture scalar: " + name);
     eggyywarning("Unsupported texture scalar: " + name);
   }
   }

+ 8 - 4
panda/src/egg2pg/eggLoader.cxx

@@ -886,19 +886,23 @@ load_texture(TextureDef &def, const EggTexture *egg_tex) {
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
                                       egg_tex->get_alpha_fullpath(),
                                       egg_tex->get_alpha_fullpath(),
                                       wanted_channels,
                                       wanted_channels,
-                                      egg_tex->get_alpha_file_channel());
+                                      egg_tex->get_alpha_file_channel(),
+				      egg_tex->get_read_mipmaps());
     } else {
     } else {
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
       tex = TexturePool::load_texture(egg_tex->get_fullpath(),
-                                      wanted_channels);
+                                      wanted_channels,
+				      egg_tex->get_read_mipmaps());
     }
     }
     break;
     break;
 
 
   case EggTexture::TT_3d_texture:
   case EggTexture::TT_3d_texture:
-    tex = TexturePool::load_3d_texture(egg_tex->get_fullpath());
+    tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(),
+				       egg_tex->get_read_mipmaps());
     break;
     break;
 
 
   case EggTexture::TT_cube_map:
   case EggTexture::TT_cube_map:
-    tex = TexturePool::load_cube_map(egg_tex->get_fullpath());
+    tex = TexturePool::load_cube_map(egg_tex->get_fullpath(),
+				     egg_tex->get_read_mipmaps());
     break;
     break;
   }
   }
 
 

+ 312 - 386
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -470,27 +470,47 @@ reset() {
   if (is_at_least_version(1, 3)) {
   if (is_at_least_version(1, 3)) {
     _supports_compressed_texture = true;
     _supports_compressed_texture = true;
 
 
+    _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1D");
     _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
     _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2D");
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2D");
+    _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3D");
+    _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1D");
     _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
     _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2D");
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2D");
+    _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3D");
     _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
     _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
       get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImage");
       get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImage");
 
 
   } else if (has_extension("GL_ARB_texture_compression")) {
   } else if (has_extension("GL_ARB_texture_compression")) {
     _supports_compressed_texture = true;
     _supports_compressed_texture = true;
 
 
+    _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1DARB");
     _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
     _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2DARB");
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2DARB");
+    _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3DARB");
+    _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1DARB");
     _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
     _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2DARB");
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2DARB");
+    _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3DARB");
     _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
     _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
       get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImageARB");
       get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImageARB");
   }
   }
 
 
   if (_supports_compressed_texture) {
   if (_supports_compressed_texture) {
-    if (_glCompressedTexImage2D == NULL || 
+    if (_glCompressedTexImage1D == NULL || 
+        _glCompressedTexImage2D == NULL || 
+        _glCompressedTexImage3D == NULL || 
+	_glCompressedTexSubImage1D == NULL || 
 	_glCompressedTexSubImage2D == NULL || 
 	_glCompressedTexSubImage2D == NULL || 
+	_glCompressedTexSubImage3D == NULL || 
 	_glGetCompressedTexImage == NULL) {
 	_glGetCompressedTexImage == NULL) {
       GLCAT.warning()
       GLCAT.warning()
         << "Compressed textures advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
         << "Compressed textures advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
@@ -2394,77 +2414,28 @@ extract_texture_data(Texture *tex) {
   PTA_uchar image;
   PTA_uchar image;
   size_t page_size = 0;
   size_t page_size = 0;
 
 
-  if (target == GL_TEXTURE_CUBE_MAP) {
-    // A cube map, compressed or uncompressed.  This we must extract
-    // one page at a time.
-
-    // If the cube map is compressed, we assume that all the
-    // compressed pages are exactly the same size.  OpenGL doesn't
-    // make this assumption, but it happens to be true for all
-    // currently extant compression schemes, and it makes things
-    // simpler for us.  (It also makes things much simpler for the
-    // graphics hardware, so it's likely to continue to be true for a
-    // while at least.)
-
-    GLenum external_format = get_external_image_format(tex);
-    GLenum pixel_type = get_component_type(type);
-    page_size = tex->get_expected_ram_page_size();
-
-    if (compression != Texture::CM_off) {
-      GLint image_size;
-      GLP(GetTexLevelParameteriv)(page_target, 0, 
-				  GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
-      nassertr(image_size <= (int)page_size, false);
-      page_size = image_size;
-    }
-
-    image = PTA_uchar::empty_array(page_size * 6);
-
-    for (int z = 0; z < 6; ++z) {
-      page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
-      
-      if (compression == Texture::CM_off) {
-	GLP(GetTexImage)(page_target, 0, external_format, pixel_type, 
-			 image.p() + z * page_size);
-      } else {
-	_glGetCompressedTexImage(page_target, 0, image.p() + z * page_size);
-      }
-    }
-
-  } else if (compression == Texture::CM_off) {
-    // An uncompressed 1-d, 2-d, or 3-d texture.
-    image = PTA_uchar::empty_array(tex->get_expected_ram_image_size());
-    GLenum external_format = get_external_image_format(tex);
-    GLenum pixel_type = get_component_type(type);
-    GLP(GetTexImage)(target, 0, external_format, pixel_type, image.p());
-
-  } else {
-    // A compressed 1-d, 2-d, or 3-d texture.
-    GLint image_size;
-    GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
-    page_size = image_size / tex->get_z_size();
-    image = PTA_uchar::empty_array(image_size);
-    _glGetCompressedTexImage(target, 0, image.p());
-  }
-
-  // Now see if we were successful.
-  error_code = GLP(GetError)();
-  if (error_code != GL_NO_ERROR) {
-    const GLubyte *error_string = GLUP(ErrorString)(error_code);
-    GLCAT.error()
-      << "Unable to extract texture for " << tex->get_name();
-    if (error_string != (const GLubyte *)NULL) {
-      GLCAT.error(false)
-        << " : " << error_string;
-    }
-    GLCAT.error(false)
-      << "\n";
-
+  if (!extract_texture_image(image, page_size, tex, target, page_target,
+			     type, compression, 0)) {
     return false;
     return false;
   }
   }
   
   
   tex->set_ram_image(image, compression, page_size);
   tex->set_ram_image(image, compression, page_size);
 
 
+  if (tex->uses_mipmaps()) {
+    // Also get the mipmap levels.
+    GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
+    GLint highest_level = num_expected_levels;
+    GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
+    highest_level = min(highest_level, num_expected_levels);
+    for (int n = 1; n <= highest_level; ++n) {
+      if (!extract_texture_image(image, page_size, tex, target, page_target,
+				 type, compression, n)) {
+	return false;
+      }
+      tex->set_ram_mipmap_image(n, image, page_size);
+    }
+  }
+
   return true;
   return true;
 }
 }
 
 
@@ -5619,8 +5590,7 @@ do_issue_texture() {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-update_standard_texture_bindings()
-{
+update_standard_texture_bindings() {
   int num_stages = _target._texture->get_num_on_stages();
   int num_stages = _target._texture->get_num_on_stages();
   int num_old_stages = _max_texture_stages;
   int num_old_stages = _max_texture_stages;
   if (_state._texture != (TextureAttrib *)NULL) {
   if (_state._texture != (TextureAttrib *)NULL) {
@@ -6147,7 +6117,6 @@ specify_texture(Texture *tex) {
   Texture::FilterType minfilter = tex->get_minfilter();
   Texture::FilterType minfilter = tex->get_minfilter();
   Texture::FilterType magfilter = tex->get_magfilter();
   Texture::FilterType magfilter = tex->get_magfilter();
   bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
   bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
-  Texture::CompressionMode image_compression = tex->get_ram_image_compression();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (CLP(force_mipmaps)) {
   if (CLP(force_mipmaps)) {
@@ -6157,20 +6126,17 @@ specify_texture(Texture *tex) {
   }
   }
 #endif
 #endif
 
 
-  if (_supports_generate_mipmap &&
-      (auto_generate_mipmaps || !tex->might_have_ram_image() ||
-       image_compression != Texture::CM_off)) {
-    // If the hardware can automatically generate mipmaps, ask it to
-    // do so now, but only if the texture requires them.
-    GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
+  if (!tex->might_have_ram_image()) {
+    // If it's a dynamically generated texture (that is, the RAM image
+    // isn't available so it didn't pass through the CPU), we should
+    // enable GL-generated mipmaps here if we can.
+    if (_supports_generate_mipmap) {
+      GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
 
 
-  } else if (!tex->might_have_ram_image()) {
-    // If the hardware can't automatically generate mipmaps, but it's
-    // a dynamically generated texture (that is, the RAM image isn't
-    // available so it didn't pass through the CPU), then we'd better
-    // not try to enable mipmap filtering, since we can't generate
-    // mipmaps.
-    uses_mipmaps = false;
+    } else {
+      // Otherwise, don't try to use mipmaps.
+      uses_mipmaps = false;
+    }
   }
   }
 
 
   GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
   GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
@@ -6417,53 +6383,42 @@ upload_texture(CLP(TextureContext) *gtc) {
       return false;
       return false;
     }
     }
 
 
-    size_t page_size = tex->get_ram_page_size();
-    const unsigned char *image_base = image;
-
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
+       true, 0, image_compression);
 
 
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
+       true, 1, image_compression);
 
 
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
+       true, 2, image_compression);
 
 
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
+       true, 3, image_compression);
 
 
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
+       true, 4, image_compression);
 
 
     success = success && upload_texture_image
     success = success && upload_texture_image
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
       (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image_base, page_size, image_compression);
-    image_base += page_size;
-
-    nassertr((size_t)(image_base - image) == image.size(), false);
+       true, 5, image_compression);
 
 
   } else {
   } else {
     // Any other kind of texture can be loaded all at once.
     // Any other kind of texture can be loaded all at once.
     success = upload_texture_image
     success = upload_texture_image
       (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
       (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
        internal_format, width, height, depth, external_format, component_type,
        internal_format, width, height, depth, external_format, component_type,
-       image, image.size(), image_compression);
+       false, 0, image_compression);
   }
   }
 
 
   if (success) {
   if (success) {
@@ -6477,12 +6432,6 @@ upload_texture(CLP(TextureContext) *gtc) {
     gtc->update_data_size_bytes(get_texture_memory_size(tex));
     gtc->update_data_size_bytes(get_texture_memory_size(tex));
 #endif
 #endif
 
 
-#ifndef NDEBUG
-    if (uses_mipmaps && CLP(save_mipmaps)) {
-      save_mipmap_images(tex);
-    }
-#endif
-
     report_my_gl_errors();
     report_my_gl_errors();
     return true;
     return true;
   }
   }
@@ -6503,8 +6452,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
                      GLenum target, GLint internal_format,
                      GLenum target, GLint internal_format,
                      int width, int height, int depth,
                      int width, int height, int depth,
                      GLint external_format, GLenum component_type,
                      GLint external_format, GLenum component_type,
-                     const unsigned char *image,
-		     size_t image_size,
+                     bool one_page_only, int z,
 		     Texture::CompressionMode image_compression) {
 		     Texture::CompressionMode image_compression) {
   // Make sure the error stack is cleared out before we begin.
   // Make sure the error stack is cleared out before we begin.
   report_my_gl_errors();
   report_my_gl_errors();
@@ -6518,152 +6466,215 @@ upload_texture_image(CLP(TextureContext) *gtc,
   }
   }
 
 
   PStatTimer timer(_load_texture_pcollector);
   PStatTimer timer(_load_texture_pcollector);
+  Texture *tex = gtc->get_texture();
+
+  if (GLCAT.is_debug()) {
+    if (image_compression != Texture::CM_off) {
+      GLCAT.debug()
+	<< "loading pre-compressed texture " << tex->get_name() << "\n";
+    } else if (is_compressed_format(internal_format)) {
+      GLCAT.debug()
+	<< "compressing texture " << tex->get_name() << "\n";
+    }
+  }
+
+  int num_ram_mipmap_levels = 1;
+  bool load_ram_mipmaps = false;
 
 
   if (uses_mipmaps) {
   if (uses_mipmaps) {
-#ifdef DO_PSTATS
-    _data_transferred_pcollector.add_level(image_size * 4 / 3);
-#endif
-#ifndef NDEBUG
-    if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
-      build_phony_mipmaps(gtc->get_texture());
-      report_my_gl_errors();
-      return true;
+    num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
 
 
-    } else
-#endif
+    if (num_ram_mipmap_levels == 1) {
+      // No RAM mipmap levels available.  Should we generate some?
       if (!_supports_generate_mipmap || 
       if (!_supports_generate_mipmap || 
           (!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
           (!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
-        // We only need to build the mipmaps by hand if (a) the GL
-        // doesn't support generating them automatically, or (b) the
-        // user has specifically requested we don't use GL's
-        // auto-mipmap feature (but if the source texture image is
-        // compressed, we can't build mipmaps, so we ignore
-        // auto_generate_mipmaps in that case).
-        bool success = true;
-        switch (target) {
-        case GL_TEXTURE_1D:
-          GLUP(Build1DMipmaps)(target, internal_format, width,
-                               external_format, component_type, image);
-          break;
-
-        case GL_TEXTURE_3D:
-#ifdef GLU_VERSION_1_3
-          GLUP(Build3DMipmaps)(target, internal_format,
-                               width, height, depth,
-                               external_format, component_type, image);
-#else  // GLU_VERSION_1_3
-          // Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
-          // Just fall through and load the texture without mipmaps.
-          GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-          success = false;
-#endif  // GLU_VERSION_1_3
-          break;
-
-        default:
-          GLUP(Build2DMipmaps)(target, internal_format,
-                               width, height,
-                               external_format, component_type, image);
-        }
+        // Yes, the GL won't generate them, so we need to.
+        tex->generate_ram_mipmap_images();
+        num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
+      }
+    }
 
 
-        report_my_gl_errors();
-        if (success) {
-          return true;
-        }
+    if (num_ram_mipmap_levels != 1) {
+      // We will load the mipmap levels from RAM.  Don't ask the GL to
+      // generate them.
+      if (_supports_generate_mipmap) {
+        GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
       }
       }
-  }
+      load_ram_mipmaps = true;
 
 
-  if (GLCAT.is_debug()) {
-    if (image_compression != Texture::CM_off) {
-      GLCAT.debug()
-	<< "loading pre-compressed texture " << gtc->get_texture()->get_name() << "\n";
-    } else if (is_compressed_format(internal_format)) {
-      GLCAT.debug()
-	<< "compressing texture " << gtc->get_texture()->get_name() << "\n";
+    } else {
+      // We don't have mipmap levels in RAM.  Ask the GL to generate
+      // them if it can.
+      if (_supports_generate_mipmap) {
+        GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
+      } else {
+        // If it can't, do without mipmaps.
+        GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        uses_mipmaps = false;
+      }
     }
     }
   }
   }
 
 
+  int highest_level = 0;
+
   if (!gtc->_already_applied ||
   if (!gtc->_already_applied ||
       gtc->_internal_format != internal_format ||
       gtc->_internal_format != internal_format ||
       gtc->_width != width ||
       gtc->_width != width ||
       gtc->_height != height ||
       gtc->_height != height ||
       gtc->_depth != depth) {
       gtc->_depth != depth) {
     // We need to reload a new image.
     // We need to reload a new image.
-#ifdef DO_PSTATS
-    _data_transferred_pcollector.add_level(image_size);
-#endif
-    switch (target) {
-    case GL_TEXTURE_1D:
-      nassertr(image_compression == Texture::CM_off, false);
-      GLP(TexImage1D)(target, 0, internal_format,
-                      width, 0,
-                      external_format, component_type, image);
-      break;
 
 
-    case GL_TEXTURE_3D:
-      if (_supports_3d_texture) {
-	nassertr(image_compression == Texture::CM_off, false);
-        _glTexImage3D(target, 0, internal_format,
-                      width, height, depth, 0,
-                      external_format, component_type, image);
-      } else {
-        report_my_gl_errors();
-        return false;
+    for (int n = 0; n < num_ram_mipmap_levels; ++n) {
+      const unsigned char *image = tex->get_ram_mipmap_image(n);
+      if (image == (const unsigned char *)NULL) {
+        GLCAT.warning()
+          << "No mipmap level " << n << " defined for " << tex->get_name()
+          << "\n";
+        // No mipmap level n; stop here.
+        break;
+      }
+      size_t image_size = tex->get_ram_mipmap_image_size(n);
+      if (one_page_only) {
+        image_size = tex->get_ram_mipmap_page_size(n);
+        image += image_size * z;
       }
       }
-      break;
 
 
-    default:
-      if (image_compression == Texture::CM_off) {
-	GLP(TexImage2D)(target, 0, internal_format,
-			width, height, 0,
-			external_format, component_type, image);
-      } else {
-	_glCompressedTexImage2D(target, 0, external_format, width, height, 
-				0, image_size, image);
+#ifdef DO_PSTATS
+      _data_transferred_pcollector.add_level(image_size);
+#endif
+      switch (target) {
+      case GL_TEXTURE_1D:
+        if (image_compression == Texture::CM_off) {
+          GLP(TexImage1D)(target, n, internal_format,
+                          width, 0,
+                          external_format, component_type, image);
+        } else {
+          _glCompressedTexImage1D(target, n, external_format, width,
+                                  0, image_size, image);
+        }
+        break;
+        
+      case GL_TEXTURE_3D:
+        if (_supports_3d_texture) {
+          if (image_compression == Texture::CM_off) {
+            _glTexImage3D(target, n, internal_format,
+                          width, height, depth, 0,
+                          external_format, component_type, image);
+          } else {
+            _glCompressedTexImage3D(target, n, external_format, width, 
+                                    height, depth,
+                                    0, image_size, image);
+          }
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
+        
+      default:
+        if (image_compression == Texture::CM_off) {
+          GLP(TexImage2D)(target, n, internal_format,
+                          width, height, 0,
+                          external_format, component_type, image);
+        } else {
+          _glCompressedTexImage2D(target, n, external_format, width, height, 
+                                  0, image_size, image);
+        }
       }
       }
+
+      highest_level = n;
+
+      width = max(width >> 1, 1);
+      height = max(height >> 1, 1);
+      depth = max(depth >> 1, 1);
     }
     }
   } else {
   } else {
     // We can reload the image over the previous image, possibly
     // We can reload the image over the previous image, possibly
     // saving on texture memory fragmentation.
     // saving on texture memory fragmentation.
+    for (int n = 0; n < num_ram_mipmap_levels; ++n) {
+      const unsigned char *image = tex->get_ram_mipmap_image(n);
+      if (image == (const unsigned char *)NULL) {
+        GLCAT.warning()
+          << "No mipmap level " << n << " defined for " << tex->get_name()
+          << "\n";
+        // No mipmap level n; stop here.
+        break;
+      }
+      size_t image_size = tex->get_ram_mipmap_image_size(n);
+      if (one_page_only) {
+        image_size = tex->get_ram_mipmap_page_size(n);
+        image += image_size * z;
+      }
+
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
-    _data_transferred_pcollector.add_level(image_size);
+      _data_transferred_pcollector.add_level(image_size);
 #endif
 #endif
-    switch (target) {
-    case GL_TEXTURE_1D:
-      nassertr(image_compression == Texture::CM_off, false);
-      GLP(TexSubImage1D)(target, 0, 0, width,
-                         external_format, component_type, image);
-      break;
+      switch (target) {
+      case GL_TEXTURE_1D:
+        if (image_compression == Texture::CM_off) {
+          GLP(TexSubImage1D)(target, n, 0, width,
+                             external_format, component_type, image);
+        } else {
+          _glCompressedTexSubImage1D(target, n, 0, width,
+                                     external_format, image_size, image);
+        }
+        break;
 
 
-    case GL_TEXTURE_3D:
-      if (_supports_3d_texture) {
-	nassertr(image_compression == Texture::CM_off, false);
-        _glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
-                         external_format, component_type, image);
-      } else {
-        report_my_gl_errors();
-        return false;
+      case GL_TEXTURE_3D:
+        if (_supports_3d_texture) {
+          if (image_compression == Texture::CM_off) {
+            _glTexSubImage3D(target, n, 0, 0, 0, width, height, depth,
+                             external_format, component_type, image);
+          } else {
+            _glCompressedTexSubImage3D(target, n, 0, 0, 0, width, height, depth,
+                                       external_format, image_size, image);
+          }
+        } else {
+          report_my_gl_errors();
+          return false;
+        }
+        break;
+        
+      default:
+        if (image_compression == Texture::CM_off) {
+          GLP(TexSubImage2D)(target, n, 0, 0, width, height,
+                             external_format, component_type, image);
+        } else {
+          _glCompressedTexSubImage2D(target, n, 0, 0, width, height,
+                                     external_format, image_size, image);
+        }
+        break;
       }
       }
-      break;
 
 
-    default:
-      if (image_compression == Texture::CM_off) {
-	GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
-			   external_format, component_type, image);
-      } else {
-	_glCompressedTexSubImage2D(target, 0, 0, 0, width, height,
-				   external_format, image_size, image);
-      }
-      break;
+      highest_level = n;
+
+      width = max(width >> 1, 1);
+      height = max(height >> 1, 1);
+      depth = max(depth >> 1, 1);
     }
     }
   }
   }
 
 
+  if (load_ram_mipmaps) {
+    // By the time we get here, we have successfully loaded a certain
+    // number of mipmap levels.  Tell the GL that's all it's going to
+    // get.
+    GLP(TexParameteri)(target, GL_TEXTURE_MAX_LEVEL, highest_level);
+
+  } else if (uses_mipmaps) {
+    // Since the mipmap levels were auto-generated and are therefore
+    // complete, make sure the GL doesn't remember some previous value
+    // for GL_TEXTURE_MAX_LEVEL from the above call--set it to the
+    // full count of mipmap levels.
+    GLP(TexParameteri)(target, GL_TEXTURE_MAX_LEVEL, tex->get_expected_num_mipmap_levels() - 1);
+  }
+
   // Report the error message explicitly if the GL texture creation
   // Report the error message explicitly if the GL texture creation
   // failed.
   // failed.
   GLenum error_code = GLP(GetError)();
   GLenum error_code = GLP(GetError)();
   if (error_code != GL_NO_ERROR) {
   if (error_code != GL_NO_ERROR) {
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
     GLCAT.error()
     GLCAT.error()
-      << "GL texture creation failed for " << gtc->get_texture()->get_name();
+      << "GL texture creation failed for " << tex->get_name();
     if (error_string != (const GLubyte *)NULL) {
     if (error_string != (const GLubyte *)NULL) {
       GLCAT.error(false)
       GLCAT.error(false)
         << " : " << error_string;
         << " : " << error_string;
@@ -6810,6 +6821,91 @@ check_nonresident_texture(BufferContextChain &chain) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::extract_texture_image
+//       Access: Protected
+//  Description: Called from extract_texture_data(), this gets just
+//               the image array for a particular mipmap level (or for
+//               the base image).
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsStateGuardian)::
+extract_texture_image(PTA_uchar &image, size_t &page_size,
+		      Texture *tex, GLenum target, GLenum page_target,
+		      Texture::ComponentType type, 
+		      Texture::CompressionMode compression, int n) {
+  if (target == GL_TEXTURE_CUBE_MAP) {
+    // A cube map, compressed or uncompressed.  This we must extract
+    // one page at a time.
+
+    // If the cube map is compressed, we assume that all the
+    // compressed pages are exactly the same size.  OpenGL doesn't
+    // make this assumption, but it happens to be true for all
+    // currently extant compression schemes, and it makes things
+    // simpler for us.  (It also makes things much simpler for the
+    // graphics hardware, so it's likely to continue to be true for a
+    // while at least.)
+
+    GLenum external_format = get_external_image_format(tex);
+    GLenum pixel_type = get_component_type(type);
+    page_size = tex->get_expected_ram_mipmap_page_size(n);
+
+    if (compression != Texture::CM_off) {
+      GLint image_size;
+      GLP(GetTexLevelParameteriv)(page_target, n, 
+				  GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
+      nassertr(image_size <= (int)page_size, false);
+      page_size = image_size;
+    }
+
+    image = PTA_uchar::empty_array(page_size * 6);
+
+    for (int z = 0; z < 6; ++z) {
+      page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
+      
+      if (compression == Texture::CM_off) {
+	GLP(GetTexImage)(page_target, n, external_format, pixel_type, 
+			 image.p() + z * page_size);
+      } else {
+	_glGetCompressedTexImage(page_target, 0, image.p() + z * page_size);
+      }
+    }
+
+  } else if (compression == Texture::CM_off) {
+    // An uncompressed 1-d, 2-d, or 3-d texture.
+    image = PTA_uchar::empty_array(tex->get_expected_ram_mipmap_image_size(n));
+    GLenum external_format = get_external_image_format(tex);
+    GLenum pixel_type = get_component_type(type);
+    GLP(GetTexImage)(target, n, external_format, pixel_type, image.p());
+
+  } else {
+    // A compressed 1-d, 2-d, or 3-d texture.
+    GLint image_size;
+    GLP(GetTexLevelParameteriv)(target, n, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
+    page_size = image_size / tex->get_z_size();
+    image = PTA_uchar::empty_array(image_size);
+    _glGetCompressedTexImage(target, n, image.p());
+  }
+
+  // Now see if we were successful.
+  GLenum error_code = GLP(GetError)();
+  if (error_code != GL_NO_ERROR) {
+    const GLubyte *error_string = GLUP(ErrorString)(error_code);
+    GLCAT.error()
+      << "Unable to extract texture for " << *tex
+      << ", mipmap level " << n << ": ";
+    if (error_string != (const GLubyte *)NULL) {
+      GLCAT.error(false)
+        << " : " << error_string;
+    }
+    GLCAT.error(false)
+      << "\n";
+
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::do_point_size
 //     Function: GLGraphicsStateGuardian::do_point_size
 //       Access: Protected
 //       Access: Protected
@@ -6850,173 +6946,3 @@ do_point_size() {
 
 
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
-
-#ifndef NDEBUG
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::build_phony_mipmaps
-//       Access: Protected
-//  Description: Generates a series of colored mipmap levels to aid in
-//               visualizing the mipmap levels as the hardware applies
-//               them.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-build_phony_mipmaps(Texture *tex) {
-  int x_size = tex->get_x_size();
-  int y_size = tex->get_y_size();
-
-  GLCAT.info()
-    << "Building phony mipmap levels for " << tex->get_name() << "\n";
-  int level = 0;
-  while (x_size > 0 && y_size > 0) {
-    GLCAT.info(false)
-      << "  level " << level << " is " << x_size << " by " << y_size << "\n";
-    build_phony_mipmap_level(level, x_size, y_size);
-
-    x_size >>= 1;
-    y_size >>= 1;
-    level++;
-  }
-
-  while (x_size > 0) {
-    GLCAT.info(false)
-      << "  level " << level << " is " << x_size << " by 1\n";
-    build_phony_mipmap_level(level, x_size, 1);
-
-    x_size >>= 1;
-    level++;
-  }
-
-  while (y_size > 0) {
-    GLCAT.info(false)
-      << "  level " << level << " is 1 by " << y_size << "\n";
-    build_phony_mipmap_level(level, 1, y_size);
-
-    y_size >>= 1;
-    level++;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::build_phony_mipmap_level
-//       Access: Protected
-//  Description: Generates a single colored mipmap level.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-build_phony_mipmap_level(int level, int x_size, int y_size) {
-  static const int num_levels = 10;
-  static const char *level_filenames[num_levels] = {
-    "mipmap_level_0.rgb",
-    "mipmap_level_1.rgb",
-    "mipmap_level_2.rgb",
-    "mipmap_level_3.rgb",
-    "mipmap_level_4.rgb",
-    "mipmap_level_5.rgb",
-    "mipmap_level_6.rgb",
-    "mipmap_level_7.rgb",
-    "mipmap_level_8.rgb",
-    "mipmap_level_9.rgb"
-  };
-  static const RGBColorf level_colors[num_levels] = {
-    RGBColorf(1.0f, 1.0f, 1.0f),
-    RGBColorf(1.0f, 0.0f, 0.0f),
-    RGBColorf(0.0f, 1.0f, 0.0f),
-    RGBColorf(0.0f, 0.0f, 1.0f),
-    RGBColorf(1.0f, 1.0f, 0.0f),
-    RGBColorf(0.0f, 1.0f, 1.0f),
-    RGBColorf(1.0f, 0.0f, 1.0f),
-    RGBColorf(1.0f, 0.5, 0.0f),
-    RGBColorf(0.0f, 1.0f, 0.5),
-    RGBColorf(0.83, 0.71, 1.0f)
-  };
-
-  level = level % num_levels;
-  Filename filename(level_filenames[level]);
-
-  PNMImage image_sized(x_size, y_size);
-  PNMImage image_source;
-  if (filename.resolve_filename(get_texture_path()) ||
-      filename.resolve_filename(get_model_path())) {
-    image_source.read(filename);
-  }
-
-  if (image_source.is_valid()) {
-    image_sized.quick_filter_from(image_source);
-
-  } else {
-    GLCAT.info(false)
-      << "    " << filename << " cannot be read, making solid color mipmap.\n";
-    image_sized.fill(level_colors[level][0],
-                     level_colors[level][1],
-                     level_colors[level][2]);
-  }
-
-  PT(Texture) tex = new Texture;
-  if (!tex->load(image_sized)) {
-    GLCAT.warning()
-      << "Unable to load phony mipmap image.\n";
-  } else {
-    GLenum internal_format = get_internal_image_format(tex);
-    GLenum external_format = get_external_image_format(tex);
-    GLenum component_type = get_component_type(tex->get_component_type());
-
-    GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format,
-                    tex->get_x_size(), tex->get_y_size(), 0,
-                    external_format, component_type, tex->get_ram_image());
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::save_mipmap_images
-//       Access: Protected
-//  Description: Saves out each mipmap level of the indicated texture
-//               (which must also be the currently active texture in
-//               the GL state) as a separate image file to disk.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-save_mipmap_images(Texture *tex) {
-  if (tex->get_texture_type() != Texture::TT_2d_texture) {
-    // Never mind on unusual texture formats.
-    return;
-  }
-
-  Filename filename = tex->get_name();
-  string name;
-  if (filename.empty()) {
-    static int index = 0;
-    name = "texture" + format_string(index);
-    index++;
-  } else {
-    name = filename.get_basename_wo_extension();
-  }
-
-  GLenum external_format = get_external_image_format(tex);
-  GLenum type = get_component_type(tex->get_component_type());
-
-  int x_size = tex->get_x_size();
-  int y_size = tex->get_y_size();
-
-  // Specify byte-alignment for the pixels on output.
-  GLP(PixelStorei)(GL_PACK_ALIGNMENT, 1);
-
-  int mipmap_level = 0;
-  do {
-    x_size = max(x_size, 1);
-    y_size = max(y_size, 1);
-
-    PT(Texture) mtex = new Texture;
-    mtex->setup_2d_texture(x_size, y_size, tex->get_component_type(),
-                           tex->get_format());
-    GLP(GetTexImage)(GL_TEXTURE_2D, mipmap_level, external_format,
-                     type, mtex->make_ram_image());
-    Filename mipmap_filename = name + "_" + format_string(mipmap_level) + ".rgb";
-    nout << "Writing mipmap level " << mipmap_level
-         << " (" << x_size << " by " << y_size << ") "
-         << mipmap_filename << "\n";
-    mtex->write(mipmap_filename);
-
-    x_size >>= 1;
-    y_size >>= 1;
-    mipmap_level++;
-  } while (x_size > 0 || y_size > 0);
-}
-#endif  // NDEBUG

+ 12 - 10
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -65,11 +65,12 @@ typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset,
 typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
 typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
-class CLP(GeomContext);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GLGraphicsStateGuardian
 //       Class : GLGraphicsStateGuardian
@@ -274,21 +275,18 @@ protected:
                             GLenum target, GLint internal_format, 
                             GLenum target, GLint internal_format, 
                             int width, int height, int depth,
                             int width, int height, int depth,
                             GLint external_format, GLenum component_type, 
                             GLint external_format, GLenum component_type, 
-                            const unsigned char *image,
-			    size_t image_size,
+                            bool one_page_only, int z,
 			    Texture::CompressionMode image_compression);
 			    Texture::CompressionMode image_compression);
 
 
   size_t get_texture_memory_size(Texture *tex);
   size_t get_texture_memory_size(Texture *tex);
   void check_nonresident_texture(BufferContextChain &chain);
   void check_nonresident_texture(BufferContextChain &chain);
+  bool extract_texture_image(PTA_uchar &image, size_t &page_size,
+			     Texture *tex, GLenum target, GLenum page_target,
+			     Texture::ComponentType type, 
+			     Texture::CompressionMode compression, int n);
 
 
   void do_point_size();
   void do_point_size();
 
 
-#ifndef NDEBUG
-  void build_phony_mipmaps(Texture *tex);
-  void build_phony_mipmap_level(int level, int x_size, int y_size);
-  void save_mipmap_images(Texture *tex);
-#endif
-
   enum AutoAntialiasMode {
   enum AutoAntialiasMode {
     AA_poly,
     AA_poly,
     AA_line,
     AA_line,
@@ -374,8 +372,12 @@ public:
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
 
 
+  PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D;
   PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
   PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
+  PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D;
+  PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC _glCompressedTexSubImage1D;
   PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC _glCompressedTexSubImage2D;
   PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC _glCompressedTexSubImage2D;
+  PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC _glCompressedTexSubImage3D;
   PFNGLGETCOMPRESSEDTEXIMAGEPROC _glGetCompressedTexImage;
   PFNGLGETCOMPRESSEDTEXIMAGEPROC _glGetCompressedTexImage;
 
 
   bool _supports_bgr;
   bool _supports_bgr;

+ 0 - 10
panda/src/glstuff/glmisc_src.cxx

@@ -56,16 +56,6 @@ ConfigVariableBool CLP(force_mipmaps)
    PRC_DESC("Configure this true to enable full trilinear mipmapping on every "
    PRC_DESC("Configure this true to enable full trilinear mipmapping on every "
             "texture, whether it asks for it or not."));
             "texture, whether it asks for it or not."));
 
 
-ConfigVariableBool CLP(show_mipmaps)
-  ("gl-show-mipmaps", false,
-   PRC_DESC("Configure this true to cause mipmaps to be rendered with phony "
-            "colors, using mipmap_level_*.rgb if they are available."));
-
-ConfigVariableBool CLP(save_mipmaps)
-  ("gl-save-mipmaps", false,
-   PRC_DESC("Configure this true to cause the generated mipmap images to be "
-            "written out to image files on the disk as they are generated."));
-
 ConfigVariableBool CLP(color_mask)
 ConfigVariableBool CLP(color_mask)
   ("gl-color-mask", true,
   ("gl-color-mask", true,
    PRC_DESC("Configure this false if your GL's implementation of glColorMask() "
    PRC_DESC("Configure this false if your GL's implementation of glColorMask() "

+ 0 - 2
panda/src/glstuff/glmisc_src.h

@@ -27,8 +27,6 @@ extern ConfigVariableBool CLP(support_clamp_to_border);
 extern ConfigVariableBool CLP(ignore_filters);
 extern ConfigVariableBool CLP(ignore_filters);
 extern ConfigVariableBool CLP(ignore_mipmaps);
 extern ConfigVariableBool CLP(ignore_mipmaps);
 extern ConfigVariableBool CLP(force_mipmaps);
 extern ConfigVariableBool CLP(force_mipmaps);
-extern ConfigVariableBool CLP(show_mipmaps);
-extern ConfigVariableBool CLP(save_mipmaps);
 extern ConfigVariableBool CLP(color_mask);
 extern ConfigVariableBool CLP(color_mask);
 extern ConfigVariableBool CLP(compile_and_execute);
 extern ConfigVariableBool CLP(compile_and_execute);
 
 

+ 370 - 37
panda/src/gobj/texture.I

@@ -126,6 +126,240 @@ setup_cube_map(int size, ComponentType component_type,
   setup_texture(TT_cube_map, size, size, 6, component_type, format);
   setup_texture(TT_cube_map, size, size, 6, component_type, format);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads the named filename into the texture.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+read(const Filename &fullpath) {
+  return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Combine a 3-component image with a grayscale image
+//               to get a 4-component image.
+//
+//               See the description of the full-parameter read()
+//               method for the meaning of the
+//               primary_file_num_channels and alpha_file_channel
+//               parameters.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+read(const Filename &fullpath, const Filename &alpha_fullpath,
+     int primary_file_num_channels, int alpha_file_channel) {
+  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
+		 alpha_file_channel, 0, 0, false, false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads a single file into a single page or mipmap
+//               level, or automatically reads a series of files into
+//               a series of pages and/or mipmap levels.
+//
+//               See the description of the full-parameter read()
+//               method for the meaning of the various parameters.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+read(const Filename &fullpath, int z, int n, 
+     bool read_pages, bool read_mipmaps) {
+  return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::read
+//       Access: Published
+//  Description: Reads the texture from the indicated filename.  If
+//               primary_file_num_channels is not 0, it specifies the
+//               number of components to downgrade the image to if it
+//               is greater than this number.
+//
+//               If the filename has the extension .txo, this
+//               implicitly reads a texture object instead of a
+//               filename (which replaces all of the texture
+//               properties).  In this case, all the rest of the
+//               parameters are ignored, and the filename should not
+//               contain any hash marks; just the one named file will
+//               be read, since a single .txo file can contain all
+//               pages and mipmaps necessary to define a texture.
+//
+//               If alpha_fullpath is not empty, it specifies the name
+//               of a file from which to retrieve the alpha.  In this
+//               case, alpha_file_channel represents the numeric
+//               channel of this image file to use as the resulting
+//               texture's alpha channel; usually, this is 0 to
+//               indicate the grayscale combination of r, g, b; or it
+//               may be a one-based channel number, e.g. 1 for the red
+//               channel, 2 for the green channel, and so on.
+//
+//               If read pages is false, then z indicates the page
+//               number into which this image will be assigned.
+//               Normally this is 0 for the first (or only) page of
+//               the texture.  3-D textures have one page for each
+//               level of depth, and cube map textures always have six
+//               pages.
+//
+//               If read_pages is true, multiple images will be read
+//               at once, one for each page of a cube map or a 3-D
+//               texture.  In this case, the filename should contain a
+//               sequence of one or more hash marks ("#") which will
+//               be filled in with the z value of each page,
+//               zero-based.  In this case, the z parameter indicates
+//               the maximum z value that will be loaded, or 0 to load
+//               all filenames that exist.
+//
+//               If read_mipmaps is false, then n indicates the mipmap
+//               level to which this image will be assigned.  Normally
+//               this is 0 for the base texture image, but it is
+//               possible to load custom mipmap levels into the later
+//               images.  After the base texture image is loaded (thus
+//               defining the size of the texture), you can call
+//               get_expected_num_mipmap_levels() to determine the
+//               maximum sensible value for n.
+//
+//               If read_mipmaps is true, multiple images will be read
+//               as above, but this time the images represent the
+//               different mipmap levels of the texture image.  In
+//               this case, the n parameter indicates the maximum n
+//               value that will be loaded, or 0 to load all filenames
+//               that exist (up to the expected number of mipmap
+//               levels).
+//
+//               If both read_pages and read_mipmaps is true, then
+//               both sequences will be read; the filename should
+//               contain two sequences of hash marks, separated by
+//               some character such as a hyphen, underscore, or dot.
+//               The first hash mark sequence will be filled in with
+//               the mipmap level, while the second hash mark sequence
+//               will be the page index.
+//
+//               This method implicitly sets keep_ram_image to false.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+read(const Filename &fullpath, const Filename &alpha_fullpath,
+     int primary_file_num_channels, int alpha_file_channel,
+     int z, int n, bool read_pages, bool read_mipmaps) {
+  return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
+		 alpha_file_channel, z, n, read_pages, read_mipmaps);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::write
+//       Access: Published
+//  Description: Writes the texture to the named filename.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+write(const Filename &fullpath) {
+  return do_write(fullpath, 0, 0, false, false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::write
+//       Access: Published
+//  Description: Writes a single page or mipmap level to a single
+//               file, or automatically writes a series of pages
+//               and/or mipmap levels to a numbered series of files.
+//
+//               If the filename ends in the extension .txo, this
+//               implicitly writes a Panda texture object (.txo)
+//               instead of an image file.  In this case, the
+//               remaining parameters are ignored, and only one file
+//               is written, which will contain all of the pages and
+//               resident mipmap levels in the texture.
+//
+//               If write_pages is false, then z indicates the page
+//               number to write.  3-D textures have one page number
+//               for each level of depth; cube maps have six pages
+//               number 0 through 5.  Other kinds of textures have
+//               only one page, numbered 0.
+//
+//               If write_pages is true, then all pages of the texture
+//               will be written.  In this case z is ignored, and the
+//               filename should contain a sequence of hash marks
+//               ("#") which will be filled in with the page index
+//               number.
+//
+//               If write_mipmaps is false, then n indicates the
+//               mipmap level number to write.  Normally, this is 0,
+//               for the base texture image.  Normally, the mipmap
+//               levels of a texture are not available in RAM (they
+//               are generated automatically by the graphics card).
+//               However, if you have the mipmap levels available, for
+//               instance because you called
+//               generate_ram_mipmap_images() to generate them
+//               internally, or you called
+//               GraphicsEngine::extract_texture_data() to retrieve
+//               them from the graphics card, then you may write out
+//               each mipmap level with this parameter.
+//
+//               If write_mipmaps is true, then all mipmap levels of
+//               the texture will be written.  In this case n is
+//               ignored, and the filename should contain a sequence
+//               of hash marks ("#") which will be filled in with the
+//               mipmap level number.
+//
+//               If both write_pages and write_mipmaps is true, then
+//               all pages and all mipmap levels will be written.  In
+//               this case, the filename should contain two different
+//               sequences of hash marks, separated by a character
+//               such as a hyphen, underscore, or dot.  The first hash
+//               mark sequence will be filled in with the mipmap
+//               level, while the second hash mark sequence will be
+//               the page index.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+write(const Filename &fullpath, int z, int n, 
+      bool write_pages, bool write_mipmaps) {
+  return do_write(fullpath, z, n, write_pages, write_mipmaps);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::load
+//       Access: Published
+//  Description: Replaces the texture with the indicated image.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+load(const PNMImage &pnmimage) {
+  return do_load_one(pnmimage, 0, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::load
+//       Access: Published
+//  Description: Stores the indicated image in the given page and
+//               mipmap level.  See read().
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+load(const PNMImage &pnmimage, int z, int n) {
+  return do_load_one(pnmimage, z, n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::store
+//       Access: Published
+//  Description: Saves the texture to the indicated PNMImage, but does
+//               not write it to disk.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+store(PNMImage &pnmimage) const {
+  return do_store_one(pnmimage, 0, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::store
+//       Access: Published
+//  Description: Saves the indicated page and mipmap level of the
+//               texture to the PNMImage.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+store(PNMImage &pnmimage, int z, int n) const {
+  return do_store_one(pnmimage, z, n);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::has_filename
 //     Function: Texture::has_filename
 //       Access: Published
 //       Access: Published
@@ -462,7 +696,10 @@ might_have_ram_image() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE size_t Texture::
 INLINE size_t Texture::
 get_ram_image_size() const {
 get_ram_image_size() const {
-  return _ram_image.size();
+  if (_ram_images.empty()) {
+    return 0;
+  }
+  return _ram_images[0]._image.size();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -479,7 +716,11 @@ get_ram_image_size() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE size_t Texture::
 INLINE size_t Texture::
 get_ram_page_size() const {
 get_ram_page_size() const {
-  return _ram_image_compression != CM_off ? _ram_page_size : get_expected_ram_page_size();
+  if (_ram_image_compression == CM_off || _ram_images.empty()) {
+    return get_expected_ram_page_size();
+  } else {
+    return _ram_images[0]._page_size;
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -542,6 +783,99 @@ set_keep_ram_image(bool keep_ram_image) {
   _keep_ram_image = keep_ram_image;
   _keep_ram_image = keep_ram_image;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_num_ram_mipmap_images
+//       Access: Published
+//  Description: Returns the maximum number of mipmap level images
+//               available in system memory.  The actual number may be
+//               less than this; use has_ram_mipmap_image() to verify
+//               each level.
+////////////////////////////////////////////////////////////////////
+INLINE int Texture::
+get_num_ram_mipmap_images() const {
+  return _ram_images.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::has_ram_mipmap_image
+//       Access: Published
+//  Description: Returns true if the Texture has the nth mipmap level
+//               available in system memory, false otherwise.  If the
+//               texture's minfilter mode requires mipmapping (see
+//               uses_mipmaps()), and all the texture's mipmap levels
+//               are not available when the texture is rendered, they
+//               will be generated automatically.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+has_ram_mipmap_image(int n) const {
+  return (n >= 0 && n < (int)_ram_images.size() && !_ram_images[n]._image.empty());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_ram_mipmap_image_size
+//       Access: Published
+//  Description: Returns the number of bytes used by the in-memory
+//               image for mipmap level n, or 0 if there is no
+//               in-memory image for this mipmap level.
+////////////////////////////////////////////////////////////////////
+INLINE size_t Texture::
+get_ram_mipmap_image_size(int n) const {
+  if (n >= 0 && n < (int)_ram_images.size()) {
+    return _ram_images[n]._image.size();
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_ram_mipmap_page_size
+//       Access: Published
+//  Description: Returns the number of bytes used by the in-memory
+//               image per page for mipmap level n, or 0 if there is
+//               no in-memory image for this mipmap level.
+//
+//               For a non-compressed texture, this is the same as
+//               get_expected_ram_mipmap_page_size().  For a compressed
+//               texture, this may be a smaller value.  (We do assume
+//               that all pages will be the same size on a compressed
+//               texture).
+////////////////////////////////////////////////////////////////////
+INLINE size_t Texture::
+get_ram_mipmap_page_size(int n) const {
+  if (_ram_image_compression != CM_off) {
+    if (n >= 0 && n < (int)_ram_images.size()) {
+      return _ram_images[n]._page_size;
+    }
+    return 0;
+  } else {
+    return get_expected_ram_mipmap_page_size(n);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_expected_ram_mipmap_image_size
+//       Access: Published
+//  Description: Returns the number of bytes that *ought* to be used
+//               by the in-memory image for mipmap level n, based on
+//               the texture parameters.
+////////////////////////////////////////////////////////////////////
+INLINE size_t Texture::
+get_expected_ram_mipmap_image_size(int n) const {
+  return get_expected_ram_mipmap_page_size(n) * (size_t)get_expected_mipmap_z_size(n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_expected_ram_mipmap_page_size
+//       Access: Published
+//  Description: Returns the number of bytes that should be used per
+//               each Z page of the 3-d texture, for mipmap level n.
+//               For a 2-d or 1-d texture, this is the same as
+//               get_expected_ram_mipmap_image_size(n).
+////////////////////////////////////////////////////////////////////
+INLINE size_t Texture::
+get_expected_ram_mipmap_page_size(int n) const {
+  return (size_t)(get_expected_mipmap_x_size(n) * get_expected_mipmap_y_size(n) * _num_components * _component_width);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_modified
 //     Function: Texture::get_modified
 //       Access: Published
 //       Access: Published
@@ -714,28 +1048,29 @@ set_z_size(int z_size) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: Texture::set_loaded_from_disk
+//     Function: Texture::set_loaded_from_image
 //       Access: Published
 //       Access: Published
 //  Description: Sets the flag that indicates the texture has been
 //  Description: Sets the flag that indicates the texture has been
-//               loaded from a disk file.  You should also ensure the
-//               filename has been set correctly.  When this flag is
-//               true, the texture may be automatically reloaded when
-//               its ram image needs to be replaced.
+//               loaded from a disk file or PNMImage.  You should also
+//               ensure the filename has been set correctly.  When
+//               this flag is true, the texture may be automatically
+//               reloaded when its ram image needs to be replaced.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-set_loaded_from_disk() {
-  _loaded_from_disk = true;
+set_loaded_from_image() {
+  _loaded_from_image = true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: Texture::get_loaded_from_disk
+//     Function: Texture::get_loaded_from_image
 //       Access: Published
 //       Access: Published
 //  Description: Returns the flag that indicates the texture has been
 //  Description: Returns the flag that indicates the texture has been
-//               loaded from a disk file.  See set_loaded_from_disk().
+//               loaded from a disk file or PNMImage.  See
+//               set_loaded_from_image().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool Texture::
 INLINE bool Texture::
-get_loaded_from_disk() const {
-  return _loaded_from_disk;
+get_loaded_from_image() const {
+  return _loaded_from_image;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -800,7 +1135,7 @@ set_match_framebuffer_format(bool flag) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store_unscaled_byte
 //     Function: Texture::store_unscaled_byte
-//       Access: Private
+//       Access: Private, Static
 //  Description: This is used by load() to store the next consecutive
 //  Description: This is used by load() to store the next consecutive
 //               component value into the indicated element of the
 //               component value into the indicated element of the
 //               array, which is taken to be an array of unsigned
 //               array, which is taken to be an array of unsigned
@@ -808,13 +1143,13 @@ set_match_framebuffer_format(bool flag) {
 //               0-255.
 //               0-255.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-store_unscaled_byte(int &index, int value) {
-  _ram_image[index++] = (uchar)value;
+store_unscaled_byte(unsigned char *&p, int value) {
+  (*p++) = (uchar)value;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store_unscaled_short
 //     Function: Texture::store_unscaled_short
-//       Access: Private
+//       Access: Private, Static
 //  Description: This is used by load() to store the next consecutive
 //  Description: This is used by load() to store the next consecutive
 //               component value into the indicated element of the
 //               component value into the indicated element of the
 //               array, which is taken to be an array of unsigned
 //               array, which is taken to be an array of unsigned
@@ -822,19 +1157,19 @@ store_unscaled_byte(int &index, int value) {
 //               0-65535.
 //               0-65535.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-store_unscaled_short(int &index, int value) {
+store_unscaled_short(unsigned char *&p, int value) {
   union {
   union {
     ushort us;
     ushort us;
     uchar uc[2];
     uchar uc[2];
   } v;
   } v;
   v.us = (ushort)value;
   v.us = (ushort)value;
-  _ram_image[index++] = v.uc[0];
-  _ram_image[index++] = v.uc[1];
+  (*p++) = v.uc[0];
+  (*p++) = v.uc[1];
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store_scaled_byte
 //     Function: Texture::store_scaled_byte
-//       Access: Private
+//       Access: Private, Static
 //  Description: This is used by load() to store the next consecutive
 //  Description: This is used by load() to store the next consecutive
 //               component value into the indicated element of the
 //               component value into the indicated element of the
 //               array, which is taken to be an array of unsigned
 //               array, which is taken to be an array of unsigned
@@ -842,13 +1177,13 @@ store_unscaled_short(int &index, int value) {
 //               factor before storing it.
 //               factor before storing it.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-store_scaled_byte(int &index, int value, double scale) {
-  store_unscaled_byte(index, (int)(value * scale));
+store_scaled_byte(unsigned char *&p, int value, double scale) {
+  store_unscaled_byte(p, (int)(value * scale));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store_scaled_short
 //     Function: Texture::store_scaled_short
-//       Access: Private
+//       Access: Private, Static
 //  Description: This is used by load() to store the next consecutive
 //  Description: This is used by load() to store the next consecutive
 //               component value into the indicated element of the
 //               component value into the indicated element of the
 //               array, which is taken to be an array of unsigned
 //               array, which is taken to be an array of unsigned
@@ -856,41 +1191,39 @@ store_scaled_byte(int &index, int value, double scale) {
 //               factor before storing it.
 //               factor before storing it.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-store_scaled_short(int &index, int value, double scale) {
-  store_unscaled_short(index, (int)(value * scale));
+store_scaled_short(unsigned char *&p, int value, double scale) {
+  store_unscaled_short(p, (int)(value * scale));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_unsigned_byte
 //     Function: Texture::get_unsigned_byte
-//       Access: Private
-//  Description: This is used by store() to retieve the next
+//       Access: Private, Static
+//  Description: This is used by store() to retrieve the next
 //               consecutive component value from the indicated
 //               consecutive component value from the indicated
 //               element of the array, which is taken to be an array
 //               element of the array, which is taken to be an array
 //               of unsigned bytes.
 //               of unsigned bytes.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double Texture::
 INLINE double Texture::
-get_unsigned_byte(int &index) const {
-  nassertr(index >= 0 && index < (int)_ram_image.size(), 0.0);
-  return (double)_ram_image[index++] / 255.0;
+get_unsigned_byte(const unsigned char *&p) {
+  return (double)(*p++) / 255.0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::get_unsigned_short
 //     Function: Texture::get_unsigned_short
-//       Access: Private
-//  Description: This is used by store() to retieve the next
+//       Access: Private, Static
+//  Description: This is used by store() to retrieve the next
 //               consecutive component value from the indicated
 //               consecutive component value from the indicated
 //               element of the array, which is taken to be an array
 //               element of the array, which is taken to be an array
 //               of unsigned shorts.
 //               of unsigned shorts.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double Texture::
 INLINE double Texture::
-get_unsigned_short(int &index) const {
-  nassertr(index >= 0 && index+1 < (int)_ram_image.size(), 0.0);
+get_unsigned_short(const unsigned char *&p) {
   union {
   union {
     ushort us;
     ushort us;
     uchar uc[2];
     uchar uc[2];
   } v;
   } v;
-  v.uc[0] = _ram_image[index++];
-  v.uc[1] = _ram_image[index++];
+  v.uc[0] = (*p++);
+  v.uc[1] = (*p++);
   return (double)v.us / 65535.0;
   return (double)v.us / 65535.0;
 }
 }
 
 

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 362 - 589
panda/src/gobj/texture.cxx


+ 112 - 25
panda/src/gobj/texture.h

@@ -146,7 +146,7 @@ PUBLISHED:
   };
   };
 
 
   enum CompressionMode {
   enum CompressionMode {
-    // Generic compresssion modes.  Usually, you should choose one of
+    // Generic compression modes.  Usually, you should choose one of
     // these.
     // these.
     CM_default,  // on or off, according to compressed-textures
     CM_default,  // on or off, according to compressed-textures
     CM_off,      // uncompressed image
     CM_off,      // uncompressed image
@@ -174,6 +174,7 @@ PUBLISHED:
   virtual ~Texture();
   virtual ~Texture();
 
 
   virtual PT(Texture) make_copy();
   virtual PT(Texture) make_copy();
+  virtual void clear();
 
 
   void setup_texture(TextureType texture_type,
   void setup_texture(TextureType texture_type,
                      int x_size, int y_size, int z_size,
                      int x_size, int y_size, int z_size,
@@ -194,21 +195,26 @@ PUBLISHED:
 
 
   void generate_normalization_cube_map(int size);
   void generate_normalization_cube_map(int size);
 
 
-  virtual bool read(const Filename &fullpath, int z = 0,
-        int primary_file_num_channels = 0);
-  virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath,
-        int z = 0,
-        int primary_file_num_channels = 0, int alpha_file_channel = 0);
-  bool write(const Filename &fullpath, int z = 0) const;
+  INLINE bool read(const Filename &fullpath);
+  INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
+		   int primary_file_num_channels, int alpha_file_channel);
+  INLINE bool read(const Filename &fullpath, int z, int n, 
+		   bool read_pages, bool read_mipmaps);
+  INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath,
+		   int primary_file_num_channels, int alpha_file_channel,
+		   int z, int n, bool read_pages, bool read_mipmaps);
+
+  INLINE bool write(const Filename &fullpath);
+  INLINE bool write(const Filename &fullpath, int z, int n, 
+		    bool write_pages, bool write_mipmaps);
 
 
   bool read_txo(istream &in, const string &filename = "stream");
   bool read_txo(istream &in, const string &filename = "stream");
   bool write_txo(ostream &out, const string &filename = "stream") const;
   bool write_txo(ostream &out, const string &filename = "stream") const;
 
 
-  bool read_pages(Filename fullpath_pattern, int z_size = 0);
-  bool write_pages(Filename fullpath_pattern);
-
-  virtual bool load(const PNMImage &pnmimage, int z = 0);
-  bool store(PNMImage &pnmimage, int z = 0) const;
+  INLINE bool load(const PNMImage &pnmimage);
+  INLINE bool load(const PNMImage &pnmimage, int z, int n);
+  INLINE bool store(PNMImage &pnmimage) const;
+  INLINE bool store(PNMImage &pnmimage, int z, int n) const;
 
 
   Texture *load_related(const PT(InternalName) &suffix) const;
   Texture *load_related(const PT(InternalName) &suffix) const;
 
 
@@ -252,6 +258,11 @@ PUBLISHED:
   INLINE bool get_render_to_texture() const;
   INLINE bool get_render_to_texture() const;
   INLINE bool uses_mipmaps() const;
   INLINE bool uses_mipmaps() const;
 
 
+  int get_expected_num_mipmap_levels() const;
+  int get_expected_mipmap_x_size(int n) const;
+  int get_expected_mipmap_y_size(int n) const;
+  int get_expected_mipmap_z_size(int n) const;
+
   virtual bool has_ram_image() const;
   virtual bool has_ram_image() const;
   INLINE bool might_have_ram_image() const;
   INLINE bool might_have_ram_image() const;
   INLINE size_t get_ram_image_size() const;
   INLINE size_t get_ram_image_size() const;
@@ -268,6 +279,21 @@ PUBLISHED:
   INLINE void set_keep_ram_image(bool keep_ram_image);
   INLINE void set_keep_ram_image(bool keep_ram_image);
   virtual bool get_keep_ram_image() const;
   virtual bool get_keep_ram_image() const;
 
 
+  INLINE int get_num_ram_mipmap_images() const;
+  INLINE bool has_ram_mipmap_image(int n) const;
+  bool has_all_ram_mipmap_images() const;
+  INLINE size_t get_ram_mipmap_image_size(int n) const;
+  INLINE size_t get_ram_mipmap_page_size(int n) const;
+  INLINE size_t get_expected_ram_mipmap_image_size(int n) const;
+  INLINE size_t get_expected_ram_mipmap_page_size(int n) const;
+  CPTA_uchar get_ram_mipmap_image(int n);
+  PTA_uchar modify_ram_mipmap_image(int n);
+  PTA_uchar make_ram_mipmap_image(int n);
+  void set_ram_mipmap_image(int n, PTA_uchar image, size_t page_size = 0);
+  void clear_ram_mipmap_image(int n);
+  void clear_ram_mipmap_images();
+  void generate_ram_mipmap_images();
+
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
 
 
   void prepare(PreparedGraphicsObjects *prepared_objects);
   void prepare(PreparedGraphicsObjects *prepared_objects);
@@ -297,18 +323,18 @@ PUBLISHED:
   INLINE void set_z_size(int z_size);
   INLINE void set_z_size(int z_size);
   void set_format(Format format);
   void set_format(Format format);
   void set_component_type(ComponentType component_type);
   void set_component_type(ComponentType component_type);
-  INLINE void set_loaded_from_disk();
-  INLINE bool get_loaded_from_disk() const;
+  INLINE void set_loaded_from_image();
+  INLINE bool get_loaded_from_image() const;
 
 
   INLINE void set_loaded_from_txo();
   INLINE void set_loaded_from_txo();
   INLINE bool get_loaded_from_txo() const;
   INLINE bool get_loaded_from_txo() const;
 
 
+  static bool is_mipmap(FilterType type);
+
 public:
 public:
   INLINE bool get_match_framebuffer_format() const;
   INLINE bool get_match_framebuffer_format() const;
   INLINE void set_match_framebuffer_format(bool flag);
   INLINE void set_match_framebuffer_format(bool flag);
 
 
-  static bool is_mipmap(FilterType type);
-
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                               GraphicsStateGuardianBase *gsg);
                               GraphicsStateGuardianBase *gsg);
 
 
@@ -328,6 +354,18 @@ public:
   static bool has_alpha(Format format);
   static bool has_alpha(Format format);
 
 
 protected:
 protected:
+  virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath,
+		       int primary_file_num_channels, int alpha_file_channel,
+		       int z, int n, bool read_pages, bool read_mipmaps);
+  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+			   int z, int n, int primary_file_num_channels, int alpha_file_channel);
+  bool do_write(const Filename &fullpath, int z, int n, 
+		bool write_pages, bool write_mipmaps) const;
+  bool do_write_one(const Filename &fullpath, int z, int n) const;
+
+  virtual bool do_load_one(const PNMImage &pnmimage, int z, int n);
+  bool do_store_one(PNMImage &pnmimage, int z, int n) const;
+
   virtual void reconsider_dirty();
   virtual void reconsider_dirty();
   virtual void reload_ram_image();
   virtual void reload_ram_image();
 
 
@@ -335,23 +373,65 @@ protected:
   bool reconsider_image_properties(int x_size, int y_size, int num_components,
   bool reconsider_image_properties(int x_size, int y_size, int num_components,
            ComponentType component_type, int z);
            ComponentType component_type, int z);
 
 
+  // This nested class declaration is used below.
+  class RamImage {
+  public:
+    PTA_uchar _image;
+    size_t _page_size;
+  };
+
 private:
 private:
+  void convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z,
+                             const PNMImage &pnmimage);
+  bool convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
+                           CPTA_uchar image, size_t page_size, int z) const;
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
 
 
   void consider_rescale(PNMImage &pnmimage);
   void consider_rescale(PNMImage &pnmimage);
   void consider_downgrade(PNMImage &pnmimage, int num_channels);
   void consider_downgrade(PNMImage &pnmimage, int num_channels);
 
 
-  INLINE void store_unscaled_byte(int &index, int value);
-  INLINE void store_unscaled_short(int &index, int value);
-  INLINE void store_scaled_byte(int &index, int value, double scale);
-  INLINE void store_scaled_short(int &index, int value, double scale);
-  INLINE double get_unsigned_byte(int &index) const;
-  INLINE double get_unsigned_short(int &index) const;
+  INLINE static void store_unscaled_byte(unsigned char *&p, int value);
+  INLINE static void store_unscaled_short(unsigned char *&p, int value);
+  INLINE static void store_scaled_byte(unsigned char *&p, int value, double scale);
+  INLINE static void store_scaled_short(unsigned char *&p, int value, double scale);
+  INLINE static double get_unsigned_byte(const unsigned char *&p);
+  INLINE static double get_unsigned_short(const unsigned char *&p);
 
 
   INLINE static bool is_txo_filename(const Filename &fullpath);
   INLINE static bool is_txo_filename(const Filename &fullpath);
   bool read_txo_file(const Filename &fullpath);
   bool read_txo_file(const Filename &fullpath);
   bool write_txo_file(const Filename &fullpath) const;
   bool write_txo_file(const Filename &fullpath) const;
 
 
+  void filter_2d_mipmap_pages(RamImage &to, const RamImage &from,
+                              int x_size, int y_size);
+
+  void filter_3d_mipmap_level(RamImage &to, const RamImage &from,
+                              int x_size, int y_size, int z_size);
+
+  typedef void Filter2DComponent(unsigned char *&p, 
+                                 const unsigned char *&q,
+                                 size_t pixel_size, size_t row_size);
+
+  typedef void Filter3DComponent(unsigned char *&p, 
+                                 const unsigned char *&q,
+                                 size_t pixel_size, size_t row_size,
+                                 size_t page_size);
+
+  static void filter_2d_unsigned_byte(unsigned char *&p, 
+                                      const unsigned char *&q,
+                                      size_t pixel_size, size_t row_size);
+  static void filter_2d_unsigned_short(unsigned char *&p, 
+                                       const unsigned char *&q,
+                                       size_t pixel_size, size_t row_size);
+
+  static void filter_3d_unsigned_byte(unsigned char *&p, 
+                                      const unsigned char *&q,
+                                      size_t pixel_size, size_t row_size,
+                                      size_t page_size);
+  static void filter_3d_unsigned_short(unsigned char *&p, 
+                                       const unsigned char *&q,
+                                       size_t pixel_size, size_t row_size,
+                                       size_t page_size);
+
 protected:
 protected:
   Filename _filename;
   Filename _filename;
   Filename _alpha_filename;
   Filename _alpha_filename;
@@ -376,8 +456,11 @@ protected:
   Format _format;
   Format _format;
   ComponentType _component_type;
   ComponentType _component_type;
 
 
-  bool _loaded_from_disk;
+  bool _loaded_from_image;
   bool _loaded_from_txo;
   bool _loaded_from_txo;
+  bool _has_read_pages;
+  bool _has_read_mipmaps;
+  int _num_mipmap_levels_read;
 
 
   WrapMode _wrap_u;
   WrapMode _wrap_u;
   WrapMode _wrap_v;
   WrapMode _wrap_v;
@@ -407,9 +490,13 @@ protected:
   typedef pmap<PT(InternalName), PT(Texture)> RelatedTextures;
   typedef pmap<PT(InternalName), PT(Texture)> RelatedTextures;
   RelatedTextures _related_textures;
   RelatedTextures _related_textures;
 
 
-  PTA_uchar _ram_image;
   CompressionMode _ram_image_compression;
   CompressionMode _ram_image_compression;
-  size_t _ram_page_size;
+
+  // There is usually one RamImage for the mipmap level 0 (the base
+  // image).  There may or may not also be additional images for the
+  // additional mipmap levels.
+  typedef pvector<RamImage> RamImages;
+  RamImages _ram_images;
 
 
   UpdateSeq _modified;
   UpdateSeq _modified;
 
 

+ 34 - 9
panda/src/gobj/texturePool.I

@@ -51,10 +51,17 @@ verify_texture(const string &filename) {
 //               If a texture with the same filename was previously
 //               If a texture with the same filename was previously
 //               loaded, returns that one instead.  If the texture
 //               loaded, returns that one instead.  If the texture
 //               file cannot be found, returns NULL.
 //               file cannot be found, returns NULL.
+//
+//               If read_mipmaps is true, the filename should contain
+//               a hash mark ('#'), which will be filled in with the
+//               mipmap level number; and the texture will be defined
+//               with a series of images, one for each mipmap level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_texture(const string &filename, int primary_file_num_channels) {
-  return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels);
+load_texture(const string &filename, int primary_file_num_channels,
+	     bool read_mipmaps) {
+  return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels,
+					   read_mipmaps);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -65,13 +72,21 @@ load_texture(const string &filename, int primary_file_num_channels) {
 //               If a texture with the same filename was previously
 //               If a texture with the same filename was previously
 //               loaded, returns that one instead.  If the texture
 //               loaded, returns that one instead.  If the texture
 //               file cannot be found, returns NULL.
 //               file cannot be found, returns NULL.
+//
+//               If read_mipmaps is true, both filenames should
+//               contain a hash mark ('#'), which will be filled in
+//               with the mipmap level number; and the texture will be
+//               defined with a series of images, two for each mipmap
+//               level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
 load_texture(const string &filename, const string &alpha_filename,
 load_texture(const string &filename, const string &alpha_filename,
-             int primary_file_num_channels, int alpha_file_channel) {
+             int primary_file_num_channels, int alpha_file_channel,
+	     bool read_mipmaps) {
   return get_global_ptr()->ns_load_texture(filename, alpha_filename, 
   return get_global_ptr()->ns_load_texture(filename, alpha_filename, 
-                                    primary_file_num_channels,
-                                    alpha_file_channel);
+					   primary_file_num_channels,
+					   alpha_file_channel,
+					   read_mipmaps);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -82,10 +97,15 @@ load_texture(const string &filename, const string &alpha_filename,
 //               with index 0.  The filename should include a sequence
 //               with index 0.  The filename should include a sequence
 //               of one or more hash characters ("#") which will be
 //               of one or more hash characters ("#") which will be
 //               filled in with the index number of each level.
 //               filled in with the index number of each level.
+//
+//               If read_mipmaps is true, the filename should contain
+//               an additional hash mark.  The first hash mark will be
+//               filled in with the mipmap level number, and the
+//               second with the index number of each 3-d level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_3d_texture(const string &filename_pattern) {
-  return get_global_ptr()->ns_load_3d_texture(filename_pattern);
+load_3d_texture(const string &filename_pattern, bool read_mipmaps) {
+  return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -96,10 +116,15 @@ load_3d_texture(const string &filename_pattern) {
 //               filename should include a sequence of one or more
 //               filename should include a sequence of one or more
 //               hash characters ("#") which will be filled in with
 //               hash characters ("#") which will be filled in with
 //               the index number of each pagee.
 //               the index number of each pagee.
+//
+//               If read_mipmaps is true, the filename should contain
+//               an additional hash mark.  The first hash mark will be
+//               filled in with the mipmap level number, and the
+//               second with the face number, 0 through 5.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *TexturePool::
 INLINE Texture *TexturePool::
-load_cube_map(const string &filename_pattern) {
-  return get_global_ptr()->ns_load_cube_map(filename_pattern);
+load_cube_map(const string &filename_pattern, bool read_mipmaps) {
+  return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 14 - 10
panda/src/gobj/texturePool.cxx

@@ -206,7 +206,8 @@ ns_has_texture(const Filename &orig_filename) {
 //  Description: The nonstatic implementation of load_texture().
 //  Description: The nonstatic implementation of load_texture().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
-ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
+ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
+		bool read_mipmaps) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
 
 
   if (!_fake_texture_image.empty()) {
   if (!_fake_texture_image.empty()) {
@@ -227,7 +228,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) {
   gobj_cat.info()
   gobj_cat.info()
     << "Loading texture " << filename << "\n";
     << "Loading texture " << filename << "\n";
   PT(Texture) tex = make_texture(filename.get_extension());
   PT(Texture) tex = make_texture(filename.get_extension());
-  if (!tex->read(filename, 0, primary_file_num_channels)) {
+  if (!tex->read(filename, 0, primary_file_num_channels, false, read_mipmaps)) {
     // This texture was not found or could not be read.
     // This texture was not found or could not be read.
     report_texture_unreadable(filename);
     report_texture_unreadable(filename);
     return NULL;
     return NULL;
@@ -249,12 +250,14 @@ Texture *TexturePool::
 ns_load_texture(const Filename &orig_filename, 
 ns_load_texture(const Filename &orig_filename, 
                 const Filename &orig_alpha_filename,
                 const Filename &orig_alpha_filename,
                 int primary_file_num_channels,
                 int primary_file_num_channels,
-                int alpha_file_channel) {
+                int alpha_file_channel,
+		bool read_mipmaps) {
   Filename filename(orig_filename);
   Filename filename(orig_filename);
   Filename alpha_filename(orig_alpha_filename);
   Filename alpha_filename(orig_alpha_filename);
 
 
   if (!_fake_texture_image.empty()) {
   if (!_fake_texture_image.empty()) {
-    return ns_load_texture(_fake_texture_image, primary_file_num_channels);
+    return ns_load_texture(_fake_texture_image, primary_file_num_channels,
+			   read_mipmaps);
   }
   }
 
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
@@ -275,8 +278,8 @@ ns_load_texture(const Filename &orig_filename,
     << "Loading texture " << filename << " and alpha component "
     << "Loading texture " << filename << " and alpha component "
     << alpha_filename << endl;
     << alpha_filename << endl;
   PT(Texture) tex = make_texture(filename.get_extension());
   PT(Texture) tex = make_texture(filename.get_extension());
-  if (!tex->read(filename, alpha_filename, 0, primary_file_num_channels,
-                 alpha_file_channel)) {
+  if (!tex->read(filename, alpha_filename, primary_file_num_channels,
+                 alpha_file_channel, 0, 0, false, read_mipmaps)) {
     // This texture was not found or could not be read.
     // This texture was not found or could not be read.
     report_texture_unreadable(filename);
     report_texture_unreadable(filename);
     return NULL;
     return NULL;
@@ -296,7 +299,8 @@ ns_load_texture(const Filename &orig_filename,
 //  Description: The nonstatic implementation of load_3d_texture().
 //  Description: The nonstatic implementation of load_3d_texture().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
-ns_load_3d_texture(const Filename &filename_pattern) {
+ns_load_3d_texture(const Filename &filename_pattern,
+		   bool read_mipmaps) {
   Filename filename(filename_pattern);
   Filename filename(filename_pattern);
   filename.set_pattern(true);
   filename.set_pattern(true);
 
 
@@ -315,7 +319,7 @@ ns_load_3d_texture(const Filename &filename_pattern) {
     << "Loading 3-d texture " << filename << "\n";
     << "Loading 3-d texture " << filename << "\n";
   PT(Texture) tex = make_texture(filename.get_extension());
   PT(Texture) tex = make_texture(filename.get_extension());
   tex->setup_3d_texture();
   tex->setup_3d_texture();
-  if (!tex->read_pages(filename)) {
+  if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
     // This texture was not found or could not be read.
     // This texture was not found or could not be read.
     report_texture_unreadable(filename);
     report_texture_unreadable(filename);
     return NULL;
     return NULL;
@@ -334,7 +338,7 @@ ns_load_3d_texture(const Filename &filename_pattern) {
 //  Description: The nonstatic implementation of load_cube_map().
 //  Description: The nonstatic implementation of load_cube_map().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Texture *TexturePool::
 Texture *TexturePool::
-ns_load_cube_map(const Filename &filename_pattern) {
+ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
   Filename filename(filename_pattern);
   Filename filename(filename_pattern);
   filename.set_pattern(true);
   filename.set_pattern(true);
 
 
@@ -353,7 +357,7 @@ ns_load_cube_map(const Filename &filename_pattern) {
     << "Loading cube map texture " << filename << "\n";
     << "Loading cube map texture " << filename << "\n";
   PT(Texture) tex = make_texture(filename.get_extension());
   PT(Texture) tex = make_texture(filename.get_extension());
   tex->setup_cube_map();
   tex->setup_cube_map();
-  if (!tex->read_pages(filename)) {
+  if (!tex->read(filename, 0, 0, true, read_mipmaps)) {
     // This texture was not found or could not be read.
     // This texture was not found or could not be read.
     report_texture_unreadable(filename);
     report_texture_unreadable(filename);
     return NULL;
     return NULL;

+ 17 - 8
panda/src/gobj/texturePool.h

@@ -42,13 +42,17 @@ PUBLISHED:
   INLINE static bool has_texture(const string &filename);
   INLINE static bool has_texture(const string &filename);
   INLINE static bool verify_texture(const string &filename);
   INLINE static bool verify_texture(const string &filename);
   INLINE static Texture *load_texture(const string &filename, 
   INLINE static Texture *load_texture(const string &filename, 
-                                      int primary_file_num_channels = 0);
+                                      int primary_file_num_channels = 0,
+				      bool read_mipmaps = false);
   INLINE static Texture *load_texture(const string &filename,
   INLINE static Texture *load_texture(const string &filename,
                                       const string &alpha_filename, 
                                       const string &alpha_filename, 
                                       int primary_file_num_channels = 0,
                                       int primary_file_num_channels = 0,
-                                      int alpha_file_channel = 0);
-  INLINE static Texture *load_3d_texture(const string &filename_pattern);
-  INLINE static Texture *load_cube_map(const string &filename_pattern);
+                                      int alpha_file_channel = 0,
+				      bool read_mipmaps = false);
+  INLINE static Texture *load_3d_texture(const string &filename_pattern,
+					 bool read_mipmaps = false);
+  INLINE static Texture *load_cube_map(const string &filename_pattern,
+				       bool read_mipmaps = false);
 
 
   INLINE static Texture *get_normalization_cube_map(int size);
   INLINE static Texture *get_normalization_cube_map(int size);
 
 
@@ -81,13 +85,18 @@ private:
   TexturePool();
   TexturePool();
 
 
   bool ns_has_texture(const Filename &orig_filename);
   bool ns_has_texture(const Filename &orig_filename);
-  Texture *ns_load_texture(const Filename &orig_filename, int primary_file_num_channels);
+  Texture *ns_load_texture(const Filename &orig_filename, 
+			   int primary_file_num_channels,
+			   bool read_mipmaps);
   Texture *ns_load_texture(const Filename &orig_filename, 
   Texture *ns_load_texture(const Filename &orig_filename, 
                            const Filename &orig_alpha_filename, 
                            const Filename &orig_alpha_filename, 
                            int primary_file_num_channels,
                            int primary_file_num_channels,
-                           int alpha_file_channel);
-  Texture *ns_load_3d_texture(const Filename &filename_pattern);
-  Texture *ns_load_cube_map(const Filename &filename_pattern);
+                           int alpha_file_channel,
+			   bool read_mipmaps);
+  Texture *ns_load_3d_texture(const Filename &filename_pattern,
+			      bool read_mipmaps);
+  Texture *ns_load_cube_map(const Filename &filename_pattern,
+			    bool read_mipmaps);
   Texture *ns_get_normalization_cube_map(int size);
   Texture *ns_get_normalization_cube_map(int size);
 
 
   void ns_add_texture(Texture *texture);
   void ns_add_texture(Texture *texture);

+ 4 - 7
panda/src/gobj/textureStage.I

@@ -263,13 +263,10 @@ get_alpha_scale() const {
 //     Function: TextureStage::set_saved_result
 //     Function: TextureStage::set_saved_result
 //       Access: Published
 //       Access: Published
 //  Description: Sets the saved_result flag.  When this is true, the
 //  Description: Sets the saved_result flag.  When this is true, the
-//               output of this stage is not part of the normal
-//               pipeline--that is, it will not be supplied as the
-//               "previous" source for the next texture stage--but it
-//               will instead be supplied as the "last_saved_result"
-//               source for any future stages, until the next
-//               TextureStage with a saved_result set true is
-//               encountered.
+//               output of this stage will be supplied as the
+//               "last_saved_result" source for any future stages,
+//               until the next TextureStage with a saved_result set
+//               true is encountered.
 //
 //
 //               This can be used to reuse the results of this texture
 //               This can be used to reuse the results of this texture
 //               stage as input to more than one stage later in the
 //               stage as input to more than one stage later in the

+ 2 - 2
panda/src/gobj/videoTexture.cxx

@@ -72,7 +72,7 @@ has_ram_image() const {
   if (this_frame != _last_frame_update) {
   if (this_frame != _last_frame_update) {
     return false;
     return false;
   }
   }
-  return !_ram_image.empty();
+  return !_ram_images.empty() && !_ram_images[0]._image.empty();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -85,7 +85,7 @@ has_ram_image() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool VideoTexture::
 bool VideoTexture::
 get_keep_ram_image() const {
 get_keep_ram_image() const {
-  // An VideoTexture should never dump its RAM image.
+  // A VideoTexture should never dump its RAM image.
   return true;
   return true;
 }
 }
 
 

+ 96 - 128
panda/src/grutil/openCVTexture.cxx

@@ -103,136 +103,12 @@ from_camera(int camera_index, int z) {
     return false;
     return false;
   }
   }
 
 
-  set_loaded_from_disk();
+  set_loaded_from_image();
   clear_current_frame();
   clear_current_frame();
 
 
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::read
-//       Access: Published, Virtual
-//  Description: Takes the video image from the indicated filename.
-//               If the filename is not a video file, attempts to read
-//               it as a still image instead.
-////////////////////////////////////////////////////////////////////
-bool OpenCVTexture::
-read(const Filename &fullpath, int z, int) {
-  if (!reconsider_z_size(z)) {
-    return false;
-  }
-  nassertr(z >= 0 && z < get_z_size(), false);
-
-  VideoPage &page = modify_page(z);
-  page._alpha.clear();
-  if (!page._color.read(fullpath)) {
-    grutil_cat.error()
-      << "OpenCV couldn't read " << fullpath << " as video.\n";
-    return false;
-  }
-
-  if (!has_name()) {
-    set_name(fullpath.get_basename_wo_extension());
-  }
-  if (!has_filename()) {
-    set_filename(fullpath);
-    clear_alpha_filename();
-  }
-
-  set_fullpath(fullpath);
-  clear_alpha_fullpath();
-
-  _primary_file_num_channels = 3;
-  _alpha_file_channel = 0;
-
-  if (!reconsider_video_properties(page._color, 3, z)) {
-    page._color.clear();
-    return false;
-  }
-
-  set_loaded_from_disk();
-  clear_current_frame();
-  
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::read
-//       Access: Published, Virtual
-//  Description: Combines a color and alpha video image from the two
-//               indicated filenames.  Both must be the same kind of
-//               video with similar properties.
-////////////////////////////////////////////////////////////////////
-bool OpenCVTexture::
-read(const Filename &fullpath, const Filename &alpha_fullpath,
-     int z, int, int alpha_file_channel) {
-  if (!reconsider_z_size(z)) {
-    return false;
-  }
-  nassertr(z >= 0 && z < get_z_size(), false);
-
-  VideoPage &page = modify_page(z);
-  if (!page._color.read(fullpath)) {
-    grutil_cat.error()
-      << "OpenCV couldn't read " << fullpath << " as video.\n";
-    return false;
-  }
-  if (!page._alpha.read(alpha_fullpath)) {
-    grutil_cat.error()
-      << "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
-    page._color.clear();
-    return false;
-  }
-
-  if (!has_name()) {
-    set_name(fullpath.get_basename_wo_extension());
-  }
-  if (!has_filename()) {
-    set_filename(fullpath);
-    set_alpha_filename(alpha_fullpath);
-  }
-
-  set_fullpath(fullpath);
-  set_alpha_fullpath(alpha_fullpath);
-
-  _primary_file_num_channels = 3;
-  _alpha_file_channel = alpha_file_channel;
-
-  if (!reconsider_video_properties(page._color, 4, z)) {
-    page._color.clear();
-    page._alpha.clear();
-    return false;
-  }
-
-  if (!reconsider_video_properties(page._alpha, 4, z)) {
-    page._color.clear();
-    page._alpha.clear();
-    return false;
-  }
-
-  set_loaded_from_disk();
-  clear_current_frame();
-  
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: OpenCVTexture::load
-//       Access: Published, Virtual
-//  Description: Resets the texture (or the particular level of the
-//               texture) to the indicated static image.
-////////////////////////////////////////////////////////////////////
-bool OpenCVTexture::
-load(const PNMImage &pnmimage, int z) {
-  if (z <= (int)_pages.size()) {
-    VideoPage &page = modify_page(z);
-    page._color.clear();
-    page._alpha.clear();
-  }
-
-  return Texture::load(pnmimage, z);
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: OpenCVTexture::modify_page
 //     Function: OpenCVTexture::modify_page
 //       Access: Private
 //       Access: Private
@@ -295,7 +171,7 @@ reconsider_video_properties(const OpenCVTexture::VideoStream &stream,
     return false;
     return false;
   }
   }
 
 
-  if (_loaded_from_disk && 
+  if (_loaded_from_image && 
       (get_video_width() != width || get_video_height() != height ||
       (get_video_width() != width || get_video_height() != height ||
        get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
        get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
     grutil_cat.error()
     grutil_cat.error()
@@ -334,6 +210,7 @@ make_texture() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void OpenCVTexture::
 void OpenCVTexture::
 update_frame(int frame) {
 update_frame(int frame) {
+  nassertv(has_ram_image());
   int max_z = max(_z_size, (int)_pages.size());
   int max_z = max(_z_size, (int)_pages.size());
   for (int z = 0; z < max_z; ++z) {
   for (int z = 0; z < max_z; ++z) {
     VideoPage &page = _pages[z];
     VideoPage &page = _pages[z];
@@ -346,7 +223,7 @@ update_frame(int frame) {
       const unsigned char *source = page._color.get_frame_data(frame);
       const unsigned char *source = page._color.get_frame_data(frame);
       if (source != NULL) {
       if (source != NULL) {
         nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
         nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-        unsigned char *dest = _ram_image.p() + get_expected_ram_page_size() * z;
+        unsigned char *dest = _ram_images[0]._image.p() + get_expected_ram_page_size() * z;
 
 
         int dest_row_width = (_x_size * _num_components * _component_width);
         int dest_row_width = (_x_size * _num_components * _component_width);
         int source_row_width = get_video_width() * 3;
         int source_row_width = get_video_width() * 3;
@@ -385,7 +262,7 @@ update_frame(int frame) {
       const unsigned char *source = page._alpha.get_frame_data(frame);
       const unsigned char *source = page._alpha.get_frame_data(frame);
       if (source != NULL) {
       if (source != NULL) {
         nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
         nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
-        unsigned char *dest = _ram_image.p() + get_expected_ram_page_size() * z;
+        unsigned char *dest = _ram_images[0]._image.p() + get_expected_ram_page_size() * z;
 
 
         int dest_row_width = (_x_size * _num_components * _component_width);
         int dest_row_width = (_x_size * _num_components * _component_width);
         int source_row_width = get_video_width() * 3;
         int source_row_width = get_video_width() * 3;
@@ -409,6 +286,97 @@ update_frame(int frame) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::do_read_one
+//       Access: Protected, Virtual
+//  Description: Combines a color and alpha video image from the two
+//               indicated filenames.  Both must be the same kind of
+//               video with similar properties.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+	    int z, int n, int primary_file_num_channels, int alpha_file_channel) {
+  nassertr(n == 0, false);
+  nassertr(z >= 0 && z < get_z_size(), false);
+
+  VideoPage &page = modify_page(z);
+  if (!page._color.read(fullpath)) {
+    grutil_cat.error()
+      << "OpenCV couldn't read " << fullpath << " as video.\n";
+    return false;
+  }
+  if (!alpha_fullpath.empty()) {
+    if (!page._alpha.read(alpha_fullpath)) {
+      grutil_cat.error()
+	<< "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
+      page._color.clear();
+      return false;
+    }
+  }
+
+  if (z == 0) {
+    if (!has_name()) {
+      set_name(fullpath.get_basename_wo_extension());
+    }
+    if (!has_filename()) {
+      set_filename(fullpath);
+      set_alpha_filename(alpha_fullpath);
+    }
+
+    set_fullpath(fullpath);
+    set_alpha_fullpath(alpha_fullpath);
+  }
+
+  _primary_file_num_channels = 3;
+  _alpha_file_channel = 0;
+
+  if (alpha_fullpath.empty()) {
+    // Only one RGB movie.
+    if (!reconsider_video_properties(page._color, 3, z)) {
+      page._color.clear();
+      return false;
+    }
+
+  } else {
+    // An RGB movie combined with an alpha movie.
+    _alpha_file_channel = alpha_file_channel;
+
+    if (!reconsider_video_properties(page._color, 4, z)) {
+      page._color.clear();
+      page._alpha.clear();
+      return false;
+    }
+    
+    if (!reconsider_video_properties(page._alpha, 4, z)) {
+      page._color.clear();
+      page._alpha.clear();
+      return false;
+    }
+  }
+
+  set_loaded_from_image();
+  clear_current_frame();
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OpenCVTexture::do_load_one
+//       Access: Protected, Virtual
+//  Description: Resets the texture (or the particular level of the
+//               texture) to the indicated static image.
+////////////////////////////////////////////////////////////////////
+bool OpenCVTexture::
+do_load_one(const PNMImage &pnmimage, int z, int n) {
+  if (z <= (int)_pages.size()) {
+    VideoPage &page = modify_page(z);
+    page._color.clear();
+    page._alpha.clear();
+  }
+
+  return Texture::do_load_one(pnmimage, z, n);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: OpenCVTexture::register_with_read_factory
 //     Function: OpenCVTexture::register_with_read_factory
 //       Access: Public, Static
 //       Access: Public, Static

+ 5 - 7
panda/src/grutil/openCVTexture.h

@@ -47,19 +47,17 @@ PUBLISHED:
 
 
   bool from_camera(int camera_index = -1, int z = 0);
   bool from_camera(int camera_index = -1, int z = 0);
 
 
-  virtual bool read(const Filename &fullpath, int z = 0,
-                    int primary_file_num_channels = 0);
-  virtual bool read(const Filename &fullpath, const Filename &alpha_fullpath, 
-                    int z = 0,
-                    int primary_file_num_channels = 0, int alpha_file_channel = 0);
-  virtual bool load(const PNMImage &pnmimage, int z = 0);
-
 public:
 public:
   static PT(Texture) make_texture();
   static PT(Texture) make_texture();
 
 
 protected:
 protected:
   virtual void update_frame(int frame);
   virtual void update_frame(int frame);
 
 
+  virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
+			   int z, int n, int primary_file_num_channels, int alpha_file_channel);
+
+  virtual bool do_load_one(const PNMImage &pnmimage, int z, int n);
+
 private:    
 private:    
   class VideoPage;
   class VideoPage;
   class VideoStream;
   class VideoStream;

+ 2 - 1
panda/src/putil/bam.h

@@ -36,9 +36,10 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
 
-static const unsigned short _bam_minor_ver = 2;
+static const unsigned short _bam_minor_ver = 3;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
+// Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
 
 
 
 
 #endif
 #endif

+ 21 - 1
pandatool/src/bam/eggToBam.cxx

@@ -118,7 +118,7 @@ EggToBam() :
      "stored uncompressed.  A particular texture that is encoded into "
      "stored uncompressed.  A particular texture that is encoded into "
      "multiple different bam files in this way cannot be unified into "
      "multiple different bam files in this way cannot be unified into "
      "the same part of texture memory if the different bam files are loaded "
      "the same part of texture memory if the different bam files are loaded "
-     "together.  All that being said, this can sometimes be a convenient "
+     "together.  That being said, this can sometimes be a convenient "
      "way to ensure the bam file is completely self-contained.",
      "way to ensure the bam file is completely self-contained.",
      &EggToBam::dispatch_none, &_tex_rawdata);
      &EggToBam::dispatch_none, &_tex_rawdata);
 
 
@@ -162,6 +162,16 @@ EggToBam() :
      "on the particular graphics card that was used to generate them.",
      "on the particular graphics card that was used to generate them.",
      &EggToBam::dispatch_none, &_tex_ctex);
      &EggToBam::dispatch_none, &_tex_ctex);
 
 
+  add_option
+    ("mipmap", "", 0,
+     "Records the pre-generated mipmap levels in the texture object file "
+     "when using -rawtex or -txo, for textures that use mipmapping.  This "
+     "will increase the size of the texture object file by about 33%, but "
+     "it prevents the need to compute the mipmaps at runtime.  The default "
+     "is to record mipmap levels only when the texture was specifically "
+     "loaded with them.",
+     &EggToBam::dispatch_none, &_tex_mipmap);
+
   add_option
   add_option
     ("load-display", "display name", 0,
     ("load-display", "display name", 0,
      "Specifies the particular display module to load to perform the texture "
      "Specifies the particular display module to load to perform the texture "
@@ -241,10 +251,20 @@ run() {
       if (_tex_ctex) {
       if (_tex_ctex) {
         tex->set_keep_ram_image(true);
         tex->set_keep_ram_image(true);
         tex->set_compression(Texture::CM_on);
         tex->set_compression(Texture::CM_on);
+	bool has_mipmap_levels = (tex->get_num_ram_mipmap_images() > 1);
         if (!_engine->extract_texture_data(tex, _gsg)) {
         if (!_engine->extract_texture_data(tex, _gsg)) {
           nout << "  couldn't compress " << tex->get_name() << "\n";
           nout << "  couldn't compress " << tex->get_name() << "\n";
         }
         }
+	if (!has_mipmap_levels && !_tex_mipmap) {
+	  // Make sure we didn't accidentally introduce mipmap levels
+	  // by rendezvousing through the graphics card.
+	  tex->clear_ram_mipmap_images();
+	}
+      } else if (_tex_mipmap && tex->uses_mipmaps()) {
+	// Generate mipmap levels.
+	tex->generate_ram_mipmap_images();
       }
       }
+
       if (_tex_txo || _tex_txopz) {
       if (_tex_txo || _tex_txopz) {
         convert_txo(tex);
         convert_txo(tex);
       }
       }

+ 1 - 0
pandatool/src/bam/eggToBam.h

@@ -69,6 +69,7 @@ private:
   bool _tex_txo;
   bool _tex_txo;
   bool _tex_txopz;
   bool _tex_txopz;
   bool _tex_ctex;
   bool _tex_ctex;
+  bool _tex_mipmap;
   string _load_display;
   string _load_display;
 
 
   // The rest of this is required to support -ctex.
   // The rest of this is required to support -ctex.

Vissa filer visades inte eftersom för många filer har ändrats