diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 6a71f3f9c6..beb1d040a7 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -192,7 +192,8 @@ class Loader: return font # texture loading funcs - def loadTexture(self, texturePath, alphaPath = None): + def loadTexture(self, texturePath, alphaPath = None, + readMipmaps = False): """ texturePath is a string. @@ -203,15 +204,15 @@ class Loader: assert Loader.notify.debug("Loading texture: %s" % (texturePath)) if phaseChecker: phaseChecker(texturePath) - texture = TexturePool.loadTexture(texturePath) + texture = TexturePool.loadTexture(texturePath, 0, readMipmaps) else: assert Loader.notify.debug("Loading texture: %s %s" % (texturePath, alphaPath)) if phaseChecker: phaseChecker(texturePath) - texture = TexturePool.loadTexture(texturePath, alphaPath) + texture = TexturePool.loadTexture(texturePath, alphaPath, 0, 0, readMipmaps) return texture - def load3DTexture(self, texturePattern): + def load3DTexture(self, texturePattern, readMipmaps = False): """ texturePattern is a string that contains a sequence of one or 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)) if phaseChecker: phaseChecker(texturePattern) - texture = TexturePool.load3dTexture(texturePattern) + texture = TexturePool.load3dTexture(texturePattern, readMipmaps) return texture - def loadCubeMap(self, texturePattern): + def loadCubeMap(self, texturePattern, readMipmaps = False): """ texturePattern is a string that contains a sequence of one or 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)) if phaseChecker: phaseChecker(texturePattern) - texture = TexturePool.loadCubeMap(texturePattern) + texture = TexturePool.loadCubeMap(texturePattern, readMipmaps) return texture def unloadTexture(self, texture): diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 1b5eea5695..3f467be9f9 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/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 traditionally support alpha channels. + 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. + format { format-definition } 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 channel(s). + 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. + minfilter { filter-type } magfilter { filter-type } magfilteralpha { filter-type } @@ -327,6 +353,12 @@ appear before they are referenced. combine-alpha-source2 { constant } combine-alpha-operand2 { src-alpha } + 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. + tex-gen { mode } This specifies that texture coordinates for the primitives that diff --git a/panda/src/egg/eggTexture.I b/panda/src/egg/eggTexture.I index f6ffe53ade..fb676af707 100644 --- a/panda/src/egg/eggTexture.I +++ b/panda/src/egg/eggTexture.I @@ -929,6 +929,39 @@ get_alpha_file_channel() const { 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 // Access: Published diff --git a/panda/src/egg/eggTexture.cxx b/panda/src/egg/eggTexture.cxx index 02f3032c59..0e5bf1ee21 100644 --- a/panda/src/egg/eggTexture.cxx +++ b/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); _flags = 0; _alpha_file_channel = 0; + _read_mipmaps = false; _multitexture_sort = 0; } @@ -103,6 +104,7 @@ operator = (const EggTexture ©) { _alpha_filename = copy._alpha_filename; _alpha_fullpath = copy._alpha_fullpath; _alpha_file_channel = copy._alpha_file_channel; + _read_mipmaps = copy._read_mipmaps; _multitexture_sort = 0; _combiner[0] = copy._combiner[0]; _combiner[1] = copy._combiner[1]; @@ -144,6 +146,11 @@ write(ostream &out, int indent_level) const { << get_alpha_file_channel() << " }\n"; } + if (get_read_mipmaps()) { + indent(out, indent_level + 2) + << " read-mipmaps { 1 }\n"; + } + if (get_texture_type() != TT_unspecified) { indent(out, indent_level + 2) << " texture_type { " << get_texture_type() << " }\n"; diff --git a/panda/src/egg/eggTexture.h b/panda/src/egg/eggTexture.h index f9d4db9ebe..49ca071e06 100644 --- a/panda/src/egg/eggTexture.h +++ b/panda/src/egg/eggTexture.h @@ -254,6 +254,10 @@ PUBLISHED: INLINE bool has_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(); bool multitexture_over(EggTexture *other); INLINE int get_multitexture_sort() const; @@ -312,6 +316,7 @@ private: Filename _alpha_filename; Filename _alpha_fullpath; int _alpha_file_channel; + bool _read_mipmaps; int _multitexture_sort; class SourceAndOperand { diff --git a/panda/src/egg/lexer.cxx.prebuilt b/panda/src/egg/lexer.cxx.prebuilt index eb45c5bad2..f580e8bbd5 100644 --- a/panda/src/egg/lexer.cxx.prebuilt +++ b/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 - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include - -/* 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 -#include -#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 -#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 = ∈ - 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 -#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 +#include + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#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 +#include +#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 +#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 = ∈ + 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 +#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" diff --git a/panda/src/egg/parser.cxx.prebuilt b/panda/src/egg/parser.cxx.prebuilt index cd5993933e..b55133f753 100644 --- a/panda/src/egg/parser.cxx.prebuilt +++ b/panda/src/egg/parser.cxx.prebuilt @@ -729,30 +729,30 @@ static const unsigned short int yyrline[] = 0, 216, 216, 217, 218, 219, 230, 231, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 274, 297, 312, 311, 339, - 340, 661, 673, 672, 699, 700, 795, 802, 823, 822, - 862, 863, 875, 874, 886, 885, 931, 935, 939, 943, - 948, 947, 962, 963, 964, 972, 991, 995, 999, 1007, - 1015, 1023, 1031, 1039, 1057, 1061, 1069, 1087, 1091, 1099, - 1118, 1117, 1138, 1137, 1159, 1158, 1179, 1180, 1310, 1322, - 1327, 1334, 1340, 1353, 1360, 1373, 1379, 1385, 1391, 1396, - 1402, 1403, 1404, 1405, 1419, 1449, 1450, 1473, 1472, 1488, - 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, - 1499, 1500, 1504, 1511, 1518, 1525, 1532, 1539, 1546, 1553, - 1560, 1567, 1574, 1578, 1579, 1591, 1595, 1596, 1618, 1651, - 1655, 1680, 1692, 1697, 1715, 1714, 1734, 1733, 1753, 1752, - 1772, 1771, 1791, 1790, 1810, 1809, 1829, 1828, 1848, 1849, - 1850, 1861, 1863, 1862, 1883, 1884, 1885, 1886, 1887, 1888, - 1889, 1890, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, - 1971, 1972, 1973, 1974, 1980, 1981, 2045, 2046, 2047, 2048, - 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2124, 2141, 2181, - 2198, 2202, 2210, 2228, 2232, 2240, 2258, 2274, 2305, 2323, - 2343, 2363, 2368, 2379, 2385, 2404, 2420, 2442, 2441, 2464, - 2463, 2485, 2486, 2490, 2494, 2498, 2502, 2518, 2517, 2538, - 2539, 2551, 2566, 2565, 2586, 2587, 2604, 2619, 2618, 2639, - 2640, 2655, 2670, 2674, 2688, 2692, 2706, 2727, 2748, 2774, - 2779, 2791, 2803, 2808, 2819, 2823, 2837, 2841, 2845, 2858, - 2862, 2878, 2882, 2896, 2897, 2912, 2918, 2924, 2941, 2949, - 2955 + 340, 664, 676, 675, 702, 703, 798, 805, 826, 825, + 865, 866, 878, 877, 889, 888, 934, 938, 942, 946, + 951, 950, 965, 966, 967, 975, 994, 998, 1002, 1010, + 1018, 1026, 1034, 1042, 1060, 1064, 1072, 1090, 1094, 1102, + 1121, 1120, 1141, 1140, 1162, 1161, 1182, 1183, 1313, 1325, + 1330, 1337, 1343, 1356, 1363, 1376, 1382, 1388, 1394, 1399, + 1405, 1406, 1407, 1408, 1422, 1452, 1453, 1476, 1475, 1491, + 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, + 1502, 1503, 1507, 1514, 1521, 1528, 1535, 1542, 1549, 1556, + 1563, 1570, 1577, 1581, 1582, 1594, 1598, 1599, 1621, 1654, + 1658, 1683, 1695, 1700, 1718, 1717, 1737, 1736, 1756, 1755, + 1775, 1774, 1794, 1793, 1813, 1812, 1832, 1831, 1851, 1852, + 1853, 1864, 1866, 1865, 1886, 1887, 1888, 1889, 1890, 1891, + 1892, 1893, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, + 1974, 1975, 1976, 1977, 1983, 1984, 2048, 2049, 2050, 2051, + 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2127, 2144, 2184, + 2201, 2205, 2213, 2231, 2235, 2243, 2261, 2277, 2308, 2326, + 2346, 2366, 2371, 2382, 2388, 2407, 2423, 2445, 2444, 2467, + 2466, 2488, 2489, 2493, 2497, 2501, 2505, 2521, 2520, 2541, + 2542, 2554, 2569, 2568, 2589, 2590, 2607, 2622, 2621, 2642, + 2643, 2658, 2673, 2677, 2691, 2695, 2709, 2730, 2751, 2777, + 2782, 2794, 2806, 2811, 2822, 2826, 2840, 2844, 2848, 2861, + 2865, 2881, 2885, 2899, 2900, 2915, 2921, 2927, 2944, 2952, + 2958 }; #endif @@ -2454,6 +2454,9 @@ yyreduce: } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) { texture->set_alpha_file_channel((int)value); + } else if (cmp_nocase_uh(name, "read_mipmaps") == 0) { + texture->set_read_mipmaps(((int)value) != 0); + } else { eggyywarning("Unsupported texture scalar: " + name); } @@ -2461,7 +2464,7 @@ yyreduce: break; case 32: -#line 673 "parser.yxx" +#line 676 "parser.yxx" { string mref_name = (yyvsp[-1]._string); EggMaterial *material = new EggMaterial(mref_name); @@ -2476,7 +2479,7 @@ yyreduce: break; case 33: -#line 685 "parser.yxx" +#line 688 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -2484,7 +2487,7 @@ yyreduce: break; case 35: -#line 701 "parser.yxx" +#line 704 "parser.yxx" { EggMaterial *material = DCAST(EggMaterial, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -2571,7 +2574,7 @@ yyreduce: break; case 36: -#line 796 "parser.yxx" +#line 799 "parser.yxx" { string node_name = (yyvsp[-3]._string); Filename filename = (yyvsp[-1]._string); @@ -2581,7 +2584,7 @@ yyreduce: break; case 37: -#line 803 "parser.yxx" +#line 806 "parser.yxx" { if (cmp_nocase_uh((yyvsp[-5]._string), "group") != 0) { eggyyerror("keyword 'group' expected"); @@ -2594,7 +2597,7 @@ yyreduce: break; case 38: -#line 823 "parser.yxx" +#line 826 "parser.yxx" { string name = (yyvsp[0]._string); EggVertexPool *pool = NULL; @@ -2621,7 +2624,7 @@ yyreduce: break; case 39: -#line 847 "parser.yxx" +#line 850 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -2629,14 +2632,14 @@ yyreduce: break; case 42: -#line 875 "parser.yxx" +#line 878 "parser.yxx" { egg_stack.push_back(new EggVertex); } break; case 43: -#line 879 "parser.yxx" +#line 882 "parser.yxx" { PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back()); egg_stack.pop_back(); @@ -2646,7 +2649,7 @@ yyreduce: break; case 44: -#line 886 "parser.yxx" +#line 889 "parser.yxx" { vertex_index = (int)(yyvsp[0]._number); EggVertexPool *pool = DCAST(EggVertexPool, egg_stack.back()); @@ -2674,7 +2677,7 @@ yyreduce: break; case 45: -#line 911 "parser.yxx" +#line 914 "parser.yxx" { PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back()); egg_stack.pop_back(); @@ -2687,35 +2690,35 @@ yyreduce: break; case 46: -#line 932 "parser.yxx" +#line 935 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_pos((yyvsp[0]._number)); } break; case 47: -#line 936 "parser.yxx" +#line 939 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_pos(LPoint2d((yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 48: -#line 940 "parser.yxx" +#line 943 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_pos(LPoint3d((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 49: -#line 944 "parser.yxx" +#line 947 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_pos(LPoint4d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 50: -#line 948 "parser.yxx" +#line 951 "parser.yxx" { EggVertex *vertex = DCAST(EggVertex, egg_stack.back()); EggVertexUV *uv = new EggVertexUV((yyvsp[-1]._string), TexCoordd::zero()); @@ -2729,14 +2732,14 @@ yyreduce: break; case 51: -#line 959 "parser.yxx" +#line 962 "parser.yxx" { egg_stack.pop_back(); } break; case 54: -#line 965 "parser.yxx" +#line 968 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs. insert(EggMorphVertex((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2747,7 +2750,7 @@ yyreduce: break; case 55: -#line 973 "parser.yxx" +#line 976 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs. insert(EggMorphVertex((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2758,21 +2761,21 @@ yyreduce: break; case 56: -#line 992 "parser.yxx" +#line 995 "parser.yxx" { DCAST(EggVertexUV, egg_stack.back())->set_uv(TexCoordd((yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 57: -#line 996 "parser.yxx" +#line 999 "parser.yxx" { DCAST(EggVertexUV, egg_stack.back())->set_uvw(LVecBase3d((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 58: -#line 1000 "parser.yxx" +#line 1003 "parser.yxx" { if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) { eggyywarning("Ignoring repeated tangent"); @@ -2783,7 +2786,7 @@ yyreduce: break; case 59: -#line 1008 "parser.yxx" +#line 1011 "parser.yxx" { if (DCAST(EggVertexUV, egg_stack.back())->has_binormal()) { eggyywarning("Ignoring repeated binormal"); @@ -2794,7 +2797,7 @@ yyreduce: break; case 60: -#line 1016 "parser.yxx" +#line 1019 "parser.yxx" { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. insert(EggMorphTexCoord((yyvsp[-4]._string), LVector3d((yyvsp[-2]._number), (yyvsp[-1]._number), 0.0))).second; @@ -2805,7 +2808,7 @@ yyreduce: break; case 61: -#line 1024 "parser.yxx" +#line 1027 "parser.yxx" { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. insert(EggMorphTexCoord((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2816,7 +2819,7 @@ yyreduce: break; case 62: -#line 1032 "parser.yxx" +#line 1035 "parser.yxx" { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. insert(EggMorphTexCoord((yyvsp[-3]._string), LVector3d((yyvsp[-2]._number), (yyvsp[-1]._number), 0.0))).second; @@ -2827,7 +2830,7 @@ yyreduce: break; case 63: -#line 1040 "parser.yxx" +#line 1043 "parser.yxx" { bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs. insert(EggMorphTexCoord((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2838,14 +2841,14 @@ yyreduce: break; case 64: -#line 1058 "parser.yxx" +#line 1061 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_normal(Normald((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 65: -#line 1062 "parser.yxx" +#line 1065 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals. insert(EggMorphNormal((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2856,7 +2859,7 @@ yyreduce: break; case 66: -#line 1070 "parser.yxx" +#line 1073 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals. insert(EggMorphNormal((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2867,14 +2870,14 @@ yyreduce: break; case 67: -#line 1088 "parser.yxx" +#line 1091 "parser.yxx" { DCAST(EggVertex, egg_stack.back())->set_color(Colorf((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 68: -#line 1092 "parser.yxx" +#line 1095 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas. insert(EggMorphColor((yyvsp[-6]._string), LVector4f((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2885,7 +2888,7 @@ yyreduce: break; case 69: -#line 1100 "parser.yxx" +#line 1103 "parser.yxx" { bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas. insert(EggMorphColor((yyvsp[-5]._string), LVector4f((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -2896,7 +2899,7 @@ yyreduce: break; case 70: -#line 1118 "parser.yxx" +#line 1121 "parser.yxx" { EggGroup *group = new EggGroup((yyvsp[0]._string)); egg_stack.push_back(group); @@ -2904,7 +2907,7 @@ yyreduce: break; case 71: -#line 1123 "parser.yxx" +#line 1126 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -2912,7 +2915,7 @@ yyreduce: break; case 72: -#line 1138 "parser.yxx" +#line 1141 "parser.yxx" { EggGroup *group = new EggGroup((yyvsp[0]._string)); group->set_group_type(EggGroup::GT_joint); @@ -2921,7 +2924,7 @@ yyreduce: break; case 73: -#line 1144 "parser.yxx" +#line 1147 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -2929,7 +2932,7 @@ yyreduce: break; case 74: -#line 1159 "parser.yxx" +#line 1162 "parser.yxx" { EggGroup *group = new EggGroup((yyvsp[0]._string)); group->set_group_type(EggGroup::GT_instance); @@ -2938,7 +2941,7 @@ yyreduce: break; case 75: -#line 1165 "parser.yxx" +#line 1168 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -2946,7 +2949,7 @@ yyreduce: break; case 77: -#line 1181 "parser.yxx" +#line 1184 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -3079,7 +3082,7 @@ yyreduce: break; case 78: -#line 1311 "parser.yxx" +#line 1314 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string strval = (yyvsp[-1]._string); @@ -3094,7 +3097,7 @@ yyreduce: break; case 79: -#line 1323 "parser.yxx" +#line 1326 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); group->set_billboard_center(LPoint3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); @@ -3102,7 +3105,7 @@ yyreduce: break; case 80: -#line 1328 "parser.yxx" +#line 1331 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string name = (yyvsp[-4]._string); @@ -3112,7 +3115,7 @@ yyreduce: break; case 81: -#line 1335 "parser.yxx" +#line 1338 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); int value = (int)(yyvsp[-1]._number); @@ -3121,7 +3124,7 @@ yyreduce: break; case 82: -#line 1341 "parser.yxx" +#line 1344 "parser.yxx" { // The special flavor of DCS, with { sync } or { nosync }. EggGroup *group = DCAST(EggGroup, egg_stack.back()); @@ -3137,7 +3140,7 @@ yyreduce: break; case 83: -#line 1354 "parser.yxx" +#line 1357 "parser.yxx" { // The traditional flavor of DART, with { 0 } or { 1 }. EggGroup *group = DCAST(EggGroup, egg_stack.back()); @@ -3147,7 +3150,7 @@ yyreduce: break; case 84: -#line 1361 "parser.yxx" +#line 1364 "parser.yxx" { // The special flavor of DART, with { sync } or { nosync }. EggGroup *group = DCAST(EggGroup, egg_stack.back()); @@ -3163,7 +3166,7 @@ yyreduce: break; case 85: -#line 1374 "parser.yxx" +#line 1377 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); int value = (int)(yyvsp[-1]._number); @@ -3172,7 +3175,7 @@ yyreduce: break; case 86: -#line 1380 "parser.yxx" +#line 1383 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string type = (yyvsp[-1]._string); @@ -3181,7 +3184,7 @@ yyreduce: break; case 87: -#line 1386 "parser.yxx" +#line 1389 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); int value = (int)(yyvsp[-1]._number); @@ -3190,7 +3193,7 @@ yyreduce: break; case 88: -#line 1392 "parser.yxx" +#line 1395 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); group->set_tag((yyvsp[-3]._string), (yyvsp[-1]._string)); @@ -3198,7 +3201,7 @@ yyreduce: break; case 89: -#line 1397 "parser.yxx" +#line 1400 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); int value = (int)(yyvsp[-1]._number); @@ -3207,14 +3210,14 @@ yyreduce: break; case 93: -#line 1406 "parser.yxx" +#line 1409 "parser.yxx" { DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 94: -#line 1420 "parser.yxx" +#line 1423 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string strval = (yyvsp[0]._string); @@ -3237,7 +3240,7 @@ yyreduce: break; case 96: -#line 1451 "parser.yxx" +#line 1454 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); string strval = (yyvsp[0]._string); @@ -3252,84 +3255,84 @@ yyreduce: break; case 97: -#line 1473 "parser.yxx" +#line 1476 "parser.yxx" { egg_stack.back()->as_transform()->clear_transform(); } break; case 112: -#line 1505 "parser.yxx" +#line 1508 "parser.yxx" { egg_stack.back()->as_transform()->add_translate2d(LVector2d((yyvsp[-2]._number), (yyvsp[-1]._number))); } break; case 113: -#line 1512 "parser.yxx" +#line 1515 "parser.yxx" { egg_stack.back()->as_transform()->add_translate3d(LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } break; case 114: -#line 1519 "parser.yxx" +#line 1522 "parser.yxx" { egg_stack.back()->as_transform()->add_rotate2d((yyvsp[-1]._number)); } break; case 115: -#line 1526 "parser.yxx" +#line 1529 "parser.yxx" { egg_stack.back()->as_transform()->add_rotx((yyvsp[-1]._number)); } break; case 116: -#line 1533 "parser.yxx" +#line 1536 "parser.yxx" { egg_stack.back()->as_transform()->add_roty((yyvsp[-1]._number)); } break; case 117: -#line 1540 "parser.yxx" +#line 1543 "parser.yxx" { egg_stack.back()->as_transform()->add_rotz((yyvsp[-1]._number)); } break; case 118: -#line 1547 "parser.yxx" +#line 1550 "parser.yxx" { egg_stack.back()->as_transform()->add_rotate3d((yyvsp[-4]._number), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } break; case 119: -#line 1554 "parser.yxx" +#line 1557 "parser.yxx" { egg_stack.back()->as_transform()->add_scale2d(LVecBase2d((yyvsp[-2]._number), (yyvsp[-1]._number))); } break; case 120: -#line 1561 "parser.yxx" +#line 1564 "parser.yxx" { egg_stack.back()->as_transform()->add_scale3d(LVecBase3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number))); } break; case 121: -#line 1568 "parser.yxx" +#line 1571 "parser.yxx" { egg_stack.back()->as_transform()->add_uniform_scale((yyvsp[-1]._number)); } break; case 124: -#line 1582 "parser.yxx" +#line 1585 "parser.yxx" { egg_stack.back()->as_transform()->add_matrix3 (LMatrix3d((yyvsp[-8]._number), (yyvsp[-7]._number), (yyvsp[-6]._number), @@ -3339,7 +3342,7 @@ yyreduce: break; case 127: -#line 1600 "parser.yxx" +#line 1603 "parser.yxx" { egg_stack.back()->as_transform()->add_matrix4 (LMatrix4d((yyvsp[-15]._number), (yyvsp[-14]._number), (yyvsp[-13]._number), (yyvsp[-12]._number), @@ -3350,7 +3353,7 @@ yyreduce: break; case 128: -#line 1619 "parser.yxx" +#line 1622 "parser.yxx" { if ((yyvsp[-2]._egg) != (EggVertexPool *)NULL) { EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[-2]._egg)); @@ -3375,14 +3378,14 @@ yyreduce: break; case 129: -#line 1652 "parser.yxx" +#line 1655 "parser.yxx" { (yyval._number) = 1.0; } break; case 130: -#line 1656 "parser.yxx" +#line 1659 "parser.yxx" { string name = (yyvsp[-3]._string); double value = (yyvsp[-1]._number); @@ -3399,7 +3402,7 @@ yyreduce: break; case 132: -#line 1693 "parser.yxx" +#line 1696 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); group->set_lod(EggSwitchConditionDistance((yyvsp[-8]._number), (yyvsp[-7]._number), LPoint3d((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number)))); @@ -3407,7 +3410,7 @@ yyreduce: break; case 133: -#line 1698 "parser.yxx" +#line 1701 "parser.yxx" { EggGroup *group = DCAST(EggGroup, egg_stack.back()); group->set_lod(EggSwitchConditionDistance((yyvsp[-9]._number), (yyvsp[-8]._number), LPoint3d((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number)), (yyvsp[-7]._number))); @@ -3415,14 +3418,14 @@ yyreduce: break; case 134: -#line 1715 "parser.yxx" +#line 1718 "parser.yxx" { egg_stack.push_back(new EggPolygon((yyvsp[0]._string))); } break; case 135: -#line 1719 "parser.yxx" +#line 1722 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3430,14 +3433,14 @@ yyreduce: break; case 136: -#line 1734 "parser.yxx" +#line 1737 "parser.yxx" { egg_stack.push_back(new EggTriangleFan((yyvsp[0]._string))); } break; case 137: -#line 1738 "parser.yxx" +#line 1741 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3445,14 +3448,14 @@ yyreduce: break; case 138: -#line 1753 "parser.yxx" +#line 1756 "parser.yxx" { egg_stack.push_back(new EggTriangleStrip((yyvsp[0]._string))); } break; case 139: -#line 1757 "parser.yxx" +#line 1760 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3460,14 +3463,14 @@ yyreduce: break; case 140: -#line 1772 "parser.yxx" +#line 1775 "parser.yxx" { egg_stack.push_back(new EggPoint((yyvsp[0]._string))); } break; case 141: -#line 1776 "parser.yxx" +#line 1779 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3475,14 +3478,14 @@ yyreduce: break; case 142: -#line 1791 "parser.yxx" +#line 1794 "parser.yxx" { egg_stack.push_back(new EggLine((yyvsp[0]._string))); } break; case 143: -#line 1795 "parser.yxx" +#line 1798 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3490,14 +3493,14 @@ yyreduce: break; case 144: -#line 1810 "parser.yxx" +#line 1813 "parser.yxx" { egg_stack.push_back(new EggNurbsSurface((yyvsp[0]._string))); } break; case 145: -#line 1814 "parser.yxx" +#line 1817 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3505,14 +3508,14 @@ yyreduce: break; case 146: -#line 1829 "parser.yxx" +#line 1832 "parser.yxx" { egg_stack.push_back(new EggNurbsCurve((yyvsp[0]._string))); } break; case 147: -#line 1833 "parser.yxx" +#line 1836 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3520,7 +3523,7 @@ yyreduce: break; case 152: -#line 1863 "parser.yxx" +#line 1866 "parser.yxx" { if (!egg_stack.back()->is_of_type(EggCompositePrimitive::get_class_type())) { eggyyerror("Not a composite primitive; components are not allowed here."); @@ -3537,7 +3540,7 @@ yyreduce: break; case 153: -#line 1877 "parser.yxx" +#line 1880 "parser.yxx" { PT(EggPrimitive) prim = DCAST(EggPrimitive, egg_stack.back()); egg_stack.pop_back(); @@ -3547,7 +3550,7 @@ yyreduce: break; case 161: -#line 1891 "parser.yxx" +#line 1894 "parser.yxx" { EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -3613,7 +3616,7 @@ yyreduce: break; case 173: -#line 1975 "parser.yxx" +#line 1978 "parser.yxx" { EggNurbsCurve *curve = DCAST(EggNurbsCurve, (yyvsp[0]._egg)); EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); @@ -3622,7 +3625,7 @@ yyreduce: break; case 175: -#line 1982 "parser.yxx" +#line 1985 "parser.yxx" { EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -3678,7 +3681,7 @@ yyreduce: break; case 186: -#line 2056 "parser.yxx" +#line 2059 "parser.yxx" { EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -3740,7 +3743,7 @@ yyreduce: break; case 187: -#line 2125 "parser.yxx" +#line 2128 "parser.yxx" { if ((yyvsp[0]._egg) != (EggTexture *)NULL) { EggTexture *texture = DCAST(EggTexture, (yyvsp[0]._egg)); @@ -3750,7 +3753,7 @@ yyreduce: break; case 188: -#line 2142 "parser.yxx" +#line 2145 "parser.yxx" { EggTexture *texture = NULL; @@ -3783,7 +3786,7 @@ yyreduce: break; case 189: -#line 2182 "parser.yxx" +#line 2185 "parser.yxx" { if ((yyvsp[0]._egg) != (EggMaterial *)NULL) { EggMaterial *material = DCAST(EggMaterial, (yyvsp[0]._egg)); @@ -3793,14 +3796,14 @@ yyreduce: break; case 190: -#line 2199 "parser.yxx" +#line 2202 "parser.yxx" { DCAST(EggPrimitive, egg_stack.back())->set_normal(Normald((yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 191: -#line 2203 "parser.yxx" +#line 2206 "parser.yxx" { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals. insert(EggMorphNormal((yyvsp[-5]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -3811,7 +3814,7 @@ yyreduce: break; case 192: -#line 2211 "parser.yxx" +#line 2214 "parser.yxx" { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals. insert(EggMorphNormal((yyvsp[-4]._string), LVector3d((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -3822,14 +3825,14 @@ yyreduce: break; case 193: -#line 2229 "parser.yxx" +#line 2232 "parser.yxx" { DCAST(EggPrimitive, egg_stack.back())->set_color(Colorf((yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number), (yyvsp[0]._number))); } break; case 194: -#line 2233 "parser.yxx" +#line 2236 "parser.yxx" { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas. insert(EggMorphColor((yyvsp[-6]._string), LVector4f((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -3840,7 +3843,7 @@ yyreduce: break; case 195: -#line 2241 "parser.yxx" +#line 2244 "parser.yxx" { bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas. insert(EggMorphColor((yyvsp[-5]._string), LVector4f((yyvsp[-4]._number), (yyvsp[-3]._number), (yyvsp[-2]._number), (yyvsp[-1]._number)))).second; @@ -3851,7 +3854,7 @@ yyreduce: break; case 196: -#line 2259 "parser.yxx" +#line 2262 "parser.yxx" { EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back()); int value = (int)(yyvsp[0]._number); @@ -3860,7 +3863,7 @@ yyreduce: break; case 197: -#line 2275 "parser.yxx" +#line 2278 "parser.yxx" { if ((yyvsp[-2]._egg) != (EggVertexPool *)NULL) { EggVertexPool *pool = DCAST(EggVertexPool, (yyvsp[-2]._egg)); @@ -3884,7 +3887,7 @@ yyreduce: break; case 198: -#line 2306 "parser.yxx" +#line 2309 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); int u_order = (int)(yyvsp[-1]._number); @@ -3895,7 +3898,7 @@ yyreduce: break; case 199: -#line 2324 "parser.yxx" +#line 2327 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); PTA_double nums = (yyvsp[0]._number_list); @@ -3908,7 +3911,7 @@ yyreduce: break; case 200: -#line 2344 "parser.yxx" +#line 2347 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); PTA_double nums = (yyvsp[0]._number_list); @@ -3921,7 +3924,7 @@ yyreduce: break; case 201: -#line 2364 "parser.yxx" +#line 2367 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nurbs->_trims.push_back(EggNurbsSurface::Trim()); @@ -3929,7 +3932,7 @@ yyreduce: break; case 203: -#line 2380 "parser.yxx" +#line 2383 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nassertr(!nurbs->_trims.empty(), 0); @@ -3938,7 +3941,7 @@ yyreduce: break; case 204: -#line 2386 "parser.yxx" +#line 2389 "parser.yxx" { EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back()); nassertr(!nurbs->_trims.empty(), 0); @@ -3949,7 +3952,7 @@ yyreduce: break; case 205: -#line 2405 "parser.yxx" +#line 2408 "parser.yxx" { EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back()); int order = (int)(yyvsp[0]._number); @@ -3958,7 +3961,7 @@ yyreduce: break; case 206: -#line 2421 "parser.yxx" +#line 2424 "parser.yxx" { EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back()); PTA_double nums = (yyvsp[0]._number_list); @@ -3971,7 +3974,7 @@ yyreduce: break; case 207: -#line 2442 "parser.yxx" +#line 2445 "parser.yxx" { EggTable *table = new EggTable((yyvsp[0]._string)); table->set_table_type(EggTable::TT_table); @@ -3980,7 +3983,7 @@ yyreduce: break; case 208: -#line 2448 "parser.yxx" +#line 2451 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -3988,7 +3991,7 @@ yyreduce: break; case 209: -#line 2464 "parser.yxx" +#line 2467 "parser.yxx" { EggTable *table = new EggTable((yyvsp[0]._string)); table->set_table_type(EggTable::TT_bundle); @@ -3997,7 +4000,7 @@ yyreduce: break; case 210: -#line 2470 "parser.yxx" +#line 2473 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -4005,42 +4008,42 @@ yyreduce: break; case 212: -#line 2487 "parser.yxx" +#line 2490 "parser.yxx" { DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 213: -#line 2491 "parser.yxx" +#line 2494 "parser.yxx" { DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 214: -#line 2495 "parser.yxx" +#line 2498 "parser.yxx" { DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 215: -#line 2499 "parser.yxx" +#line 2502 "parser.yxx" { DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 216: -#line 2503 "parser.yxx" +#line 2506 "parser.yxx" { DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 217: -#line 2518 "parser.yxx" +#line 2521 "parser.yxx" { EggSAnimData *anim_data = new EggSAnimData((yyvsp[0]._string)); egg_stack.push_back(anim_data); @@ -4048,7 +4051,7 @@ yyreduce: break; case 218: -#line 2523 "parser.yxx" +#line 2526 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -4056,7 +4059,7 @@ yyreduce: break; case 220: -#line 2540 "parser.yxx" +#line 2543 "parser.yxx" { EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -4071,14 +4074,14 @@ yyreduce: break; case 221: -#line 2552 "parser.yxx" +#line 2555 "parser.yxx" { DCAST(EggSAnimData, egg_stack.back())->set_data((yyvsp[-1]._number_list)); } break; case 222: -#line 2566 "parser.yxx" +#line 2569 "parser.yxx" { EggXfmAnimData *anim_data = new EggXfmAnimData((yyvsp[0]._string)); egg_stack.push_back(anim_data); @@ -4086,7 +4089,7 @@ yyreduce: break; case 223: -#line 2571 "parser.yxx" +#line 2574 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -4094,7 +4097,7 @@ yyreduce: break; case 225: -#line 2588 "parser.yxx" +#line 2591 "parser.yxx" { EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -4114,14 +4117,14 @@ yyreduce: break; case 226: -#line 2605 "parser.yxx" +#line 2608 "parser.yxx" { DCAST(EggXfmAnimData, egg_stack.back())->set_data((yyvsp[-1]._number_list)); } break; case 227: -#line 2619 "parser.yxx" +#line 2622 "parser.yxx" { EggXfmSAnim *anim_group = new EggXfmSAnim((yyvsp[0]._string)); egg_stack.push_back(anim_group); @@ -4129,7 +4132,7 @@ yyreduce: break; case 228: -#line 2624 "parser.yxx" +#line 2627 "parser.yxx" { (yyval._egg) = egg_stack.back(); egg_stack.pop_back(); @@ -4137,7 +4140,7 @@ yyreduce: break; case 230: -#line 2641 "parser.yxx" +#line 2644 "parser.yxx" { EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back()); string name = (yyvsp[-3]._string); @@ -4155,42 +4158,42 @@ yyreduce: break; case 231: -#line 2656 "parser.yxx" +#line 2659 "parser.yxx" { DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, (yyvsp[0]._egg))); } break; case 232: -#line 2671 "parser.yxx" +#line 2674 "parser.yxx" { (yyval._number_list) = PTA_double::empty_array(0); } break; case 233: -#line 2675 "parser.yxx" +#line 2678 "parser.yxx" { (yyval._number_list).push_back((double)(yyvsp[0]._number)); } break; case 234: -#line 2689 "parser.yxx" +#line 2692 "parser.yxx" { (yyval._number_list) = PTA_double::empty_array(0); } break; case 235: -#line 2693 "parser.yxx" +#line 2696 "parser.yxx" { (yyval._number_list).push_back((yyvsp[0]._number)); } break; case 236: -#line 2707 "parser.yxx" +#line 2710 "parser.yxx" { string name = (yyvsp[0]._string); Textures::iterator vpi = textures.find(name); @@ -4204,7 +4207,7 @@ yyreduce: break; case 237: -#line 2728 "parser.yxx" +#line 2731 "parser.yxx" { string name = (yyvsp[0]._string); Materials::iterator vpi = materials.find(name); @@ -4218,7 +4221,7 @@ yyreduce: break; case 238: -#line 2749 "parser.yxx" +#line 2752 "parser.yxx" { string name = (yyvsp[0]._string); VertexPools::iterator vpi = vertex_pools.find(name); @@ -4236,7 +4239,7 @@ yyreduce: break; case 239: -#line 2775 "parser.yxx" +#line 2778 "parser.yxx" { eggyyerror("Name required."); (yyval._string) = ""; @@ -4244,7 +4247,7 @@ yyreduce: break; case 242: -#line 2804 "parser.yxx" +#line 2807 "parser.yxx" { eggyyerror("String required."); (yyval._string) = ""; @@ -4252,63 +4255,63 @@ yyreduce: break; case 244: -#line 2820 "parser.yxx" +#line 2823 "parser.yxx" { (yyval._string) = ""; } break; case 246: -#line 2838 "parser.yxx" +#line 2841 "parser.yxx" { (yyval._string) = (yyvsp[0]._string); } break; case 247: -#line 2842 "parser.yxx" +#line 2845 "parser.yxx" { (yyval._string) = (yyvsp[0]._string); } break; case 249: -#line 2859 "parser.yxx" +#line 2862 "parser.yxx" { (yyval._string) = ""; } break; case 250: -#line 2863 "parser.yxx" +#line 2866 "parser.yxx" { (yyval._string) = (yyvsp[0]._string); } break; case 251: -#line 2879 "parser.yxx" +#line 2882 "parser.yxx" { (yyval._string) = (yyvsp[0]._string); } break; case 252: -#line 2883 "parser.yxx" +#line 2886 "parser.yxx" { (yyval._string) = (yyvsp[-1]._string) + "\n" + (yyvsp[0]._string); } break; case 254: -#line 2898 "parser.yxx" +#line 2901 "parser.yxx" { (yyval._number) = (yyvsp[0]._ulong); } break; case 255: -#line 2913 "parser.yxx" +#line 2916 "parser.yxx" { (yyval._number) = (yyvsp[0]._number); (yyval._ulong) = (unsigned long)(yyvsp[0]._number); @@ -4317,7 +4320,7 @@ yyreduce: break; case 256: -#line 2919 "parser.yxx" +#line 2922 "parser.yxx" { (yyval._number) = (yyvsp[0]._ulong); (yyval._ulong) = (yyvsp[0]._ulong); @@ -4326,7 +4329,7 @@ yyreduce: break; case 257: -#line 2925 "parser.yxx" +#line 2928 "parser.yxx" { (yyval._number) = 0.0; (yyval._ulong) = 0; @@ -4335,7 +4338,7 @@ yyreduce: break; case 258: -#line 2942 "parser.yxx" +#line 2945 "parser.yxx" { int i = (int)(yyvsp[0]._number); if ((double)i != (yyvsp[0]._number)) { @@ -4346,7 +4349,7 @@ yyreduce: break; case 259: -#line 2950 "parser.yxx" +#line 2953 "parser.yxx" { (yyval._number) = (yyvsp[0]._ulong); } @@ -4356,7 +4359,7 @@ yyreduce: } /* Line 1037 of yacc.c. */ -#line 4360 "y.tab.c" +#line 4363 "y.tab.c" yyvsp -= yylen; yyssp -= yylen; diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index cd33a2bf57..b8ed69d0c4 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -654,6 +654,9 @@ texture_body: } else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) { texture->set_alpha_file_channel((int)value); + } else if (cmp_nocase_uh(name, "read_mipmaps") == 0) { + texture->set_read_mipmaps(((int)value) != 0); + } else { eggyywarning("Unsupported texture scalar: " + name); } diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 7591c0af0d..6b93056932 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/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(), egg_tex->get_alpha_fullpath(), wanted_channels, - egg_tex->get_alpha_file_channel()); + egg_tex->get_alpha_file_channel(), + egg_tex->get_read_mipmaps()); } else { tex = TexturePool::load_texture(egg_tex->get_fullpath(), - wanted_channels); + wanted_channels, + egg_tex->get_read_mipmaps()); } break; 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; 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; } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 3588062d8b..f95386fd6a 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -470,27 +470,47 @@ reset() { if (is_at_least_version(1, 3)) { _supports_compressed_texture = true; + _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1D"); _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2D"); + _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3D"); + _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1D"); _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2D"); + _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3D"); _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImage"); } else if (has_extension("GL_ARB_texture_compression")) { _supports_compressed_texture = true; + _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1DARB"); _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage2DARB"); + _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage3DARB"); + _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage1DARB"); _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage2DARB"); + _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3DARB"); _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImageARB"); } if (_supports_compressed_texture) { - if (_glCompressedTexImage2D == NULL || + if (_glCompressedTexImage1D == NULL || + _glCompressedTexImage2D == NULL || + _glCompressedTexImage3D == NULL || + _glCompressedTexSubImage1D == NULL || _glCompressedTexSubImage2D == NULL || + _glCompressedTexSubImage3D == NULL || _glGetCompressedTexImage == NULL) { GLCAT.warning() << "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; 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; } 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; } @@ -5619,8 +5590,7 @@ do_issue_texture() { // Description: //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: -update_standard_texture_bindings() -{ +update_standard_texture_bindings() { int num_stages = _target._texture->get_num_on_stages(); int num_old_stages = _max_texture_stages; if (_state._texture != (TextureAttrib *)NULL) { @@ -6147,7 +6117,6 @@ specify_texture(Texture *tex) { Texture::FilterType minfilter = tex->get_minfilter(); Texture::FilterType magfilter = tex->get_magfilter(); bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps); - Texture::CompressionMode image_compression = tex->get_ram_image_compression(); #ifndef NDEBUG if (CLP(force_mipmaps)) { @@ -6157,20 +6126,17 @@ specify_texture(Texture *tex) { } #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, @@ -6417,53 +6383,42 @@ upload_texture(CLP(TextureContext) *gtc) { return false; } - size_t page_size = tex->get_ram_page_size(); - const unsigned char *image_base = image; - success = success && upload_texture_image (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X, 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 (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 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 (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 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 (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 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 (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 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 (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 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 { // Any other kind of texture can be loaded all at once. success = upload_texture_image (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()), internal_format, width, height, depth, external_format, component_type, - image, image.size(), image_compression); + false, 0, image_compression); } if (success) { @@ -6477,12 +6432,6 @@ upload_texture(CLP(TextureContext) *gtc) { gtc->update_data_size_bytes(get_texture_memory_size(tex)); #endif -#ifndef NDEBUG - if (uses_mipmaps && CLP(save_mipmaps)) { - save_mipmap_images(tex); - } -#endif - report_my_gl_errors(); return true; } @@ -6503,8 +6452,7 @@ upload_texture_image(CLP(TextureContext) *gtc, GLenum target, GLint internal_format, int width, int height, int depth, GLint external_format, GLenum component_type, - const unsigned char *image, - size_t image_size, + bool one_page_only, int z, Texture::CompressionMode image_compression) { // Make sure the error stack is cleared out before we begin. report_my_gl_errors(); @@ -6518,152 +6466,215 @@ upload_texture_image(CLP(TextureContext) *gtc, } PStatTimer timer(_load_texture_pcollector); - - 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; - - } else -#endif - if (!_supports_generate_mipmap || - (!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); - } - - report_my_gl_errors(); - if (success) { - return true; - } - } - } + Texture *tex = gtc->get_texture(); if (GLCAT.is_debug()) { if (image_compression != Texture::CM_off) { GLCAT.debug() - << "loading pre-compressed texture " << gtc->get_texture()->get_name() << "\n"; + << "loading pre-compressed texture " << tex->get_name() << "\n"; } else if (is_compressed_format(internal_format)) { GLCAT.debug() - << "compressing texture " << gtc->get_texture()->get_name() << "\n"; + << "compressing texture " << tex->get_name() << "\n"; } } + int num_ram_mipmap_levels = 1; + bool load_ram_mipmaps = false; + + if (uses_mipmaps) { + num_ram_mipmap_levels = tex->get_num_ram_mipmap_images(); + + if (num_ram_mipmap_levels == 1) { + // No RAM mipmap levels available. Should we generate some? + if (!_supports_generate_mipmap || + (!auto_generate_mipmaps && image_compression == Texture::CM_off)) { + // 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(); + } + } + + 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; + + } 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 || gtc->_internal_format != internal_format || gtc->_width != width || gtc->_height != height || gtc->_depth != depth) { // We need to reload a new image. + + 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 - _data_transferred_pcollector.add_level(image_size); + _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; + 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); + } } - 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); - } + highest_level = n; + + width = max(width >> 1, 1); + height = max(height >> 1, 1); + depth = max(depth >> 1, 1); } } else { // We can reload the image over the previous image, possibly // 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 - _data_transferred_pcollector.add_level(image_size); + _data_transferred_pcollector.add_level(image_size); #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 // failed. GLenum error_code = GLP(GetError)(); if (error_code != GL_NO_ERROR) { const GLubyte *error_string = GLUP(ErrorString)(error_code); 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) { GLCAT.error(false) << " : " << 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 // Access: Protected @@ -6850,173 +6946,3 @@ do_point_size() { 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 diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index b3b5053b52..533c53ca67 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/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 PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); 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 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 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); -class CLP(GeomContext); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); //////////////////////////////////////////////////////////////////// // Class : GLGraphicsStateGuardian @@ -274,21 +275,18 @@ protected: GLenum target, GLint internal_format, int width, int height, int depth, GLint external_format, GLenum component_type, - const unsigned char *image, - size_t image_size, + bool one_page_only, int z, Texture::CompressionMode image_compression); size_t get_texture_memory_size(Texture *tex); 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(); -#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 { AA_poly, AA_line, @@ -374,8 +372,12 @@ public: PFNGLTEXIMAGE3DPROC _glTexImage3D; PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D; + PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D; PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D; + PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D; + PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC _glCompressedTexSubImage1D; PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC _glCompressedTexSubImage2D; + PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC _glCompressedTexSubImage3D; PFNGLGETCOMPRESSEDTEXIMAGEPROC _glGetCompressedTexImage; bool _supports_bgr; diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index 64d9782229..bee167d9a2 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/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 " "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) ("gl-color-mask", true, PRC_DESC("Configure this false if your GL's implementation of glColorMask() " diff --git a/panda/src/glstuff/glmisc_src.h b/panda/src/glstuff/glmisc_src.h index 6b14c79b83..c6c754b562 100644 --- a/panda/src/glstuff/glmisc_src.h +++ b/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_mipmaps); extern ConfigVariableBool CLP(force_mipmaps); -extern ConfigVariableBool CLP(show_mipmaps); -extern ConfigVariableBool CLP(save_mipmaps); extern ConfigVariableBool CLP(color_mask); extern ConfigVariableBool CLP(compile_and_execute); diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 0b0cee37cb..e19fea78fe 100644 --- a/panda/src/gobj/texture.I +++ b/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); } +//////////////////////////////////////////////////////////////////// +// 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 // Access: Published @@ -462,7 +696,10 @@ might_have_ram_image() const { //////////////////////////////////////////////////////////////////// INLINE size_t Texture:: 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:: 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; } +//////////////////////////////////////////////////////////////////// +// 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 // 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 // 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:: -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 // 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:: -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 -// Access: Private +// Access: Private, Static // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // array, which is taken to be an array of unsigned @@ -808,13 +1143,13 @@ set_match_framebuffer_format(bool flag) { // 0-255. //////////////////////////////////////////////////////////////////// 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 -// Access: Private +// Access: Private, Static // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // array, which is taken to be an array of unsigned @@ -822,19 +1157,19 @@ store_unscaled_byte(int &index, int value) { // 0-65535. //////////////////////////////////////////////////////////////////// INLINE void Texture:: -store_unscaled_short(int &index, int value) { +store_unscaled_short(unsigned char *&p, int value) { union { ushort us; uchar uc[2]; } v; 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 -// Access: Private +// Access: Private, Static // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // 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. //////////////////////////////////////////////////////////////////// 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 -// Access: Private +// Access: Private, Static // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // 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. //////////////////////////////////////////////////////////////////// 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 -// 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 // element of the array, which is taken to be an array // of unsigned bytes. //////////////////////////////////////////////////////////////////// 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 -// 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 // element of the array, which is taken to be an array // of unsigned shorts. //////////////////////////////////////////////////////////////////// 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 { ushort us; uchar uc[2]; } 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; } diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 92eb429ea9..cf791c19e6 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -64,7 +64,6 @@ Texture(const string &name) : _border_color.set(0.0f, 0.0f, 0.0f, 1.0f); _compression = CM_default; _ram_image_compression = CM_off; - _ram_page_size = 0; _render_to_texture = false; _match_framebuffer_format = false; @@ -75,8 +74,11 @@ Texture(const string &name) : set_format(F_rgb); set_component_type(T_unsigned_byte); - _loaded_from_disk = false; + _loaded_from_image = false; _loaded_from_txo = false; + _has_read_pages = false; + _has_read_mipmaps = false; + _num_mipmap_levels_read = 0; } //////////////////////////////////////////////////////////////////// @@ -102,8 +104,11 @@ Texture(const Texture ©) : _texture_type(copy._texture_type), _format(copy._format), _component_type(copy._component_type), - _loaded_from_disk(copy._loaded_from_disk), + _loaded_from_image(copy._loaded_from_image), _loaded_from_txo(copy._loaded_from_txo), + _has_read_pages(copy._has_read_pages), + _has_read_mipmaps(copy._has_read_mipmaps), + _num_mipmap_levels_read(copy._num_mipmap_levels_read), _wrap_u(copy._wrap_u), _wrap_v(copy._wrap_v), _wrap_w(copy._wrap_w), @@ -114,9 +119,8 @@ Texture(const Texture ©) : _border_color(copy._border_color), _compression(copy._compression), _match_framebuffer_format(copy._match_framebuffer_format), - _ram_image(copy._ram_image), _ram_image_compression(copy._ram_image_compression), - _ram_page_size(copy._ram_page_size) + _ram_images(copy._ram_images) { } @@ -143,7 +147,7 @@ operator = (const Texture ©) { _texture_type = copy._texture_type; _format = copy._format; _component_type = copy._component_type; - _loaded_from_disk = copy._loaded_from_disk; + _loaded_from_image = copy._loaded_from_image; _loaded_from_txo = copy._loaded_from_txo; _wrap_u = copy._wrap_u; _wrap_v = copy._wrap_v; @@ -155,9 +159,8 @@ operator = (const Texture ©) { _border_color = copy._border_color; _compression = copy._compression; _match_framebuffer_format = copy._match_framebuffer_format; - _ram_image = copy._ram_image; _ram_image_compression = copy._ram_image_compression; - _ram_page_size = copy._ram_page_size; + _ram_images = copy._ram_images; ++_modified; } @@ -180,7 +183,7 @@ Texture:: // be duplicated in texture memory (and may be // independently modified if desired). // -// If the Texture is an AviTexture, the resulting +// If the Texture is a VideoTexture, the resulting // duplicate may be animated independently of the // original. //////////////////////////////////////////////////////////////////// @@ -189,6 +192,17 @@ make_copy() { return new Texture(*this); } +//////////////////////////////////////////////////////////////////// +// Function: Texture::clear +// Access: Published, Virtual +// Description: Reinitializes the texture to its default, empty +// state. +//////////////////////////////////////////////////////////////////// +void Texture:: +clear() { + operator =(Texture(get_name())); +} + //////////////////////////////////////////////////////////////////// // Function: Texture::setup_texture // Access: Published @@ -221,8 +235,10 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size, set_format(format); clear_ram_image(); - _loaded_from_disk = false; + _loaded_from_image = false; _loaded_from_txo = false; + _has_read_pages = false; + _has_read_mipmaps = false; } //////////////////////////////////////////////////////////////////// @@ -328,232 +344,6 @@ generate_normalization_cube_map(int size) { } } -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published, Virtual -// Description: Reads the texture from the indicated filename. If -// num_channels is not 0, it specifies the number of -// components to downgrade the image to if it is greater -// than this number. -// -// This also implicitly sets keep_ram_image to false. -// -// If the filename has the extension .txo, this -// implicitly reads a texture object instead of a -// filename (which replaces all of the texture -// properties). -//////////////////////////////////////////////////////////////////// -bool Texture:: -read(const Filename &fullpath, int z, int primary_file_num_channels) { - if (is_txo_filename(fullpath)) { - return read_txo_file(fullpath); - } - - PNMImage image; - - if (textures_header_only) { - if (!image.read_header(fullpath)) { - gobj_cat.error() - << "Texture::read() - couldn't read: " << fullpath << endl; - return false; - } - image = PNMImage(1, 1, image.get_num_channels(), image.get_maxval(), - image.get_type()); - image.fill(0.2, 0.3, 1.0); - if (image.has_alpha()) { - image.alpha_fill(1.0); - } - - } else { - if (!image.read(fullpath, NULL, false)) { - gobj_cat.error() - << "Texture::read() - couldn't read: " << fullpath << endl; - 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(); - - // Check to see if we need to scale it. - consider_rescale(image); - consider_downgrade(image, primary_file_num_channels); - - _primary_file_num_channels = image.get_num_channels(); - _alpha_file_channel = 0; - - return load(image, z); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published, Virtual -// Description: Combine a 3-component image with a grayscale image -// to get a 4-component image -// -// This also implicitly sets keep_ram_image to false. -//////////////////////////////////////////////////////////////////// -bool Texture:: -read(const Filename &fullpath, const Filename &alpha_fullpath, - int z, int primary_file_num_channels, int alpha_file_channel) { - PNMImage image; - if (textures_header_only) { - if (!image.read_header(fullpath)) { - gobj_cat.error() - << "Texture::read() - couldn't read: " << fullpath << endl; - return false; - } - image = PNMImage(1, 1, image.get_num_channels(), image.get_maxval(), - image.get_type()); - image.fill(0.2, 0.3, 1.0); - if (image.has_alpha()) { - image.alpha_fill(1.0); - } - - } else { - if (!image.read(fullpath, NULL, false)) { - gobj_cat.error() - << "Texture::read() - couldn't read: " << fullpath << endl; - return false; - } - } - - PNMImage alpha_image; - if (textures_header_only) { - if (!alpha_image.read_header(alpha_fullpath)) { - gobj_cat.error() - << "Texture::read() - couldn't read: " << alpha_fullpath << endl; - return false; - } - alpha_image = PNMImage(1, 1, alpha_image.get_num_channels(), - alpha_image.get_maxval(), - alpha_image.get_type()); - alpha_image.fill(1.0); - if (alpha_image.has_alpha()) { - alpha_image.alpha_fill(1.0); - } - - } else { - if (!alpha_image.read(alpha_fullpath, NULL, true)) { - gobj_cat.error() - << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; - 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); - - consider_rescale(image); - - // The grayscale (alpha channel) image must be the same size as the - // main image. - if (image.get_x_size() != alpha_image.get_x_size() || - image.get_y_size() != alpha_image.get_y_size()) { - gobj_cat.info() - << "Automatically rescaling " << alpha_fullpath.get_basename() - << " from " << alpha_image.get_x_size() << " by " - << alpha_image.get_y_size() << " to " << image.get_x_size() - << " by " << image.get_y_size() << "\n"; - - PNMImage scaled(image.get_x_size(), image.get_y_size(), - alpha_image.get_num_channels(), - alpha_image.get_maxval(), alpha_image.get_type()); - scaled.quick_filter_from(alpha_image); - alpha_image = scaled; - } - - consider_downgrade(image, primary_file_num_channels); - - _primary_file_num_channels = image.get_num_channels(); - - // Make the original image a 4-component image by taking the - // grayscale value from the second image. - image.add_alpha(); - - if (alpha_file_channel == 4 || - (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) { - // Use the alpha channel. - for (int x = 0; x < image.get_x_size(); x++) { - for (int y = 0; y < image.get_y_size(); y++) { - image.set_alpha(x, y, alpha_image.get_alpha(x, y)); - } - } - _alpha_file_channel = alpha_image.get_num_channels(); - - } else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 && - alpha_image.get_num_channels() >= 3) { - // Use the appropriate red, green, or blue channel. - for (int x = 0; x < image.get_x_size(); x++) { - for (int y = 0; y < image.get_y_size(); y++) { - image.set_alpha(x, y, alpha_image.get_channel_val(x, y, alpha_file_channel - 1)); - } - } - _alpha_file_channel = alpha_file_channel; - - } else { - // Use the grayscale channel. - for (int x = 0; x < image.get_x_size(); x++) { - for (int y = 0; y < image.get_y_size(); y++) { - image.set_alpha(x, y, alpha_image.get_gray(x, y)); - } - } - _alpha_file_channel = 0; - } - - return load(image, z); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::write -// Access: Published -// Description: Writes the texture to the indicated filename. If the -// filename ends in the extension .txo, this implicitly -// writes a Panda texture object (.txo) instead of an -// image file. -//////////////////////////////////////////////////////////////////// -bool Texture:: -write(const Filename &name, int z) const { - if (!has_ram_image()) { - ((Texture *)this)->get_ram_image(); - } - nassertr(has_ram_image(), false); - - if (is_txo_filename(name)) { - return write_txo_file(name); - } - - nassertr(get_ram_image_compression() == CM_off, false); - - PNMImage pnmimage; - if (!store(pnmimage, z)) { - return false; - } - - if (!pnmimage.write(name)) { - gobj_cat.error() - << "Texture::write() - couldn't write: " << name << endl; - return false; - } - return true; -} - //////////////////////////////////////////////////////////////////// // Function: Texture::estimate_texture_memory // Access: Published @@ -612,7 +402,7 @@ estimate_texture_memory() const { } size_t bytes = pixels * bpp; - if (is_mipmap(get_minfilter())) { + if (uses_mipmaps()) { bytes = (bytes * 4) / 3; } @@ -677,8 +467,11 @@ read_txo(istream &in, const string &filename) { } (*this) = (*other); - _loaded_from_disk = true; + _loaded_from_image = true; _loaded_from_txo = true; + _has_read_pages = false; + _has_read_mipmaps = false; + _num_mipmap_levels_read = 0; return true; } @@ -727,332 +520,6 @@ write_txo(ostream &out, const string &filename) const { return true; } -//////////////////////////////////////////////////////////////////// -// Function: Texture::read_pages -// Access: Published -// Description: Automatically reads in a sequence of pages, for the -// purpose of reading in a 3-d texture or a cube map -// texture. 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. If z_size -// is specified, the reading will stop there; otherwise, -// all found textures will be loaded, until a gap in the -// sequence is encountered. -// -// If more than one hash mark is used, the numbers will -// be padded with zeroes if necessary to the -// corresponding number of digits. -//////////////////////////////////////////////////////////////////// -bool Texture:: -read_pages(Filename fullpath_pattern, int z_size) { - if (is_txo_filename(fullpath_pattern)) { - return read_txo_file(fullpath_pattern); - } - - fullpath_pattern.set_pattern(true); - if (!fullpath_pattern.has_hash()) { - gobj_cat.error() - << "Template " << fullpath_pattern << " contains no hash marks.\n"; - return false; - } - - clear_ram_image(); - - if (z_size == 0) { - switch (_texture_type) { - case TT_1d_texture: - case TT_2d_texture: - z_size = 1; - break; - - case TT_cube_map: - z_size = 6; - break; - - default: - break; - } - } - - if (z_size != 0) { - set_z_size(z_size); - for (int z = 0; z < z_size; z++) { - if (!read(fullpath_pattern.get_filename_index(z), z)) { - return false; - } - } - } else { - set_z_size(0); - int z = 0; - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - - Filename file = fullpath_pattern.get_filename_index(z); - while (vfs->exists(file)) { - if (!read(file, z)) { - return false; - } - ++z; - - file = fullpath_pattern.get_filename_index(z); - } - } - - set_fullpath(fullpath_pattern); - clear_alpha_fullpath(); - - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::write_pages -// Access: Published -// Description: Automatically writes out a sequence of pages, for the -// purpose of writing out a 3-d texture or a cube map -// texture. 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. -// -// If more than one hash mark is used, the numbers will -// be padded with zeroes if necessary to the -// corresponding number of digits. -//////////////////////////////////////////////////////////////////// -bool Texture:: -write_pages(Filename fullpath_pattern) { - if (is_txo_filename(fullpath_pattern)) { - return write_txo_file(fullpath_pattern); - } - - fullpath_pattern.set_pattern(true); - if (!fullpath_pattern.has_hash()) { - gobj_cat.error() - << "Template " << fullpath_pattern << " contains no hash marks.\n"; - return false; - } - - for (int z = 0; z < _z_size; z++) { - if (!write(fullpath_pattern.get_filename_index(z), z)) { - return false; - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::load -// Access: Published, Virtual -// Description: Fills the texture system RAM data from the -// already-read PNMImage. -// -// For a 3-d texture or a cube map, this must be called -// multiple times, one for each page (z value). Cube -// maps have exactly 6 pages, while 3-d textures can -// have any number and can dynamically grow as each page -// is loaded. For the first page loaded, this also sets -// the texture parameters; for subsequent pages, the -// texture parameters must match those which were loaded -// previously. -// -// This also implicitly sets keep_ram_image to false if -// a filename has been set, or true if one has not been -// set. -//////////////////////////////////////////////////////////////////// -bool Texture:: -load(const PNMImage &pnmimage, int z) { - if (!reconsider_z_size(z)) { - return false; - } - nassertr(z >= 0 && z < _z_size, false); - - ComponentType component_type = T_unsigned_byte; - xelval maxval = pnmimage.get_maxval(); - if (maxval > 255) { - component_type = T_unsigned_short; - } - - if (!reconsider_image_properties(pnmimage.get_x_size(), pnmimage.get_y_size(), - pnmimage.get_num_channels(), component_type, - z)) { - return false; - } - - _loaded_from_disk = true; - modify_ram_image(); - _keep_ram_image = !has_filename(); - - // Now copy the pixel data from the PNMImage into our internal - // _image component. - bool has_alpha = pnmimage.has_alpha(); - bool is_grayscale = pnmimage.is_grayscale(); - - if (maxval == 255) { - // Most common case: one byte per pixel, and the source image - // shows a maxval of 255. No scaling is necessary. - int idx = get_expected_ram_page_size() * z; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - store_unscaled_byte(idx, pnmimage.get_gray_val(i, j)); - } else { - store_unscaled_byte(idx, pnmimage.get_blue_val(i, j)); - store_unscaled_byte(idx, pnmimage.get_green_val(i, j)); - store_unscaled_byte(idx, pnmimage.get_red_val(i, j)); - } - if (has_alpha) { - store_unscaled_byte(idx, pnmimage.get_alpha_val(i, j)); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - - } else if (maxval == 65535) { - // Another possible case: two bytes per pixel, and the source - // image shows a maxval of 65535. Again, no scaling is necessary. - int idx = get_expected_ram_page_size() * z; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - store_unscaled_short(idx, pnmimage.get_gray_val(i, j)); - } else { - store_unscaled_short(idx, pnmimage.get_blue_val(i, j)); - store_unscaled_short(idx, pnmimage.get_green_val(i, j)); - store_unscaled_short(idx, pnmimage.get_red_val(i, j)); - } - if (has_alpha) { - store_unscaled_short(idx, pnmimage.get_alpha_val(i, j)); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - - } else if (maxval <= 255) { - // A less common case: one byte per pixel, but the maxval is - // something other than 255. In this case, we should scale the - // pixel values up to the appropriate amount. - int idx = get_expected_ram_page_size() * z; - double scale = 255.0 / (double)maxval; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - store_scaled_byte(idx, pnmimage.get_gray_val(i, j), scale); - } else { - store_scaled_byte(idx, pnmimage.get_blue_val(i, j), scale); - store_scaled_byte(idx, pnmimage.get_green_val(i, j), scale); - store_scaled_byte(idx, pnmimage.get_red_val(i, j), scale); - } - if (has_alpha) { - store_scaled_byte(idx, pnmimage.get_alpha_val(i, j), scale); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - - } else { - // Another uncommon case: two bytes per pixel, and the maxval is - // something other than 65535. Again, we must scale the pixel - // values. - int idx = get_expected_ram_page_size() * z; - double scale = 65535.0 / (double)maxval; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - store_scaled_short(idx, pnmimage.get_gray_val(i, j), scale); - } else { - store_scaled_short(idx, pnmimage.get_blue_val(i, j), scale); - store_scaled_short(idx, pnmimage.get_green_val(i, j), scale); - store_scaled_short(idx, pnmimage.get_red_val(i, j), scale); - } - if (has_alpha) { - store_scaled_short(idx, pnmimage.get_alpha_val(i, j), scale); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - } - - ++_modified; - - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::store -// Access: Published -// Description: Saves the zth level of the texture to the indicated -// PNMImage, but does not write it to disk. -//////////////////////////////////////////////////////////////////// -bool Texture:: -store(PNMImage &pnmimage, int z) const { - nassertr(has_ram_image(), false); - nassertr(z >= 0 && z < _z_size, false); - - if (_component_type == T_unsigned_byte) { - pnmimage.clear(_x_size, _y_size, _num_components); - bool has_alpha = pnmimage.has_alpha(); - bool is_grayscale = pnmimage.is_grayscale(); - - int idx = get_expected_ram_page_size() * z; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - pnmimage.set_gray(i, j, get_unsigned_byte(idx)); - } else { - pnmimage.set_blue(i, j, get_unsigned_byte(idx)); - pnmimage.set_green(i, j, get_unsigned_byte(idx)); - pnmimage.set_red(i, j, get_unsigned_byte(idx)); - } - if (has_alpha) { - pnmimage.set_alpha(i, j, get_unsigned_byte(idx)); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - - return true; - - } else if (_component_type == T_unsigned_short) { - pnmimage.clear(_x_size, _y_size, _num_components, 65535); - bool has_alpha = pnmimage.has_alpha(); - bool is_grayscale = pnmimage.is_grayscale(); - - int idx = get_expected_ram_page_size() * z; - - for (int j = _y_size-1; j >= 0; j--) { - for (int i = 0; i < _x_size; i++) { - if (is_grayscale) { - pnmimage.set_gray(i, j, get_unsigned_short(idx)); - } else { - pnmimage.set_blue(i, j, get_unsigned_short(idx)); - pnmimage.set_green(i, j, get_unsigned_short(idx)); - pnmimage.set_red(i, j, get_unsigned_short(idx)); - } - if (has_alpha) { - pnmimage.set_alpha(i, j, get_unsigned_short(idx)); - } - } - } - - nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false); - - return true; - } - - gobj_cat.error() - << "Couldn't write image for " << get_name() - << "; inappropriate data type " << (int)_component_type << ".\n"; - return false; -} - //////////////////////////////////////////////////////////////////// // Function: Texture::load_related // Access: Published @@ -1227,6 +694,83 @@ set_render_to_texture(bool render_to_texture) { _render_to_texture = render_to_texture; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_expected_num_mipmap_levels +// Access: Published +// Description: Returns the number of mipmap levels that should be +// defined for this texture, given the texture's size. +// +// Note that this returns a number appropriate for +// mipmapping, even if the texture does not currently +// have mipmapping enabled. +//////////////////////////////////////////////////////////////////// +int Texture:: +get_expected_num_mipmap_levels() const { + int size = max(_x_size, max(_y_size, _z_size)); + int count = 1; + while (size > 1) { + size >>= 1; + ++count; + } + return count; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_expected_mipmap_x_size +// Access: Published +// Description: Returns the x_size that the nth mipmap level should +// have, based on the texture's size. +//////////////////////////////////////////////////////////////////// +int Texture:: +get_expected_mipmap_x_size(int n) const { + int size = max(_x_size, 1); + while (n > 0 && size > 1) { + size >>= 1; + --n; + } + return size; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_expected_mipmap_y_size +// Access: Published +// Description: Returns the y_size that the nth mipmap level should +// have, based on the texture's size. +//////////////////////////////////////////////////////////////////// +int Texture:: +get_expected_mipmap_y_size(int n) const { + int size = max(_y_size, 1); + while (n > 0 && size > 1) { + size >>= 1; + --n; + } + return size; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_expected_mipmap_z_size +// Access: Published +// Description: Returns the z_size that the nth mipmap level should +// have, based on the texture's size. +//////////////////////////////////////////////////////////////////// +int Texture:: +get_expected_mipmap_z_size(int n) const { + // 3-D textures have a different number of pages per each mipmap + // level. Other kinds of textures--especially, cube map + // textures--always have the same. + if (_texture_type == Texture::TT_3d_texture) { + int size = max(_z_size, 1); + while (n > 0 && size > 1) { + size >>= 1; + --n; + } + return size; + + } else { + return _z_size; + } +} + //////////////////////////////////////////////////////////////////// // Function: Texture::has_ram_image // Access: Published, Virtual @@ -1257,7 +801,7 @@ set_render_to_texture(bool render_to_texture) { //////////////////////////////////////////////////////////////////// bool Texture:: has_ram_image() const { - return !_ram_image.empty(); + return !_ram_images.empty() && !_ram_images[0]._image.empty(); } //////////////////////////////////////////////////////////////////// @@ -1290,11 +834,11 @@ has_ram_image() const { //////////////////////////////////////////////////////////////////// CPTA_uchar Texture:: get_ram_image() { - if (_loaded_from_disk && !has_ram_image() && has_filename()) { + if (_loaded_from_image && !has_ram_image() && has_filename()) { reload_ram_image(); } - return _ram_image; + return _ram_images[0]._image; } //////////////////////////////////////////////////////////////////// @@ -1309,13 +853,16 @@ get_ram_image() { //////////////////////////////////////////////////////////////////// PTA_uchar Texture:: modify_ram_image() { - if (_ram_image.empty() || _ram_image_compression != CM_off) { + if (_ram_images.empty() || _ram_images[0]._image.empty() || + _ram_image_compression != CM_off) { make_ram_image(); + } else { + clear_ram_mipmap_images(); } ++_modified; _keep_ram_image = true; - return _ram_image; + return _ram_images[0]._image; } //////////////////////////////////////////////////////////////////// @@ -1329,11 +876,14 @@ modify_ram_image() { //////////////////////////////////////////////////////////////////// PTA_uchar Texture:: make_ram_image() { - _ram_image = PTA_uchar::empty_array(get_expected_ram_image_size()); + _ram_images.clear(); + _ram_images.push_back(RamImage()); + _ram_images[0]._page_size = get_expected_ram_page_size(); + _ram_images[0]._image = PTA_uchar::empty_array(get_expected_ram_image_size()); _ram_image_compression = CM_off; ++_modified; _keep_ram_image = true; - return _ram_image; + return _ram_images[0]._image; } //////////////////////////////////////////////////////////////////// @@ -1351,13 +901,20 @@ set_ram_image(PTA_uchar image, Texture::CompressionMode compression, size_t page_size) { nassertv(compression != CM_default); nassertv(compression != CM_off || image.size() == get_expected_ram_image_size()); - if (_ram_image != image || _ram_image_compression != compression) { - _ram_image = image; + if (_ram_images.empty()) { + _ram_images.push_back(RamImage()); + } else { + clear_ram_mipmap_images(); + } + if (page_size == 0) { + page_size = image.size(); + } + if (_ram_images[0]._image != image || + _ram_images[0]._page_size != page_size || + _ram_image_compression != compression) { + _ram_images[0]._image = image; + _ram_images[0]._page_size = page_size; _ram_image_compression = compression; - _ram_page_size = page_size; - if (page_size == 0) { - _ram_page_size = image.size(); - } ++_modified; } _keep_ram_image = true; @@ -1370,8 +927,8 @@ set_ram_image(PTA_uchar image, Texture::CompressionMode compression, //////////////////////////////////////////////////////////////////// void Texture:: clear_ram_image() { - _ram_image.clear(); _ram_image_compression = CM_off; + _ram_images.clear(); } //////////////////////////////////////////////////////////////////// @@ -1387,6 +944,222 @@ get_keep_ram_image() const { return _keep_ram_image; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::has_all_ram_mipmap_images +// Access: Published +// Description: Returns true if all expected mipmap levels have been +// defined and exist in the system RAM, or false if even +// one mipmap level is missing. +//////////////////////////////////////////////////////////////////// +bool Texture:: +has_all_ram_mipmap_images() const { + if (_ram_images.empty() || _ram_images[0]._image.empty()) { + // If we don't even have a base image, the answer is no. + return false; + } + if (!uses_mipmaps()) { + // If we have a base image and don't require mipmapping, the + // answer is yes. + return true; + } + + // Check that we have enough mipmap levels to meet the size + // requirements. + int size = max(_x_size, max(_y_size, _z_size)); + int n = 0; + int x = 1; + while (x < size) { + x = (x << 1); + ++n; + if (n >= (int)_ram_images.size() || _ram_images[n]._image.empty()) { + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_ram_mipmap_image +// Access: Published +// Description: Returns the system-RAM image data associated with the +// nth mipmap level, if present. Returns NULL if the +// nth mipmap level is not present. +//////////////////////////////////////////////////////////////////// +CPTA_uchar Texture:: +get_ram_mipmap_image(int n) { + if (n < (int)_ram_images.size()) { + return _ram_images[n]._image; + } + return CPTA_uchar(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::modify_ram_mipmap_image +// Access: Published +// Description: Returns a modifiable pointer to the system-RAM image +// for the nth mipmap level. This assumes the RAM image +// is uncompressed; if this is not the case, raises an +// assertion. +// +// This also implicitly sets keep_ram_image to true. +//////////////////////////////////////////////////////////////////// +PTA_uchar Texture:: +modify_ram_mipmap_image(int n) { + nassertr(_ram_image_compression == CM_off, PTA_uchar()); + + if (n >= (int)_ram_images.size() || + _ram_images[n]._image.empty()) { + make_ram_mipmap_image(n); + } + + ++_modified; + _keep_ram_image = true; + return _ram_images[n]._image; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::make_ram_mipmap_image +// Access: Published +// Description: Discards the current system-RAM image for the +// nth mipmap level, if any, and allocates a new buffer +// of the appropriate size. Returns the new buffer. +// +// This also implicitly sets keep_ram_image to true. +//////////////////////////////////////////////////////////////////// +PTA_uchar Texture:: +make_ram_mipmap_image(int n) { + nassertr(_ram_image_compression == CM_off, PTA_uchar()); + + while (n >= (int)_ram_images.size()) { + _ram_images.push_back(RamImage()); + _ram_images.back()._page_size = 0; + } + + _ram_images[n]._image = PTA_uchar::empty_array(get_expected_ram_mipmap_image_size(n)); + _ram_images[n]._page_size = get_expected_ram_mipmap_page_size(n); + ++_modified; + _keep_ram_image = true; + return _ram_images[n]._image; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::set_ram_mipmap_image +// Access: Published +// Description: Replaces the current system-RAM image for the +// indicated mipmap level with the new data. If +// compression is not CM_off, it indicates that the new +// data is already pre-compressed in the indicated +// format. +// +// This also implicitly sets keep_ram_image to true. +//////////////////////////////////////////////////////////////////// +void Texture:: +set_ram_mipmap_image(int n, PTA_uchar image, size_t page_size) { + nassertv(_ram_image_compression != CM_off || image.size() == get_expected_ram_mipmap_image_size(n)); + + while (n >= (int)_ram_images.size()) { + _ram_images.push_back(RamImage()); + _ram_images.back()._page_size = 0; + } + if (page_size == 0) { + page_size = image.size(); + } + + if (_ram_images[n]._image != image || + _ram_images[n]._page_size != page_size) { + _ram_images[n]._image = image; + _ram_images[n]._page_size = page_size; + ++_modified; + } + _keep_ram_image = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::clear_ram_mipmap_image +// Access: Published +// Description: Discards the current system-RAM image for the nth +// mipmap level. +//////////////////////////////////////////////////////////////////// +void Texture:: +clear_ram_mipmap_image(int n) { + if (n >= (int)_ram_images.size()) { + return; + } + _ram_images[n]._image.clear(); + _ram_images[n]._page_size = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::clear_ram_mipmap_images +// Access: Published +// Description: Discards the current system-RAM image for all +// mipmap levels, except level 0 (the base image). +//////////////////////////////////////////////////////////////////// +void Texture:: +clear_ram_mipmap_images() { + if (!_ram_images.empty()) { + _ram_images.erase(_ram_images.begin() + 1, _ram_images.end()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::generate_ram_mipmap_images +// Access: Published +// Description: Automatically fills in the n mipmap levels of the +// Texture, based on the texture's source image. This +// requires the texture's ram image to be available in +// system memory. +// +// This call is not normally necessary, since the mipmap +// levels will be generated automatically if needed. +// But there may be certain cases in which you would +// like to call this explicitly. +//////////////////////////////////////////////////////////////////// +void Texture:: +generate_ram_mipmap_images() { + nassertv(has_ram_image()); + nassertv(get_ram_image_compression() == CM_off); + nassertv(get_component_type() != T_float); + clear_ram_mipmap_images(); + + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Generating mipmap levels for " << *this << "\n"; + } + + if (_texture_type == Texture::TT_3d_texture && _z_size != 1) { + // Eek, a 3-D texture. + int x_size = _x_size; + int y_size = _y_size; + int z_size = _z_size; + int n = 0; + while (x_size > 1 || y_size > 1 || z_size > 1) { + _ram_images.push_back(RamImage()); + filter_3d_mipmap_level(_ram_images[n + 1], _ram_images[n], + x_size, y_size, z_size); + x_size = max(x_size >> 1, 1); + y_size = max(y_size >> 1, 1); + z_size = max(z_size >> 1, 1); + ++n; + } + + } else { + // A 1-D, 2-D, or cube map texture. + int x_size = _x_size; + int y_size = _y_size; + int n = 0; + while (x_size > 1 || y_size > 1) { + _ram_images.push_back(RamImage()); + filter_2d_mipmap_pages(_ram_images[n + 1], _ram_images[n], + x_size, y_size); + x_size = max(x_size >> 1, 1); + y_size = max(y_size >> 1, 1); + ++n; + } + } +} + //////////////////////////////////////////////////////////////////// // Function: Texture::prepare // Access: Published @@ -1614,13 +1387,33 @@ write(ostream &out, int indent_level) const { << ", border " << get_border_color() << "\n"; - indent(out, indent_level + 2); if (has_ram_image()) { - out << get_ram_image_size() << " bytes in ram, compression " - << get_ram_image_compression() << "\n"; + indent(out, indent_level + 2) + << get_ram_image_size() << " bytes in ram, compression " + << get_ram_image_compression() << "\n"; + int num_ram_mipmap_images = get_num_ram_mipmap_images(); + if (num_ram_mipmap_images > 1) { + int count = 0; + size_t total_size = 0; + for (int n = 1; n < num_ram_mipmap_images; ++n) { + if (has_ram_mipmap_image(n)) { + ++count; + total_size += get_ram_mipmap_image_size(n); + } else { + // Stop at the first gap. + break; + } + } + indent(out, indent_level + 2) + << count + << " mipmap levels also present in ram (" << total_size + << " bytes).\n"; + } + } else { - out << "no ram image\n"; + indent(out, indent_level + 2) + << "no ram image\n"; } } @@ -1697,7 +1490,7 @@ set_component_type(Texture::ComponentType component_type) { //////////////////////////////////////////////////////////////////// // Function: Texture::is_mipmap -// Access: Public, Static +// Access: Published, Static // Description: Returns true if the indicated filter type requires // the use of mipmaps, or false if it does not. //////////////////////////////////////////////////////////////////// @@ -1753,7 +1546,7 @@ prepare_now(PreparedGraphicsObjects *prepared_objects, gobj_cat.debug() << "Dumping RAM for texture " << get_name() << "\n"; } - _ram_image.clear(); + clear_ram_image(); } } return tc; @@ -1856,6 +1649,527 @@ make_texture() { return new Texture; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_read +// Access: Protected, Virtual +// Description: The internal implementation of the various read() +// methods. +//////////////////////////////////////////////////////////////////// +bool Texture:: +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) { + if ((z == 0 || read_pages) && (n == 0 || read_mipmaps)) { + // When we re-read the page 0 of the base image, we clear + // everything and start over. + clear_ram_image(); + } + + if (is_txo_filename(fullpath)) { + return read_txo_file(fullpath); + } + + // If read_pages or read_mipmaps is specified, then z and n actually + // indicate z_size and n_size, respectively--the numerical limits on + // which to search for filenames. + int z_size = z; + int n_size = n; + + // Certain texture types have an implicit z_size. If z_size is + // omitted, choose an appropriate default based on the texture + // type. + if (z_size == 0) { + switch (_texture_type) { + case TT_1d_texture: + case TT_2d_texture: + z_size = 1; + break; + + case TT_cube_map: + z_size = 6; + break; + + default: + break; + } + } + + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + + if (read_pages && read_mipmaps) { + // Read a sequence of pages * mipmap levels. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath); + set_z_size(z_size); + + n = 0; + while (true) { + // For mipmap level 0, the total number of pages might be + // determined by the number of files we find. After mipmap + // level 0, though, the number of pages is predetermined. + if (n != 0) { + z_size = get_expected_mipmap_z_size(n); + } + + z = 0; + + Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z)); + Filename alpha_n_pattern = Filename::pattern_filename(alpha_fullpath_pattern.get_filename_index(z)); + + if (!n_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires two different hash sequences: " << fullpath + << "\n"; + return false; + } + + Filename file = n_pattern.get_filename_index(n); + Filename alpha_file = alpha_n_pattern.get_filename_index(n); + + if ((n_size == 0 && (vfs->exists(file) || n == 0)) || + (n_size != 0 && n < n_size)) { + // Continue through the loop. + } else { + // We've reached the end of the mipmap sequence. + break; + } + + while ((z_size == 0 && (vfs->exists(file) || z == 0)) || + (z_size != 0 && z < z_size)) { + if (!do_read_one(file, alpha_file, z, n, primary_file_num_channels, + alpha_file_channel)) { + return false; + } + ++z; + + n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z)); + file = n_pattern.get_filename_index(n); + alpha_file = alpha_n_pattern.get_filename_index(n); + } + + if (n == 0 && n_size == 0) { + // If n_size is not specified, it gets implicitly set after we + // read the base texture image (which determines the size of + // the texture). + n_size = get_expected_num_mipmap_levels(); + } + ++n; + } + + } else if (read_pages) { + // Read a sequence of cube map or 3-D texture pages. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath); + if (!fullpath_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires a hash mark: " << fullpath + << "\n"; + return false; + } + + set_z_size(z_size); + z = 0; + Filename file = fullpath_pattern.get_filename_index(z); + Filename alpha_file = alpha_fullpath_pattern.get_filename_index(z); + while ((z_size == 0 && (vfs->exists(file) || z == 0)) || + (z_size != 0 && z < z_size)) { + if (!do_read_one(file, alpha_file, z, 0, primary_file_num_channels, + alpha_file_channel)) { + return false; + } + ++z; + + file = fullpath_pattern.get_filename_index(z); + alpha_file = alpha_fullpath_pattern.get_filename_index(z); + } + + } else if (read_mipmaps) { + // Read a sequence of mipmap levels. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath); + if (!fullpath_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires a hash mark: " << fullpath + << "\n"; + return false; + } + + n = 0; + Filename file = fullpath_pattern.get_filename_index(n); + Filename alpha_file = alpha_fullpath_pattern.get_filename_index(n); + while ((n_size == 0 && (vfs->exists(file) || n == 0)) || + (n_size != 0 && n < n_size)) { + if (!do_read_one(file, alpha_file, z, n, + primary_file_num_channels, alpha_file_channel)) { + return false; + } + if (n == 0 && n_size == 0) { + // If n_size is not specified, it gets implicitly set after we + // read the base texture image (which determines the size of + // the texture). + n_size = get_expected_num_mipmap_levels(); + } + ++n; + + file = fullpath_pattern.get_filename_index(n); + alpha_file = alpha_fullpath_pattern.get_filename_index(n); + } + + } else { + // Just an ordinary read of one file. + if (!do_read_one(fullpath, alpha_fullpath, z, n, + primary_file_num_channels, alpha_file_channel)) { + return false; + } + } + + _has_read_pages = read_pages; + _has_read_mipmaps = read_mipmaps; + _num_mipmap_levels_read = _ram_images.size(); + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_read_one +// Access: Protected, Virtual +// Description: Called only from do_read(), this method reads a +// single image file, either one page or one mipmap +// level. +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, + int z, int n, int primary_file_num_channels, int alpha_file_channel) { + PNMImage image; + if (textures_header_only) { + if (!image.read_header(fullpath)) { + gobj_cat.error() + << "Texture::read() - couldn't read: " << fullpath << endl; + return false; + } + image = PNMImage(1, 1, image.get_num_channels(), image.get_maxval(), + image.get_type()); + image.fill(0.2, 0.3, 1.0); + if (image.has_alpha()) { + image.alpha_fill(1.0); + } + + } else { + if (!image.read(fullpath, NULL, false)) { + gobj_cat.error() + << "Texture::read() - couldn't read: " << fullpath << endl; + return false; + } + } + + PNMImage alpha_image; + if (!alpha_fullpath.empty()) { + if (textures_header_only) { + if (!alpha_image.read_header(alpha_fullpath)) { + gobj_cat.error() + << "Texture::read() - couldn't read: " << alpha_fullpath << endl; + return false; + } + alpha_image = PNMImage(1, 1, alpha_image.get_num_channels(), + alpha_image.get_maxval(), + alpha_image.get_type()); + alpha_image.fill(1.0); + if (alpha_image.has_alpha()) { + alpha_image.alpha_fill(1.0); + } + + } else { + if (!alpha_image.read(alpha_fullpath, NULL, true)) { + gobj_cat.error() + << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; + return false; + } + } + } + + if (z == 0 && n == 0) { + if (!has_name()) { + set_name(fullpath.get_basename_wo_extension()); + } + if (!has_filename()) { + set_filename(fullpath); + set_alpha_filename(alpha_fullpath); + + // The first time we set the filename via a read() operation, we + // clear keep_ram_image. The user can always set it again later + // if he needs to. + _keep_ram_image = false; + } + + set_fullpath(fullpath); + set_alpha_fullpath(alpha_fullpath); + + consider_rescale(image); + } + + if (!alpha_fullpath.empty()) { + // The grayscale (alpha channel) image must be the same size as the + // main image. + if (image.get_x_size() != alpha_image.get_x_size() || + image.get_y_size() != alpha_image.get_y_size()) { + gobj_cat.info() + << "Automatically rescaling " << alpha_fullpath.get_basename() + << " from " << alpha_image.get_x_size() << " by " + << alpha_image.get_y_size() << " to " << image.get_x_size() + << " by " << image.get_y_size() << "\n"; + + PNMImage scaled(image.get_x_size(), image.get_y_size(), + alpha_image.get_num_channels(), + alpha_image.get_maxval(), alpha_image.get_type()); + scaled.quick_filter_from(alpha_image); + alpha_image = scaled; + } + } + + if (n == 0) { + consider_downgrade(image, primary_file_num_channels); + _primary_file_num_channels = image.get_num_channels(); + _alpha_file_channel = 0; + } + + if (!alpha_fullpath.empty()) { + // Make the original image a 4-component image by taking the + // grayscale value from the second image. + image.add_alpha(); + + if (alpha_file_channel == 4 || + (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) { + // Use the alpha channel. + for (int x = 0; x < image.get_x_size(); x++) { + for (int y = 0; y < image.get_y_size(); y++) { + image.set_alpha(x, y, alpha_image.get_alpha(x, y)); + } + } + _alpha_file_channel = alpha_image.get_num_channels(); + + } else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 && + alpha_image.get_num_channels() >= 3) { + // Use the appropriate red, green, or blue channel. + for (int x = 0; x < image.get_x_size(); x++) { + for (int y = 0; y < image.get_y_size(); y++) { + image.set_alpha(x, y, alpha_image.get_channel_val(x, y, alpha_file_channel - 1)); + } + } + _alpha_file_channel = alpha_file_channel; + + } else { + // Use the grayscale channel. + for (int x = 0; x < image.get_x_size(); x++) { + for (int y = 0; y < image.get_y_size(); y++) { + image.set_alpha(x, y, alpha_image.get_gray(x, y)); + } + } + _alpha_file_channel = 0; + } + } + + return do_load_one(image, z, n); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_write +// Access: Protected +// Description: Internal method to write a series of pages and/or +// mipmap levels to disk files. +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_write(const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) const { + if (!has_ram_image()) { + ((Texture *)this)->get_ram_image(); + } + nassertr(has_ram_image(), false); + + if (is_txo_filename(fullpath)) { + return write_txo_file(fullpath); + } + + nassertr(has_ram_mipmap_image(n), false); + nassertr(get_ram_image_compression() == CM_off, false); + + if (write_pages && write_mipmaps) { + // Write a sequence of pages * mipmap levels. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + int num_levels = get_num_ram_mipmap_images(); + + for (int n = 0; n < num_levels; ++n) { + int z_size = get_expected_mipmap_z_size(n); + + for (z = 0; z < z_size; ++z) { + Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z)); + + if (!n_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires two different hash sequences: " << fullpath + << "\n"; + return false; + } + + if (!do_write_one(n_pattern.get_filename_index(n), z, n)) { + return false; + } + } + } + + } else if (write_pages) { + // Write a sequence of pages. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + if (!fullpath_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires a hash mark: " << fullpath + << "\n"; + return false; + } + + for (z = 0; z < _z_size; ++z) { + if (!do_write_one(fullpath_pattern.get_filename_index(z), z, n)) { + return false; + } + } + + } else if (write_mipmaps) { + // Write a sequence of mipmap images. + Filename fullpath_pattern = Filename::pattern_filename(fullpath); + if (!fullpath_pattern.has_hash()) { + gobj_cat.error() + << "Filename requires a hash mark: " << fullpath + << "\n"; + return false; + } + + int num_levels = get_num_ram_mipmap_images(); + for (int n = 0; n < num_levels; ++n) { + if (!do_write_one(fullpath_pattern.get_filename_index(n), z, n)) { + return false; + } + } + + } else { + // Write a single file. + if (!do_write_one(fullpath, z, n)) { + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_write_one +// Access: Protected +// Description: Internal method to write the indicated page and +// mipmap level to a disk image file. +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_write_one(const Filename &fullpath, int z, int n) const { + if (!has_ram_mipmap_image(n)) { + return false; + } + + nassertr(get_ram_image_compression() == CM_off, false); + + PNMImage pnmimage; + if (!do_store_one(pnmimage, z, n)) { + return false; + } + + if (!pnmimage.write(fullpath)) { + gobj_cat.error() + << "Texture::write() - couldn't write: " << fullpath << endl; + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_load_one +// Access: Protected, Virtual +// Description: Internal method to load a single page or mipmap +// level. +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_load_one(const PNMImage &pnmimage, int z, int n) { + if (_ram_images.size() <= 1 && n == 0) { + // A special case for mipmap level 0. When we load mipmap level + // 0, unless we already have mipmap levels, it determines the + // image properties like size and number of components. + if (!reconsider_z_size(z)) { + return false; + } + nassertr(z >= 0 && z < _z_size, false); + + ComponentType component_type = T_unsigned_byte; + xelval maxval = pnmimage.get_maxval(); + if (maxval > 255) { + component_type = T_unsigned_short; + } + + if (!reconsider_image_properties(pnmimage.get_x_size(), pnmimage.get_y_size(), + pnmimage.get_num_channels(), component_type, + z)) { + return false; + } + + modify_ram_image(); + _loaded_from_image = true; + } + + modify_ram_mipmap_image(n); + + // Ensure the PNMImage is an appropriate size. + int x_size = get_expected_mipmap_x_size(n); + int y_size = get_expected_mipmap_y_size(n); + if (pnmimage.get_x_size() != x_size || + pnmimage.get_y_size() != y_size) { + gobj_cat.info() + << "Automatically rescaling " << get_name() << " mipmap level " + << n << " from " << pnmimage.get_x_size() << " by " + << pnmimage.get_y_size() << " to " << x_size << " by " + << y_size << "\n"; + + PNMImage scaled(x_size, y_size, pnmimage.get_num_channels(), + pnmimage.get_maxval(), pnmimage.get_type()); + scaled.quick_filter_from(pnmimage); + + convert_from_pnmimage(_ram_images[n]._image, + get_expected_ram_mipmap_page_size(n), z, + scaled); + } else { + // Now copy the pixel data from the PNMImage into our internal + // _image component. + convert_from_pnmimage(_ram_images[n]._image, + get_expected_ram_mipmap_page_size(n), z, + pnmimage); + } + + ++_modified; + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_store_one +// Access: Protected +// Description: Internal method to copy a page and/or mipmap level to +// a PNMImage. +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_store_one(PNMImage &pnmimage, int z, int n) const { + nassertr(has_ram_mipmap_image(n), false); + nassertr(z >= 0 && z < get_expected_mipmap_z_size(n), false); + nassertr(_ram_image_compression == CM_off, false); + + return convert_to_pnmimage(pnmimage, + get_expected_mipmap_x_size(n), + get_expected_mipmap_y_size(n), + _ram_images[n]._image, + get_ram_mipmap_page_size(n), z); +} + //////////////////////////////////////////////////////////////////// // Function: Texture::reconsider_dirty // Access: Protected, Virtual @@ -1881,19 +2195,19 @@ reload_ram_image() { make_ram_image(); - if (_texture_type == TT_1d_texture || _texture_type == TT_2d_texture) { - // 1-d or 2-d texture. Just one page. - if (has_alpha_fullpath()) { - read(get_fullpath(), get_alpha_fullpath(), - 0, _primary_file_num_channels, _alpha_file_channel); - } else { - read(get_fullpath(), 0, _primary_file_num_channels); - } - - } else { - // 3-d texture or cube map. Multiple pages. - read_pages(get_fullpath(), _z_size); + int z = 0; + int n = 0; + + if (_has_read_pages) { + z = _z_size; } + if (_has_read_mipmaps) { + n = _num_mipmap_levels_read; + } + + do_read(get_fullpath(), get_alpha_fullpath(), + _primary_file_num_channels, _alpha_file_channel, + z, n, _has_read_pages, _has_read_mipmaps); } @@ -1991,9 +2305,11 @@ reconsider_z_size(int z) { // Increase the size of the data buffer to make room for the new // texture level. size_t new_size = get_expected_ram_image_size(); - if (!_ram_image.is_null() && new_size > _ram_image.size()) { - _ram_image.insert(_ram_image.end(), new_size - _ram_image.size(), 0); - nassertr(_ram_image.size() == new_size, false); + if (!_ram_images.empty() && + !_ram_images[0]._image.empty() && + new_size > _ram_images[0]._image.size()) { + _ram_images[0]._image.insert(_ram_images[0]._image.end(), new_size - _ram_images[0]._image.size(), 0); + nassertr(_ram_images[0]._image.size() == new_size, false); } } @@ -2010,7 +2326,7 @@ reconsider_z_size(int z) { bool Texture:: reconsider_image_properties(int x_size, int y_size, int num_components, Texture::ComponentType component_type, int z) { - if (!_loaded_from_disk || num_components != _num_components) { + if (!_loaded_from_image || num_components != _num_components) { // Come up with a default format based on the number of channels. // But only do this the first time the file is loaded, or if the // number of channels in the image changes on subsequent loads. @@ -2039,7 +2355,7 @@ reconsider_image_properties(int x_size, int y_size, int num_components, } } - if (!_loaded_from_disk) { + if (!_loaded_from_image) { #ifndef NDEBUG if (_texture_type == TT_1d_texture) { nassertr(y_size == 1, false); @@ -2067,6 +2383,185 @@ reconsider_image_properties(int x_size, int y_size, int num_components, return true; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::convert_from_pnmimage +// Access: Private +// Description: Internal method to convert pixel data from the +// indicated PNMImage into the given ram_image. +//////////////////////////////////////////////////////////////////// +void Texture:: +convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z, + const PNMImage &pnmimage) { + int x_size = pnmimage.get_x_size(); + int y_size = pnmimage.get_y_size(); + xelval maxval = pnmimage.get_maxval(); + + bool is_grayscale = (_num_components == 1 || _num_components == 2); + bool has_alpha = (_num_components == 2 || _num_components == 4); + bool img_has_alpha = pnmimage.has_alpha(); + + int idx = page_size * z; + nassertv(idx + page_size <= image.size()); + unsigned char *p = &image[idx]; + + if (maxval == 255) { + // Most common case: one byte per pixel, and the source image + // shows a maxval of 255. No scaling is necessary. + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + store_unscaled_byte(p, pnmimage.get_gray_val(i, j)); + } else { + store_unscaled_byte(p, pnmimage.get_blue_val(i, j)); + store_unscaled_byte(p, pnmimage.get_green_val(i, j)); + store_unscaled_byte(p, pnmimage.get_red_val(i, j)); + } + if (has_alpha) { + if (img_has_alpha) { + store_unscaled_byte(p, pnmimage.get_alpha_val(i, j)); + } else { + store_unscaled_byte(p, 255); + } + } + } + } + + } else if (maxval == 65535) { + // Another possible case: two bytes per pixel, and the source + // image shows a maxval of 65535. Again, no scaling is necessary. + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + store_unscaled_short(p, pnmimage.get_gray_val(i, j)); + } else { + store_unscaled_short(p, pnmimage.get_blue_val(i, j)); + store_unscaled_short(p, pnmimage.get_green_val(i, j)); + store_unscaled_short(p, pnmimage.get_red_val(i, j)); + } + if (has_alpha) { + if (img_has_alpha) { + store_unscaled_short(p, pnmimage.get_alpha_val(i, j)); + } else { + store_unscaled_short(p, 65535); + } + } + } + } + + } else if (maxval <= 255) { + // A less common case: one byte per pixel, but the maxval is + // something other than 255. In this case, we should scale the + // pixel values up to the appropriate amount. + double scale = 255.0 / (double)maxval; + + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + store_scaled_byte(p, pnmimage.get_gray_val(i, j), scale); + } else { + store_scaled_byte(p, pnmimage.get_blue_val(i, j), scale); + store_scaled_byte(p, pnmimage.get_green_val(i, j), scale); + store_scaled_byte(p, pnmimage.get_red_val(i, j), scale); + } + if (has_alpha) { + if (img_has_alpha) { + store_scaled_byte(p, pnmimage.get_alpha_val(i, j), scale); + } else { + store_unscaled_byte(p, 255); + } + } + } + } + + } else { + // Another uncommon case: two bytes per pixel, and the maxval is + // something other than 65535. Again, we must scale the pixel + // values. + double scale = 65535.0 / (double)maxval; + + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + store_scaled_short(p, pnmimage.get_gray_val(i, j), scale); + } else { + store_scaled_short(p, pnmimage.get_blue_val(i, j), scale); + store_scaled_short(p, pnmimage.get_green_val(i, j), scale); + store_scaled_short(p, pnmimage.get_red_val(i, j), scale); + } + if (has_alpha) { + if (img_has_alpha) { + store_scaled_short(p, pnmimage.get_alpha_val(i, j), 1.0); + } else { + store_unscaled_short(p, 65535); + } + } + } + } + } + + nassertv(p == &image[idx] + page_size); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::convert_to_pnmimage +// Access: Private +// Description: Internal method to convert pixel data to the +// indicated PNMImage from the given ram_image. +//////////////////////////////////////////////////////////////////// +bool Texture:: +convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size, + CPTA_uchar image, size_t page_size, int z) const { + pnmimage.clear(x_size, y_size, _num_components); + bool has_alpha = pnmimage.has_alpha(); + bool is_grayscale = pnmimage.is_grayscale(); + + int idx = page_size * z; + nassertr(idx + page_size <= image.size(), false); + const unsigned char *p = &image[idx]; + + if (_component_type == T_unsigned_byte) { + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + pnmimage.set_gray(i, j, get_unsigned_byte(p)); + } else { + pnmimage.set_blue(i, j, get_unsigned_byte(p)); + pnmimage.set_green(i, j, get_unsigned_byte(p)); + pnmimage.set_red(i, j, get_unsigned_byte(p)); + } + if (has_alpha) { + pnmimage.set_alpha(i, j, get_unsigned_byte(p)); + } + } + } + + } else if (_component_type == T_unsigned_short) { + for (int j = y_size-1; j >= 0; j--) { + for (int i = 0; i < x_size; i++) { + if (is_grayscale) { + pnmimage.set_gray(i, j, get_unsigned_short(p)); + } else { + pnmimage.set_blue(i, j, get_unsigned_short(p)); + pnmimage.set_green(i, j, get_unsigned_short(p)); + pnmimage.set_red(i, j, get_unsigned_short(p)); + } + if (has_alpha) { + pnmimage.set_alpha(i, j, get_unsigned_short(p)); + } + } + } + + } else { + gobj_cat.error() + << "Couldn't write image for " << get_name() + << "; inappropriate data type " << (int)_component_type << ".\n"; + return false; + } + + nassertr(p == &image[idx] + page_size, false); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::clear_prepared // Access: Private @@ -2174,8 +2669,7 @@ consider_downgrade(PNMImage &pnmimage, int num_channels) { //////////////////////////////////////////////////////////////////// // Function: Texture::read_txo_file // Access: Private -// Description: Called internally when read() or read_pages() detects -// a txo file. +// Description: Called internally when read() detects a txo file. //////////////////////////////////////////////////////////////////// bool Texture:: read_txo_file(const Filename &fullpath) { @@ -2209,8 +2703,8 @@ read_txo_file(const Filename &fullpath) { //////////////////////////////////////////////////////////////////// // Function: Texture::write_txo_file // Access: Private -// Description: Called internally when write() or write_pages() detects -// a txo file. +// Description: Called internally when write() detects a txo +// filename. //////////////////////////////////////////////////////////////////// bool Texture:: write_txo_file(const Filename &fullpath) const { @@ -2231,6 +2725,347 @@ write_txo_file(const Filename &fullpath) const { return write_txo(out, fullpath); } +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_2d_mipmap_pages +// Access: Public +// Description: Generates the next mipmap level from the previous +// one. If there are multiple pages (e.g. a cube map), +// generates each page independently. +// +// x_size and y_size are the size of the previous level. +// They need not be a power of 2, or even a multiple of +// 2. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_2d_mipmap_pages(Texture::RamImage &to, const Texture::RamImage &from, + int x_size, int y_size) { + size_t pixel_size = _num_components * _component_width; + size_t row_size = (size_t)x_size * pixel_size; + + int to_x_size = max(x_size >> 1, 1); + int to_y_size = max(y_size >> 1, 1); + + size_t to_row_size = (size_t)to_x_size * pixel_size; + to._page_size = (size_t)to_y_size * to_row_size; + to._image = PTA_uchar::empty_array(to._page_size * _z_size); + + Filter2DComponent *filter_component = (_component_type == T_unsigned_byte ? &filter_2d_unsigned_byte : filter_2d_unsigned_short); + + for (int z = 0; z < _z_size; ++z) { + // For each level. + unsigned char *p = to._image.p() + z * to._page_size; + const unsigned char *q = from._image.p() + z * from._page_size; + if (y_size != 1) { + int y; + for (y = 0; y < y_size - 1; y += 2) { + // For each row. + nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size); + nassertv(q == from._image.p() + z * from._page_size + y * row_size); + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, row_size); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, row_size); + } + } + q += row_size; + } + if (y < y_size) { + // Skip the last odd row. + q += row_size; + } + } else { + // Just one row. + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, 0); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, 0); + } + } + } + + nassertv(p == to._image.p() + (z + 1) * to._page_size); + nassertv(q == from._image.p() + (z + 1) * from._page_size); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_3d_mipmap_level +// Access: Public +// Description: Generates the next mipmap level from the previous +// one, treating all the pages of the level as a single +// 3-d block of pixels. +// +// x_size, y_size, and z_size are the size of the +// previous level. They need not be a power of 2, or +// even a multiple of 2. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_3d_mipmap_level(Texture::RamImage &to, const Texture::RamImage &from, + int x_size, int y_size, int z_size) { + size_t pixel_size = _num_components * _component_width; + size_t row_size = (size_t)x_size * pixel_size; + size_t page_size = (size_t)y_size * row_size; + + int to_x_size = max(x_size >> 1, 1); + int to_y_size = max(y_size >> 1, 1); + int to_z_size = max(z_size >> 1, 1); + + size_t to_row_size = (size_t)to_x_size * pixel_size; + size_t to_page_size = (size_t)to_y_size * to_row_size; + to._page_size = to_page_size; + to._image = PTA_uchar::empty_array(to_page_size * to_z_size); + + Filter3DComponent *filter_component = (_component_type == T_unsigned_byte ? &filter_3d_unsigned_byte : filter_3d_unsigned_short); + + unsigned char *p = to._image.p(); + const unsigned char *q = from._image.p(); + if (z_size != 1) { + int z; + for (z = 0; z < z_size - 1; z += 2) { + // For each level. + nassertv(p == to._image.p() + (z / 2) * to_page_size); + nassertv(q == from._image.p() + z * page_size); + if (y_size != 1) { + int y; + for (y = 0; y < y_size - 1; y += 2) { + // For each row. + nassertv(p == to._image.p() + (z / 2) * to_page_size + (y / 2) * to_row_size); + nassertv(q == from._image.p() + z * page_size + y * row_size); + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, row_size, page_size); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, row_size, page_size); + } + } + q += row_size; + } + if (y < y_size) { + // Skip the last odd row. + q += row_size; + } + } else { + // Just one row. + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, 0, page_size); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, 0, page_size); + } + } + } + q += page_size; + } + if (z < z_size) { + // Skip the last odd page. + q += page_size; + } + } else { + // Just one page. + if (y_size != 1) { + int y; + for (y = 0; y < y_size - 1; y += 2) { + // For each row. + nassertv(p == to._image.p() + (y / 2) * to_row_size); + nassertv(q == from._image.p() + y * row_size); + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, row_size, 0); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, row_size, 0); + } + } + q += row_size; + } + if (y < y_size) { + // Skip the last odd row. + q += row_size; + } + } else { + // Just one row. + if (x_size != 1) { + int x; + for (x = 0; x < x_size - 1; x += 2) { + // For each pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, pixel_size, 0, 0); + } + q += pixel_size; + } + if (x < x_size) { + // Skip the last odd pixel. + q += pixel_size; + } + } else { + // Just one pixel. + for (int c = 0; c < _num_components; ++c) { + // For each component. + filter_component(p, q, 0, 0, 0); + } + } + } + } + + nassertv(p == to._image.p() + to_z_size * to_page_size); + nassertv(q == from._image.p() + z_size * page_size); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_2d_unsigned_byte +// Access: Public, Static +// Description: Averages a 2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size) { + unsigned int result = ((unsigned int)q[0] + + (unsigned int)q[pixel_size] + + (unsigned int)q[row_size] + + (unsigned int)q[pixel_size + row_size]) >> 2; + *p = (unsigned char)result; + ++p; + ++q; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_2d_unsigned_short +// Access: Public, Static +// Description: Averages a 2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_2d_unsigned_short(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size) { + unsigned int result = ((unsigned int)*(unsigned short *)&q[0] + + (unsigned int)*(unsigned short *)&q[pixel_size] + + (unsigned int)*(unsigned short *)&q[row_size] + + (unsigned int)*(unsigned short *)&q[pixel_size + row_size]) >> 2; + store_unscaled_short(p, result); + q += 2; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_3d_unsigned_byte +// Access: Public, Static +// Description: Averages a 2x2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size, size_t page_size) { + unsigned int result = ((unsigned int)q[0] + + (unsigned int)q[pixel_size] + + (unsigned int)q[row_size] + + (unsigned int)q[pixel_size + row_size] + + (unsigned int)q[page_size] + + (unsigned int)q[pixel_size + page_size] + + (unsigned int)q[row_size + page_size] + + (unsigned int)q[pixel_size + row_size + page_size]) >> 3; + *p = (unsigned char)result; + ++p; + ++q; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_3d_unsigned_short +// Access: Public, Static +// Description: Averages a 2x2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size, + size_t page_size) { + unsigned int result = ((unsigned int)*(unsigned short *)&q[0] + + (unsigned int)*(unsigned short *)&q[pixel_size] + + (unsigned int)*(unsigned short *)&q[row_size] + + (unsigned int)*(unsigned short *)&q[pixel_size + row_size] + + (unsigned int)*(unsigned short *)&q[page_size] + + (unsigned int)*(unsigned short *)&q[pixel_size + page_size] + + (unsigned int)*(unsigned short *)&q[row_size + page_size] + + (unsigned int)*(unsigned short *)&q[pixel_size + row_size + page_size]) >> 3; + store_unscaled_short(p, result); + q += 2; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::register_with_read_factory // Access: Public, Static @@ -2380,21 +3215,34 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) { _component_type = (ComponentType)scan.get_uint8(); _component_width = scan.get_uint8(); _ram_image_compression = CM_off; - _ram_page_size = 0; if (manager->get_file_minor_ver() >= 1) { _ram_image_compression = (CompressionMode)scan.get_uint8(); - _ram_page_size = scan.get_uint32(); } - _loaded_from_disk = false; - PN_uint32 u_size = scan.get_uint32(); - - // fill the _image buffer with image data - string temp_buff = scan.extract_bytes(u_size); - _ram_image = PTA_uchar::empty_array((int) u_size); - for (PN_uint32 u_idx=0; u_idx < u_size; ++u_idx) { - _ram_image[(int)u_idx] = (uchar) temp_buff[u_idx]; + int num_ram_images = 1; + if (manager->get_file_minor_ver() >= 3) { + num_ram_images = scan.get_uint8(); } + + _ram_images.clear(); + _ram_images.reserve(num_ram_images); + for (int n = 0; n < num_ram_images; ++n) { + _ram_images.push_back(RamImage()); + _ram_images[n]._page_size = 0; + if (manager->get_file_minor_ver() >= 1) { + _ram_images[n]._page_size = scan.get_uint32(); + } + + size_t u_size = scan.get_uint32(); + + // fill the _image buffer with image data + PTA_uchar image = PTA_uchar::empty_array(u_size); + for (size_t u_idx = 0; u_idx < u_size; ++u_idx) { + image[(int)u_idx] = scan.get_uint8(); + } + _ram_images[n]._image = image; + } + _loaded_from_image = true; } } @@ -2481,7 +3329,7 @@ write_datagram(BamWriter *manager, Datagram &me) { me.add_string(alpha_filename); me.add_uint8(_primary_file_num_channels); me.add_uint8(_alpha_file_channel); - me.add_bool(has_rawdata); + me.add_uint8(has_rawdata); me.add_uint8(_texture_type); // The data beginning at this point is handled by fillin(). @@ -2506,10 +3354,12 @@ write_datagram(BamWriter *manager, Datagram &me) { me.add_uint8(_component_type); me.add_uint8(_component_width); me.add_uint8(_ram_image_compression); - me.add_uint32(_ram_page_size); - - me.add_uint32(_ram_image.size()); - me.append_data(_ram_image, _ram_image.size()); + me.add_uint8(_ram_images.size()); + for (size_t n = 0; n < _ram_images.size(); ++n) { + me.add_uint32(_ram_images[n]._page_size); + me.add_uint32(_ram_images[n]._image.size()); + me.append_data(_ram_images[n]._image, _ram_images[n]._image.size()); + } } } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 9dd673579d..faad44af6c 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -146,7 +146,7 @@ PUBLISHED: }; enum CompressionMode { - // Generic compresssion modes. Usually, you should choose one of + // Generic compression modes. Usually, you should choose one of // these. CM_default, // on or off, according to compressed-textures CM_off, // uncompressed image @@ -174,6 +174,7 @@ PUBLISHED: virtual ~Texture(); virtual PT(Texture) make_copy(); + virtual void clear(); void setup_texture(TextureType texture_type, int x_size, int y_size, int z_size, @@ -194,21 +195,26 @@ PUBLISHED: 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 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; @@ -252,6 +258,11 @@ PUBLISHED: INLINE bool get_render_to_texture() 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; INLINE bool might_have_ram_image() const; INLINE size_t get_ram_image_size() const; @@ -268,6 +279,21 @@ PUBLISHED: INLINE void set_keep_ram_image(bool keep_ram_image); 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; void prepare(PreparedGraphicsObjects *prepared_objects); @@ -297,18 +323,18 @@ PUBLISHED: INLINE void set_z_size(int z_size); void set_format(Format format); 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 bool get_loaded_from_txo() const; + static bool is_mipmap(FilterType type); + public: INLINE bool get_match_framebuffer_format() const; INLINE void set_match_framebuffer_format(bool flag); - static bool is_mipmap(FilterType type); - TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg); @@ -328,6 +354,18 @@ public: static bool has_alpha(Format format); 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 reload_ram_image(); @@ -335,23 +373,65 @@ protected: bool reconsider_image_properties(int x_size, int y_size, int num_components, ComponentType component_type, int z); + // This nested class declaration is used below. + class RamImage { + public: + PTA_uchar _image; + size_t _page_size; + }; + 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 consider_rescale(PNMImage &pnmimage); 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); bool read_txo_file(const Filename &fullpath); 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: Filename _filename; Filename _alpha_filename; @@ -376,8 +456,11 @@ protected: Format _format; ComponentType _component_type; - bool _loaded_from_disk; + bool _loaded_from_image; bool _loaded_from_txo; + bool _has_read_pages; + bool _has_read_mipmaps; + int _num_mipmap_levels_read; WrapMode _wrap_u; WrapMode _wrap_v; @@ -407,9 +490,13 @@ protected: typedef pmap RelatedTextures; RelatedTextures _related_textures; - PTA_uchar _ram_image; 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 RamImages; + RamImages _ram_images; UpdateSeq _modified; diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index af7816bab7..802d4304a1 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -51,10 +51,17 @@ verify_texture(const string &filename) { // If a texture with the same filename was previously // loaded, returns that one instead. If the texture // 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:: -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 // loaded, returns that one instead. If the texture // 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:: 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, - 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 // of one or more hash characters ("#") which will be // 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:: -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 // hash characters ("#") which will be filled in with // 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:: -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); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index bee2ae7b2c..6bd211307a 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -206,7 +206,8 @@ ns_has_texture(const Filename &orig_filename) { // Description: The nonstatic implementation of load_texture(). //////////////////////////////////////////////////////////////////// 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); if (!_fake_texture_image.empty()) { @@ -227,7 +228,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels) { gobj_cat.info() << "Loading texture " << filename << "\n"; 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. report_texture_unreadable(filename); return NULL; @@ -249,12 +250,14 @@ Texture *TexturePool:: ns_load_texture(const Filename &orig_filename, const Filename &orig_alpha_filename, int primary_file_num_channels, - int alpha_file_channel) { + int alpha_file_channel, + bool read_mipmaps) { Filename filename(orig_filename); Filename alpha_filename(orig_alpha_filename); 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(); @@ -275,8 +278,8 @@ ns_load_texture(const Filename &orig_filename, << "Loading texture " << filename << " and alpha component " << alpha_filename << endl; 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. report_texture_unreadable(filename); return NULL; @@ -296,7 +299,8 @@ ns_load_texture(const Filename &orig_filename, // Description: The nonstatic implementation of load_3d_texture(). //////////////////////////////////////////////////////////////////// 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.set_pattern(true); @@ -315,7 +319,7 @@ ns_load_3d_texture(const Filename &filename_pattern) { << "Loading 3-d texture " << filename << "\n"; PT(Texture) tex = make_texture(filename.get_extension()); 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. report_texture_unreadable(filename); return NULL; @@ -334,7 +338,7 @@ ns_load_3d_texture(const Filename &filename_pattern) { // Description: The nonstatic implementation of load_cube_map(). //////////////////////////////////////////////////////////////////// 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.set_pattern(true); @@ -353,7 +357,7 @@ ns_load_cube_map(const Filename &filename_pattern) { << "Loading cube map texture " << filename << "\n"; PT(Texture) tex = make_texture(filename.get_extension()); 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. report_texture_unreadable(filename); return NULL; diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index 94738a4bb4..fd6f71bcfc 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -42,13 +42,17 @@ PUBLISHED: INLINE static bool has_texture(const string &filename); INLINE static bool verify_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, const string &alpha_filename, 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); @@ -81,13 +85,18 @@ private: TexturePool(); 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, const Filename &orig_alpha_filename, 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); void ns_add_texture(Texture *texture); diff --git a/panda/src/gobj/textureStage.I b/panda/src/gobj/textureStage.I index 61fa2272c4..be1c7e0478 100755 --- a/panda/src/gobj/textureStage.I +++ b/panda/src/gobj/textureStage.I @@ -263,13 +263,10 @@ get_alpha_scale() const { // Function: TextureStage::set_saved_result // Access: Published // 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 // stage as input to more than one stage later in the diff --git a/panda/src/gobj/videoTexture.cxx b/panda/src/gobj/videoTexture.cxx index ee7bd01252..a0e00f50cc 100644 --- a/panda/src/gobj/videoTexture.cxx +++ b/panda/src/gobj/videoTexture.cxx @@ -72,7 +72,7 @@ has_ram_image() const { if (this_frame != _last_frame_update) { 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:: get_keep_ram_image() const { - // An VideoTexture should never dump its RAM image. + // A VideoTexture should never dump its RAM image. return true; } diff --git a/panda/src/grutil/openCVTexture.cxx b/panda/src/grutil/openCVTexture.cxx index 7f1910861d..45b86fe408 100644 --- a/panda/src/grutil/openCVTexture.cxx +++ b/panda/src/grutil/openCVTexture.cxx @@ -103,136 +103,12 @@ from_camera(int camera_index, int z) { return false; } - set_loaded_from_disk(); + set_loaded_from_image(); clear_current_frame(); 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 // Access: Private @@ -295,7 +171,7 @@ reconsider_video_properties(const OpenCVTexture::VideoStream &stream, return false; } - if (_loaded_from_disk && + if (_loaded_from_image && (get_video_width() != width || get_video_height() != height || get_num_frames() != num_frames || get_frame_rate() != frame_rate)) { grutil_cat.error() @@ -334,6 +210,7 @@ make_texture() { //////////////////////////////////////////////////////////////////// void OpenCVTexture:: update_frame(int frame) { + nassertv(has_ram_image()); int max_z = max(_z_size, (int)_pages.size()); for (int z = 0; z < max_z; ++z) { VideoPage &page = _pages[z]; @@ -346,7 +223,7 @@ update_frame(int frame) { const unsigned char *source = page._color.get_frame_data(frame); if (source != NULL) { 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 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); if (source != NULL) { 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 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 // Access: Public, Static diff --git a/panda/src/grutil/openCVTexture.h b/panda/src/grutil/openCVTexture.h index b438812e92..011d379af1 100644 --- a/panda/src/grutil/openCVTexture.h +++ b/panda/src/grutil/openCVTexture.h @@ -47,19 +47,17 @@ PUBLISHED: 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: static PT(Texture) make_texture(); protected: 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: class VideoPage; class VideoStream; diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 7484def3b5..b2bcc66d84 100644 --- a/panda/src/putil/bam.h +++ b/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 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 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 diff --git a/pandatool/src/bam/eggToBam.cxx b/pandatool/src/bam/eggToBam.cxx index e5a0c53a5d..d410c2e5e6 100644 --- a/pandatool/src/bam/eggToBam.cxx +++ b/pandatool/src/bam/eggToBam.cxx @@ -118,7 +118,7 @@ EggToBam() : "stored uncompressed. A particular texture that is encoded 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 " - "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.", &EggToBam::dispatch_none, &_tex_rawdata); @@ -162,6 +162,16 @@ EggToBam() : "on the particular graphics card that was used to generate them.", &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 ("load-display", "display name", 0, "Specifies the particular display module to load to perform the texture " @@ -241,10 +251,20 @@ run() { if (_tex_ctex) { tex->set_keep_ram_image(true); tex->set_compression(Texture::CM_on); + bool has_mipmap_levels = (tex->get_num_ram_mipmap_images() > 1); if (!_engine->extract_texture_data(tex, _gsg)) { 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) { convert_txo(tex); } diff --git a/pandatool/src/bam/eggToBam.h b/pandatool/src/bam/eggToBam.h index 3f8988f782..ff51b4d0f7 100644 --- a/pandatool/src/bam/eggToBam.h +++ b/pandatool/src/bam/eggToBam.h @@ -69,6 +69,7 @@ private: bool _tex_txo; bool _tex_txopz; bool _tex_ctex; + bool _tex_mipmap; string _load_display; // The rest of this is required to support -ctex.