next up previous contents
Next: Bibliography Up: No Title Previous: 6.3 Shader Writing

7. Scene File Grammar

This appendix contains the formal syntax of the mental images .mi scene description format. The grammar is in yacc format; yacc is a Unix compiler generator. Nonterminals that begin with T_ are typed values:

This appendix is intended to aid translator writers, and to describe the relationship between the .mi scene description language and the API available to  geometry shader writers. This is the complete mental ray grammar including parts that are not part of the shader interface (such as initiating rendering). Refer to the mental ray integration guide for a description of these functions.

Note that the grammars used by mental ray 1.9 and mental ray 2.0 are arranged in a slightly different way, but functionally the 2.0 grammar is a fully compatible superset of the 1.9 grammar with added features such as instancing.

%start start

%union {
        miBoolean        boolean;
        char            *symbol;
        char            *string;
        struct          {
                int      len;
                miUchar *bytes;
        }                byte_string;
        int              integer;
        double           floating;
        float            floatoctet[8];
        miMatrix         matrix;
        miVector         vector;
        miGeoVector      geovector;
        miTransform     *transform;
        miParameter     *para_type;
        miDlist         *dlist;
        miTag            tag;
}

%token <symbol> T_SYMBOL
%token <integer> T_INTEGER
%token <floating> T_FLOAT
%token <string> T_STRING
%token <byte_string> T_BYTE_STRING
%token <vector> T_VECTOR

%token ACCELERATION ACCURACY ADAPTIVE ALL ALPHA ANGLE ANY APERTURE APPLY
%token APPROXIMATE ARRAY ASPECT
%token BACK BASIS BEZIER BLUE BOOLEAN BOTH BOX BSP BSPLINE BUFFER BUMP
%token CALL CAMERA CARDINAL CAUSTIC CLASSIFICATION CLIP CODE COLOR COLORCLIP
%token CONE CONIC CONNECT CONSTANT CONTOUR CONTRAST CONTROL CORNER CP
%token CREASE CURVATURE CURVE CUSP CYLINDER
%token D DART DATA DEBUG_ DECLARE DELAUNAY DELETE_ DENSITY DEPTH DERIVATIVE
%token DESATURATE DIAGNOSTIC DIRECTION DISC DISPLACE DISTANCE DITHER
%token ECHO EMITTER END ENVIRONMENT EVEN ENERGY EXPONENT
%token FACE FALSE_ FAN FIELD FILE_ FILTER FINALGATHER FOCAL FRAME FRONT
%token GAMMA GAUSS GEOMETRY GLOBILLUM GRADING GREEN GRID GROUP GUI
%token HIDE HOLE
%token IMP IMPLICIT INCREMENTAL INFINITY_ INHERITANCE INSTANCE INSTGROUP
%token INTEGER INTERFACE_ IRRADIANCE
%token JITTER
%token LANCZOS LENGTH LENS LIGHT LINK LOCAL
%token M MAPSTO MATERIAL MATRIX MAX_ MEMORY MERGE MI MIN_ MITCHELL MIXED MOTION
%token N NOCONTOUR NULL_
%token OBJECT ODD OFF OFFSET ON OPAQUE_ OPENGL OPTIONS ORIGIN OUTPUT
%token P PARALLEL_ PARAMETRIC PHENOMENON PHOTON PHOTONMAP PHOTONS PHOTONVOL
%token PREMULTIPLY PRIORITY
%token Q QUALITY
%token RATIONAL RAY RAYCL RAW REBUILD RECTANGLE RECURSIVE RED REGISTRY REGULAR
%token RENDER RESOLUTION RGB_ ROOT
%token SAMPLELOCK SAMPLES SCALAR SCANLINE SEGMENTS SET SHADOW SHADOWMAP SHUTTER
%token SIZE SOFTNESS SORT SPACE SPATIAL SPDL SPECIAL SPHERE SPREAD STORE STRING
%token STRIP STRUCT SUBDIVISION SHADER SMART SURFACE SYSTEM
%token T TAG TAGGED TASK TAYLOR TEXTURE TIME TRACE TRANSFORM TREE TRIANGLE TRIM
%token TRUE_
%token U V VALUE VECTOR VERBOSE VERSION VIEW VISIBLE VOLUME
%token W WHITE WIDTH WINDOW WORLD

%type <floating> floating
%type <boolean> boolean
%type <string> symbol
%type <string> opt_symbol
%type <matrix> transform
%type <integer> tex_flags
%type <integer> tex_flag
%type <integer> tex_type
%type <integer> simple_type
%type <string> inst_item
%type <tag> inst_func
%type <tag> inst_params
%type <integer> filter_type
%type <integer> c_filter_type
%type <tag> function
%type <tag> function_list
%type <tag> tex_func_list
%type <tag> phen_root
%type <string> mtl_or_label
%type <para_type> shret_type
%type <para_type> shret_type_nosh
%type <para_type> shret_decl_seq
%type <para_type> shret_decl
%type <para_type> parm_decl_list
%type <para_type> parm_decl_seq
%type <para_type> parm_decl
%type <boolean> rational
%type <dlist> basis_matrix
%type <floating> merge_option
%type <vector> vector
%type <geovector> geovector
%type <dlist> para_list
%type <boolean> opt_volume_flag
%type <boolean> opt_vector_flag
%type <boolean> opt_incremental
%type <integer> apply
%type <integer> apply_list
%type <floatoctet> out_parms
%type <integer> colorclip_mode

%%

start :
                        { functag = 0;
                          mi_api_incremental(is_incremental = miFALSE);
                          mi_reset_time();
                          if (mi_get_subverbosity(miM_MI) & miMSG_PHASE)
                                mi_progress("begin mi scene file parsing"); }
                  command_list
                        { if (mi_get_subverbosity(miM_MI) & miMSG_PHASE)
                                mi_progress("end of scene file, parsing ends");
                        }
                |
                        { mi_info("end of scene file"); }
                ;


/*-----------------------------------------------------------------------------
 * primitive types
 *---------------------------------------------------------------------------*/

boolean : ON
                        { $$ = miTRUE; }
                | OFF
                        { $$ = miFALSE; }
                | TRUE_
                        { $$ = miTRUE; }
                | FALSE_
                        { $$ = miFALSE; }
                ;

floating : T_FLOAT { $$ = $1; }
                | T_INTEGER     { $$ = $1; }
                ;

vector : floating floating floating
                        { $$.x = $1; $$.y = $2; $$.z = $3; }
                | T_VECTOR
                        { $$ = $1; }
                ;

geovector : floating floating floating
                        { $$.x = $1; $$.y = $2; $$.z = $3; }
                | T_VECTOR
                        { $$.z = $1.z; $$.y = $1.y; $$.x = $1.x; }
                ;

transform : TRANSFORM floating floating floating floating
                                floating floating floating floating
                                floating floating floating floating
                                floating floating floating floating
                        { $$[0] = $2;  $$[1] = $3;  $$[2] = $4;  $$[3] = $5;
                          $$[4] = $6;  $$[5] = $7;  $$[6] = $8;  $$[7] = $9;
                          $$[8] = $10; $$[9] = $11; $$[10]= $12; $$[11]= $13;
                          $$[12]= $14; $$[13]= $15; $$[14]= $16; $$[15]= $17; }
                ;

symbol : T_SYMBOL
                        { $$ = $1; }
                | T_STRING
                        { $$ = $1; }
                ;

opt_symbol :
                        { $$ = 0; }
                | symbol
                        { $$ = $1; }
                ;

colorclip_mode : RGB_
                        { $$ = miIMG_COLORCLIP_RGB; }
                |  ALPHA
                        { $$ = miIMG_COLORCLIP_ALPHA; }
                |  RAW
                        { $$ = miIMG_COLORCLIP_RAW; }
                ;


/*-----------------------------------------------------------------------------
 * top-level commands
 *---------------------------------------------------------------------------*/

command_list : { mi_api_incremental(is_incremental = miFALSE); }
                  command
                | command_list
                        { mi_api_incremental(is_incremental = miFALSE); }
                  command
                ;

command : frame
                | debug
                | set
                | call
                | version
                | incr_command
                | INCREMENTAL
                        { mi_api_incremental(is_incremental = miTRUE); }
                  incr_command
                | DELETE_ symbol
                        { mi_api_delete($2); }
                | RENDER symbol symbol symbol
                        { mi_timing("mi scene file parsing");
                          mi_reset_time();
                          mi_api_render($2, $3, $4,
                                         mi_mem_strdup(ctx->inheritance_func));
                          if (mi_get_subverbosity(miM_MI) & miMSG_PHASE)
                                mi_progress("resume mi scene file parsing");
                          yyreturn MIYYRENDER;
                        }
                | VERBOSE boolean
                        { if (!ctx->mi_force_verbose)
                                mi_set_verbosity($2? miERR_ALL & ~miERR_DEBUG
                                                               & ~miERR_VDEBUG
                                                   : miERR_FATAL|miERR_ERROR);}
                | VERBOSE T_INTEGER
                        { if (!ctx->mi_force_verbose)
                                mi_set_verbosity((1 << $2) - 1); }
                | ECHO T_STRING
                        { mi_info("%s", $2);
                          mi_mem_release($2); }
                | SYSTEM T_STRING
                        { if ((system($2) >> 8) & 0xff)
                          mi_api_warning("system \"%s\" failed", $2);
                          mi_mem_release($2); }
                | MEMORY T_INTEGER
                        { mi_api_warning("memory view parameter ignored"); }
                | CODE T_STRING
                        { mi_link_file_add($2, miTRUE, miFALSE, miFALSE); }
                | CODE
                        { mi_api_code_verbatim_begin(); }
                  code_bytes_list
                        { mi_api_code_verbatim_end(); }
                | LINK T_STRING
                        { mi_link_file_add($2, miFALSE, miFALSE, miFALSE); }
                | DECLARE function_decl
                | DECLARE phenomenon_decl
                | DECLARE data_decl
                | REGISTRY symbol
                        { mi_api_registry_begin($2); }
                  reg_body END REGISTRY
                        { mi_api_registry_end(); }
                ;

reg_body :
                | reg_item reg_body
                ;

reg_item : VALUE symbol
                        { mi_api_registry_add(mi_mem_strdup("value"), $2); }
                | LINK symbol
                        { mi_api_registry_add(mi_mem_strdup("link"), $2); }
                | CODE symbol
                        { mi_api_registry_add(mi_mem_strdup("code"), $2); }
                | MI symbol
                        { mi_api_registry_add(mi_mem_strdup("mi"), $2); }
                | SPDL symbol
                        { mi_api_registry_add(mi_mem_strdup("spdl"), $2); }
                | ECHO symbol
                        { mi_api_registry_add(mi_mem_strdup("echo"), $2); }
                | SYSTEM symbol
                        { mi_api_registry_add(mi_mem_strdup("system"), $2); }
                | symbol symbol
                        { mi_api_registry_add($1, $2); }
                ;

incr_command : options
                | camera
                | texture
                | material
                | light
                | instance
                | instgroup
                | object
                | userdata
                | gui
                | SHADER symbol function_list
                        { mi_api_shader_add($2, $3); }
                ;

code_bytes_list : T_BYTE_STRING
                        { mi_api_code_byte_copy($1.len, $1.bytes); }
                | code_bytes_list T_BYTE_STRING
                        { mi_api_code_byte_copy($2.len, $2.bytes); }
                ;

set : SET symbol
                        { mi_api_variable_set($2, 0); }
                | SET symbol symbol
                        { mi_api_variable_set($2, $3); }
                ;

call : CALL function_list
                        { mi_api_shader_call($2, 0, 0); }
                | CALL function_list ',' symbol symbol
                        { mi_api_shader_call($2, $4, $5); }
                ;

debug : DEBUG_ symbol opt_symbol
                        { mi_api_debug($2, $3); }
                ;

version : VERSION T_STRING
                        { mi_api_version_check($2, 0);
                          ctx->mi_did_check_version = miTRUE; }
                | MIN_ VERSION T_STRING
                        { mi_api_version_check($3, 0);
                          ctx->mi_did_check_version = miTRUE; }
                | MAX_ VERSION T_STRING
                        { mi_api_version_check($3, 1);
                          ctx->mi_did_check_version = miTRUE; }
                ;


/*****************************************************************************
 *************************    mi1 compatibility    ***************************
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * frame
 *---------------------------------------------------------------------------*/

frame :
                        { mi_api_frame_begin(&camera, &options); }
                  frame_number
                  initial_frame_cmd_list
                  view
                  frame_command_list
                  END FRAME
                        { mi_timing("mi scene file parsing");
                          mi_reset_time();
                          mi_api_frame_end();
                          if (mi_get_subverbosity(miM_MI) & miMSG_PHASE)
                                mi_progress("resume mi scene file parsing");
                          yyreturn MIYYENDFRAME;
                        }
                ;

initial_frame_cmd_list
                :
                | initial_frame_cmd_list initial_frame_cmd
                ;

initial_frame_cmd
                : texture
                | light
                | material
                ;

frame_command_list
                :
                | frame_command_list frame_command
                ;

frame_command
                : texture
                | light
                | material
                | object
                | call
                | debug
                | version
                | gui
                ;


/*-----------------------------------------------------------------------------
 * view
 *---------------------------------------------------------------------------*/

view : VIEW
                  view_list
                  END VIEW
                ;

view_list :
                | view_list view_item
                ;

view_item : camview_item
                | optview_item
                | MIN_ SAMPLES T_INTEGER
                        { options->min_samples = $3; }
                | MAX_ SAMPLES T_INTEGER
                        { options->max_samples = $3; }
                | SAMPLES T_INTEGER
                        { mi_api_warning(
                                "\"samples\" view parameter ignored"); }
                | RECURSIVE boolean
                        { if (!$2)
                                mi_api_warning("\"recursive off\" ignored"); }
                | ADAPTIVE boolean
                        { mi_api_warning("\"adaptive\" statement ignored"); }
                | ACCELERATION RAY CLASSIFICATION
                        { options->acceleration = 'c'; }
                | ACCELERATION SPATIAL SUBDIVISION
                        { options->acceleration = 'b'; }
                | ACCELERATION GRID
                        { options->acceleration = 'g'; }
                | SUBDIVISION MEMORY T_INTEGER
                        { options->subdivision_memory = $3; }
                | SUBDIVISION T_INTEGER T_INTEGER
                        { options->subdivision    = $2;
                          options->subdivision_2d = $3; }
                | MAX_ SIZE T_INTEGER
                        { options->space_max_size = $3; }
                | MAX_ DEPTH T_INTEGER
                        { options->space_max_depth = $3; }
                | SHADOW SORT boolean
                        { if ($3) options->shadow = 'l'; }
                | SHADOW SEGMENTS boolean
                        { if ($3) options->shadow = 's'; }
                | transform
                        { mi_api_view_transform($1); }
                | RED floating floating
                | GREEN floating floating
                | BLUE floating floating
                | WHITE floating floating
                ;


/*****************************************************************************
 *************************    new mi2 features    ****************************
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * options
 *---------------------------------------------------------------------------*/

options : OPTIONS symbol
                        { options = mi_api_options_begin($2); }
                  option_list END OPTIONS
                        { mi_api_options_end(); }
                ;

option_list :
                | option_list option_item
                ;

option_item : optview_item
                |       { curr_datatag = &options->userdata; }
                  data
                | ACCELERATION RAYCL
                        { options->acceleration = 'c'; }
                | ACCELERATION BSP
                        { options->acceleration = 'b'; }
                | ACCELERATION GRID
                        { options->acceleration = 'g'; }
                | DIAGNOSTIC SAMPLES boolean
                        { miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_SAMPLES,$3);}
                | DIAGNOSTIC PHOTON OFF
                        { miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_PHOTON, miFALSE);}
                | DIAGNOSTIC PHOTON DENSITY floating
                        { miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_PHOTON, miFALSE);
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_PHOTON_D, miTRUE);
                          options->diag_photon_density = $4;}
                | DIAGNOSTIC PHOTON IRRADIANCE floating
                        { miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_PHOTON, miFALSE);
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_PHOTON_I, miTRUE);
                          options->diag_photon_density = $4;}
                | DIAGNOSTIC GRID OFF
                        { miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID, miFALSE);}
                | DIAGNOSTIC GRID OBJECT floating
                        { options->diag_grid_size = $4;
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID, miFALSE);
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID_O, $4 != 0.0);}
                | DIAGNOSTIC GRID WORLD floating
                        { options->diag_grid_size = $4;
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID, miFALSE);
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID_W, $4 != 0.0);}
                | DIAGNOSTIC GRID CAMERA floating
                        { options->diag_grid_size = $4;
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID, miFALSE);
                          miBIT_SWITCH(options->diagnostic_mode,
                                miSCENE_DIAG_GRID_C, $4 != 0.0);}
                | SAMPLES T_INTEGER
                        { options->min_samples = $2-2;
                          options->max_samples = $2;}
                | SAMPLES T_INTEGER T_INTEGER
                        { options->min_samples = $2;
                          options->max_samples = $3;}
                | SHADOW SORT
                        { options->shadow = 'l'; }
                | SHADOW SEGMENTS
                        { options->shadow = 's'; }
                ;

optview_item : SHADOW OFF
                        { options->shadow = 0; }
                | SHADOW ON
                        { options->shadow = 1; }
                | TRACE boolean
                        { options->trace = $2; }
                | SCANLINE boolean
                        { options->scanline = $2; }
                | SCANLINE OPENGL
                        { options->scanline = 'o'; }
                | LENS boolean
                        { options->no_lens = !$2; }
                | VOLUME boolean
                        { options->no_volume = !$2; }
                | GEOMETRY boolean
                        { options->no_geometry = !$2; }
                | DISPLACE boolean
                        { options->no_displace = !$2; }
                | OUTPUT boolean
                        { options->no_output = !$2; }
                | MERGE boolean
                        { options->no_merge = !$2; }
                | FILTER filter_type
                        { options->filter        = $2;
                          options->filter_size_x =
                          options->filter_size_y = 0.0; }
                | FILTER filter_type floating
                        { options->filter        = $2;
                          options->filter_size_x =
                          options->filter_size_y = $3; }
                | FILTER filter_type floating floating
                        { options->filter        = $2;
                          options->filter_size_x = $3;
                          options->filter_size_y = $4; }
                | FACE FRONT
                        { options->face = 'f'; }
                | FACE BACK
                        { options->face = 'b'; }
                | FACE BOTH
                        { options->face = 'a'; }
                | FIELD OFF
                        { options->field = 0; }
                | FIELD EVEN
                        { options->field = 'e'; }
                | FIELD ODD
                        { options->field = 'o'; }
                | SAMPLELOCK boolean
                        { options->samplelock = $2; }
                | PHOTON TRACE DEPTH T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $4;
                          options->photon_trace_depth      = $4 + $4; }
                | PHOTON TRACE DEPTH T_INTEGER T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $5;
                          options->photon_trace_depth      = $4 + $5; }
                | PHOTON TRACE DEPTH T_INTEGER T_INTEGER T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $5;
                          options->photon_trace_depth      = $6; }
                | TRACE DEPTH T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $3;
                          options->trace_depth      = $3 + $3; }
                | TRACE DEPTH T_INTEGER T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $4;
                          options->trace_depth      = $3 + $4; }
                | TRACE DEPTH T_INTEGER T_INTEGER T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $4;
                          options->trace_depth      = $5; }
                | CONTRAST floating floating floating
                        { options->contrast.r = $2;
                          options->contrast.g = $3;
                          options->contrast.b = $4;
                          options->contrast.a = ($2 + $3 + $4)/3; }
                | CONTRAST floating floating floating floating
                        { options->contrast.r = $2;
                          options->contrast.g = $3;
                          options->contrast.b = $4;
                          options->contrast.a = $5; }
                | TIME CONTRAST floating floating floating
                        { options->time_contrast.r = $3;
                          options->time_contrast.g = $4;
                          options->time_contrast.b = $5;
                          options->time_contrast.a = ($3 + $4 + $5)/3; }
                | TIME CONTRAST floating floating floating floating
                        { options->time_contrast.r = $3;
                          options->time_contrast.g = $4;
                          options->time_contrast.b = $5;
                          options->time_contrast.a = $6; }
                | CONTOUR STORE function
                        { options->contour_store = $3; }
                | CONTOUR CONTRAST function
                        { options->contour_contrast = $3; }
                | JITTER floating
                        { options->jitter = $2; }
                | SHUTTER floating
                        { options->shutter = $2;
                          options->motion  = options->shutter > 0; }
                | TASK SIZE T_INTEGER
                        { options->task_size = $3; }
                | RAYCL SUBDIVISION T_INTEGER T_INTEGER
                        { options->subdivision    = $3;
                          options->subdivision_2d = $4; }
                | RAYCL MEMORY T_INTEGER
                        { options->subdivision_memory = $3; }
                | BSP SIZE T_INTEGER
                        { options->space_max_size = $3; }
                | BSP DEPTH T_INTEGER
                        { options->space_max_depth = $3; }
                | BSP MEMORY T_INTEGER
                        { options->space_max_mem = $3; }
                | GRID SIZE floating
                        { options->grid_size = $3; }
                | DESATURATE boolean
                        { miImg_mode_val val;
                          val.b = $2;
                          mi_img_mode(miIMG_MODE_DESATURATE,val); }
                | DITHER boolean
                        { miImg_mode_val val;
                          val.b = $2;
                          mi_img_mode(miIMG_MODE_DITHER,val); }
                | PREMULTIPLY boolean
                        { miImg_mode_val val;
                          val.b = !($2);
                          mi_img_mode(miIMG_MODE_NOPREMULT,val); }
                | COLORCLIP colorclip_mode
                        { miImg_mode_val val;
                          val.i = $2;
                          mi_img_mode(miIMG_MODE_COLORCLIP,val); }
                | GAMMA floating
                        { miImg_mode_val val;
                          val.d = $2;
                          mi_img_mode(miIMG_MODE_GAMMA,val); }
                | OBJECT SPACE
                        { options->render_space = 'o'; }
                | CAMERA SPACE
                        { options->render_space = 'c'; }
                | MIXED SPACE
                        { options->render_space = 'm'; }
                | WORLD SPACE
                        { mi_api_warning(
                                "world space statement ignored"); } /*<<<*/
                | INHERITANCE symbol
                        { if (ctx->inheritance_func)
                                mi_mem_release(ctx->inheritance_func);
                          ctx->inheritance_func = $2; }
                | SHADOWMAP MOTION boolean
                        { options->shadow_map_motion = $3; }
                | SHADOWMAP REBUILD boolean
                        { options->recompute_shadow_maps = (($3)?'y':'n'); }
                | SHADOWMAP boolean
                        { options->use_shadow_maps = $2; }
                | SHADOWMAP OPENGL
                        { options->use_shadow_maps = 'o'; }
                | CAUSTIC boolean
                        { options->caustic = $2; }
                | CAUSTIC T_INTEGER
                        { options->caustic_flag = $2; }
                | CAUSTIC ACCURACY T_INTEGER
                        { options->caustic_accuracy = $3; }
                | CAUSTIC ACCURACY T_INTEGER floating
                        { options->caustic_accuracy = $3;
                          options->caustic_radius = $4; }
                | CAUSTIC FILTER c_filter_type
                        { options->caustic_filter = $3;
                          options->caustic_filter_const = 1.1; }
                | CAUSTIC FILTER c_filter_type floating
                        { options->caustic_filter = $3;
                          options->caustic_filter_const = $4; }
                | GLOBILLUM boolean
                        { options->globillum = $2; }
                | GLOBILLUM T_INTEGER
                        { options->globillum_flag = $2; }
                | GLOBILLUM ACCURACY T_INTEGER
                        { options->globillum_accuracy = $3; }
                | GLOBILLUM ACCURACY T_INTEGER floating
                        { options->globillum_accuracy = $3;
                          options->globillum_radius = $4; }
                | FINALGATHER boolean
                        { options->finalgather = $2; }
                | FINALGATHER ACCURACY T_INTEGER
                        { options->finalgather_rays = $3; }
                | FINALGATHER ACCURACY T_INTEGER floating
                        { options->finalgather_rays = $3;
                          options->finalgather_maxradius = $4;
                          options->finalgather_minradius = 0.0; }
                | FINALGATHER ACCURACY T_INTEGER floating floating
                        { options->finalgather_rays = $3;
                          options->finalgather_maxradius = $4;
                          options->finalgather_minradius = $5; }
                | PHOTONVOL ACCURACY T_INTEGER
                        { options->photonvol_accuracy = $3; }
                | PHOTONVOL ACCURACY T_INTEGER floating
                        { options->photonvol_accuracy = $3;
                          options->photonvol_radius = $4; }
                | PHOTONMAP FILE_ T_STRING
                        { mi_scene_delete(options->photonmap_file);
                          strcpy((char *)mi_scene_create(
                                        &options->photonmap_file,
                                        miSCENE_STRING, strlen($3)+1), $3);
                          mi_db_unpin(options->photonmap_file);
                          mi_mem_release($3); }
                | PHOTONMAP REBUILD boolean
                        { options->photonmap_rebuild = $3; }
                | APPROXIMATE opt_displace
                | FRAME BUFFER T_INTEGER opt_symbol
                        { mi_api_framebuffer(options, $3, $4); }
                ;

filter_type : BOX
                        { $$ = 'b'; }
                | TRIANGLE
                        { $$ = 't'; }
                | GAUSS
                        { $$ = 'g'; }
                | MITCHELL
                        { $$ = 'm'; }
                | LANCZOS
                        { $$ = 'l'; }
                ;

c_filter_type : BOX
                        { $$ = 'b'; }
                | CONE
                        { $$ = 'c'; }
                | GAUSS
                        { $$ = 'g'; }
                ;

opt_displace : { miAPPROX_DEFAULT(approx); }
                  s_approx_tech ALL
                        { memcpy(&options->approx, &approx, sizeof(miApprox));}
                |       { miAPPROX_DEFAULT(approx); }
                  DISPLACE s_approx_tech ALL
                        { memcpy(&options->approx_displace, &approx,
                                                           sizeof(miApprox)); }
                ;


/*-----------------------------------------------------------------------------
 * camera
 *---------------------------------------------------------------------------*/

camera : CAMERA symbol
                        { camera = mi_api_camera_begin($2);
                          have_l = have_o = have_v = have_e = 0; }
                  camera_list END CAMERA
                        { mi_api_camera_end(); }
                ;

camera_list :
                | camera_list camera_item
                ;

camera_item : camview_item
                | frame_number
                | FIELD T_INTEGER
                        { camera->frame_field = $2; }
                ;

camview_item : OUTPUT
                        { mi_api_function_delete(&camera->output); }
                | OUTPUT T_STRING T_STRING
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_file_def(0, 0, $2, $3)); }
                | OUTPUT T_STRING out_parms T_STRING
                        { miTag ftag;
                          if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          camera->output = mi_api_function_append(
                                camera->output,
                                ftag = mi_api_output_file_def(0, 0, $2, $4));
                          mi_api_output_file_parameter(ftag, 0, $3); }
                | OUTPUT T_STRING T_STRING T_STRING
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          mi_api_output_type_identify(&tbm, &ibm, $2);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_file_def(tbm, ibm, $3, $4));}
                | OUTPUT T_STRING T_STRING out_parms T_STRING
                        { miTag ftag;
                          if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          mi_api_output_type_identify(&tbm, &ibm, $2);
                          camera->output = mi_api_function_append(
                                camera->output,
                                ftag = mi_api_output_file_def(tbm, ibm,$3,$5));
                          mi_api_output_file_parameter(ftag, 0, $4); }
                | OUTPUT T_STRING function
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          mi_api_output_type_identify(&tbm, &ibm, $2);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_function_def(tbm, ibm, $3)); }
                | VOLUME
                        { mi_api_function_delete(&camera->volume); }
                | VOLUME function_list
                        { if (!have_v++)
                                mi_api_function_delete(&camera->volume);
                          camera->volume = mi_api_function_append(
                                                camera->volume, $2); }
                | ENVIRONMENT
                        { mi_api_function_delete(&camera->environment); }
                | ENVIRONMENT function_list
                        { if (!have_e++)
                                mi_api_function_delete(&camera->environment);
                          camera->environment = mi_api_function_append(
                                                camera->environment, $2); }
                | LENS
                        { mi_api_function_delete(&camera->lens); }
                | LENS function_list
                        { if (!have_l++)
                                mi_api_function_delete(&camera->lens);
                          camera->lens = mi_api_function_append(
                                                camera->lens, $2); }
                | FOCAL floating
                        { camera->focal = $2;
                          camera->orthographic = miFALSE; }
                | FOCAL INFINITY_
                        { camera->focal = 1;
                          camera->orthographic = miTRUE; }
                | APERTURE floating
                        { camera->aperture = $2; }
                | ASPECT floating
                        { camera->aspect = $2; }
                | RESOLUTION T_INTEGER T_INTEGER
                        { camera->x_resolution = $2;
                          camera->y_resolution = $3; }
                | OFFSET floating floating
                        { camera->x_offset = $2;
                          camera->y_offset = $3; }
                | WINDOW T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                        { camera->window.xl = $2;
                          camera->window.yl = $3;
                          camera->window.xh = $4;
                          camera->window.yh = $5; }
                | CLIP floating floating
                        { camera->clip.min = $2;
                          camera->clip.max = $3; }
                |       { curr_datatag = &camera->userdata; }
                  data
                ;

out_parms : QUALITY T_INTEGER
                        { $$[0] = (float) $2; }
                ;

frame_number : FRAME T_INTEGER
                        { camera->frame       = $2;
                          camera->frame_time  = 0;
                          camera->frame_field = 0; }
                | FRAME T_INTEGER floating
                        { camera->frame       = $2;
                          camera->frame_time  = $3;
                          camera->frame_field = 0; }
                ;


/*-----------------------------------------------------------------------------
 * instance
 *---------------------------------------------------------------------------*/

instance : INSTANCE symbol
                        { curr_inst = mi_api_instance_begin($2);
                          if (!curr_inst) curr_inst = &dummy_inst; }
                  inst_item inst_func
                  inst_flags
                  inst_params
                        { mi_api_instance_end($4, $5, $7); }
                  END INSTANCE
                ;

inst_item :
                        { $$ = 0; }
                | symbol
                        { $$ = $1; }
                ;

inst_func :
                        { $$ = miNULLTAG; }
                | GEOMETRY function_list
                        { $$ = $2; }
                ;

inst_flags :
                | inst_flag inst_flags
                ;

inst_flag : VISIBLE boolean
                        { curr_inst->visible = $2 ? 2 : 1; }
                | SHADOW boolean
                        { curr_inst->shadow = $2 ? 2 : 1; }
                | TRACE boolean
                        { curr_inst->trace = $2 ? 2 : 1; }
                | CAUSTIC
                        { curr_inst->caustic &= 0x30;
                          curr_inst->caustic |= 0x03; }
                | CAUSTIC boolean
                        { curr_inst->caustic &= 0x0f;
                          curr_inst->caustic |= $2 ? 0x20 : 0x10; }
                | CAUSTIC T_INTEGER
                        { curr_inst->caustic &= 0x30;
                          curr_inst->caustic |= ($2 & 0x0f); }
                | GLOBILLUM
                        { curr_inst->globillum &= 0x30;
                          curr_inst->globillum |= 0x03; }
                | GLOBILLUM boolean
                        { curr_inst->globillum &= 0x0f;
                          curr_inst->globillum |= $2 ? 0x20 : 0x10; }
                | GLOBILLUM T_INTEGER
                        { curr_inst->globillum &= 0x30;
                          curr_inst->globillum |= ($2 & 0x0f); }
                | HIDE boolean
                        { curr_inst->off = $2; }
                | TRANSFORM
                        { curr_inst->tf.function = miNULLTAG;
                          mi_matrix_ident(curr_inst->tf.global_to_local); }
                | TRANSFORM function
                        { curr_inst->tf.function = $2;
                          mi_matrix_ident(curr_inst->tf.global_to_local); }
                | transform
                        { curr_inst->tf.function = miNULLTAG;
                          mi_matrix_copy(
                                curr_inst->tf.global_to_local, $1);
                          if (!mi_matrix_invert(curr_inst->tf.local_to_global,
                                               curr_inst->tf.global_to_local)){
                                mi_api_warning("singular matrix, using "
                                                                "identity");
                                mi_matrix_ident(curr_inst->tf.global_to_local);
                                mi_matrix_ident(curr_inst->tf.local_to_global);
                        }}
                | MOTION OFF
                        { mi_matrix_null(curr_inst->motion_transform);
                          curr_inst->gen_motion = miGM_OFF; }
                | MOTION TRANSFORM
                        { mi_matrix_null(curr_inst->motion_transform);
                          curr_inst->gen_motion = miGM_INHERIT; }
                | MOTION transform
                        { mi_matrix_copy(curr_inst->motion_transform, $2);
                          curr_inst->gen_motion = miGM_TRANSFORM; }
                | MATERIAL
                        { curr_inst->material = miNULLTAG;
                          curr_inst->mtl_array_size = 0; }
                  inst_mtl
                | TAG T_INTEGER
                        { curr_inst->label = $2; }
                |       { curr_datatag = &curr_inst->userdata; }
                  data
                ;

inst_params :
                        { $$ = (miTag)-1; }
                | '(' ')'
                        { $$ = miNULLTAG; }
                | '('
                        { if (!ctx->inheritance_func)
                                mi_api_error(
                                        "no inheritance function in options");
                          else {
                                mi_api_function_call(mi_mem_strdup(
                                        ctx->inheritance_func));
                          }
                        }
                  parameter_seq comma_rparen
                        { $$ = mi_api_function_call_end(0); }
                ;

comma_rparen : ')'
                | ',' ')'
                ;

inst_mtl :
                | symbol
                        { curr_inst->material = mi_api_material_lookup($1); }
                | '['
                        { taglist = mi_api_dlist_create(miDLIST_TAG); }
                  inst_mtl_array ']'
                        { curr_inst->mtl_array_size = taglist->nb;
                          curr_inst->material = mi_api_taglist(taglist); }
                ;

inst_mtl_array : symbol
                        { mi_api_dlist_add(taglist,
                                (void *)(miIntptr)mi_api_material_lookup($1));}
                  inst_mtl_next
                ;

inst_mtl_next :
                | ','
                | ',' inst_mtl_array
                ;


/*-----------------------------------------------------------------------------
 * instgroup
 *---------------------------------------------------------------------------*/

instgroup : INSTGROUP symbol
                        { curr_group = mi_api_instgroup_begin($2);
                          mi_api_instgroup_clear(); }
                  group_flags
                  group_list END INSTGROUP
                        { mi_api_instgroup_end(); }
                ;

group_flags :
                | group_flag group_flags
                ;

group_flag : MERGE floating
                        { curr_group->merge = $2;
                          curr_group->merge_group = $2 >= miMERGE_MIN; }
                | TAG T_INTEGER
                        { curr_group->label = $2; }
                |       { curr_datatag = &curr_group->userdata; }
                  data
                ;

group_list :
                | symbol
                        { mi_api_instgroup_additem($1); }
                  group_list
                ;


/*****************************************************************************
 *************************    either    **************************************
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * function declaration
 *---------------------------------------------------------------------------*/

function_decl : shret_type_nosh T_STRING parm_decl_list
                        { mi_api_funcdecl_begin($1, $2, $3);
                          mi_api_funcdecl_end(); }
                | SHADER shret_type T_STRING parm_decl_list
                        { if (!(curr_decl = mi_api_funcdecl_begin($2, $3, $4)))
                                curr_decl = &dummy_decl; }
                  declare_req_seq END DECLARE
                        { mi_api_funcdecl_end(); }
                ;

shret_type : shret_type_nosh
                        { $$ = $1; }
                | SHADER
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, 0, 0); }
                ;

shret_type_nosh :
                        { $$ = mi_api_parameter_decl(miTYPE_COLOR, 0, 0); }
                | simple_type
                        { $$ = mi_api_parameter_decl($1, 0, 0); }
                | STRUCT '{' shret_decl_seq '}'
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_STRUCT, 0, 0);
                          mi_api_parameter_child(parm, $3);
                          $$ = parm; }
                ;

shret_decl_seq : shret_decl_seq ',' shret_decl
                        { $$ = mi_api_parameter_append($1, $3); }
                | shret_decl
                        { $$ = $1; }
                ;

shret_decl : simple_type symbol
                        { $$ = mi_api_parameter_decl($1, $2, 0); }
                | SHADER symbol
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, $2, 0); }
                | DATA symbol
                        { $$ = mi_api_parameter_decl(miTYPE_DATA,   $2, 0); }
                ;

parm_decl_list : '(' parm_decl_seq ')'
                        { $$ = $2; }
                | '(' parm_decl_seq ',' ')'
                        { $$ = $2; }
                | '(' ')'
                        { $$ = 0; }
                ;

parm_decl_seq : parm_decl_seq ',' parm_decl
                        { $$ = mi_api_parameter_append($1, $3); }
                | parm_decl
                        { $$ = $1; }
                ;

parm_decl : simple_type symbol
                        { $$ = mi_api_parameter_decl($1, $2, 0); }
                | SHADER symbol
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, $2, 0); }
                | DATA symbol
                        { $$ = mi_api_parameter_decl(miTYPE_DATA,   $2, 0); }
                | STRUCT symbol '{' parm_decl_seq '}'
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_STRUCT, $2, 0);
                          mi_api_parameter_child(parm, $4);
                          $$ = parm; }
                | ARRAY parm_decl
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_ARRAY, 0, 0);
                          mi_api_parameter_child(parm, $2);
                          $$ = parm; }
                ;

simple_type : BOOLEAN
                        { $$ = miTYPE_BOOLEAN; }
                | INTEGER
                        { $$ = miTYPE_INTEGER; }
                | SCALAR
                        { $$ = miTYPE_SCALAR; }
                | STRING
                        { $$ = miTYPE_STRING; }
                | COLOR
                        { $$ = miTYPE_COLOR; }
                | VECTOR
                        { $$ = miTYPE_VECTOR; }
                | TRANSFORM
                        { $$ = miTYPE_TRANSFORM; }
                | SCALAR TEXTURE
                        { $$ = miTYPE_SCALAR_TEX; }
                | VECTOR TEXTURE
                        { $$ = miTYPE_VECTOR_TEX; }
                | COLOR TEXTURE
                        { $$ = miTYPE_COLOR_TEX; }
                | LIGHT
                        { $$ = miTYPE_LIGHT; }
                | MATERIAL
                        { $$ = miTYPE_MATERIAL; }
                | GEOMETRY
                        { $$ = miTYPE_GEOMETRY; }
                ;

declare_req_seq :
                | declare_req declare_req_seq
                ;

declare_req : gui
                | SCANLINE OFF
                        { curr_decl->phen.scanline = 1; }
                | SCANLINE ON
                        { curr_decl->phen.scanline = 2; }
                | TRACE OFF
                        { curr_decl->phen.trace = 1; }
                | TRACE ON
                        { curr_decl->phen.trace = 2; }
                | SHADOW OFF
                        { curr_decl->phen.shadow = 1; }
                | SHADOW ON
                        { curr_decl->phen.shadow = 2; }
                | SHADOW SORT
                        { curr_decl->phen.shadow = 'l'; }
                | SHADOW SEGMENTS
                        { curr_decl->phen.shadow = 's'; }
                | FACE FRONT
                        { curr_decl->phen.face = 'f'; }
                | FACE BACK
                        { curr_decl->phen.face = 'b'; }
                | FACE BOTH
                        { curr_decl->phen.face = 'a'; }
                | TEXTURE T_INTEGER
                        { curr_decl->phen.mintextures = $2; }
                | BUMP T_INTEGER
                        { curr_decl->phen.minbumps = $2; }
                | DERIVATIVE
                        { curr_decl->phen.deriv1 =
                          curr_decl->phen.deriv2 = 0; }
                | DERIVATIVE T_INTEGER
                        { if ($2 == 1)
                                curr_decl->phen.deriv1 = miTRUE;
                          else if ($2 == 2)
                                curr_decl->phen.deriv2 = miTRUE;
                          else
                                mi_api_error("derivative not 1 or 2"); }
                | DERIVATIVE T_INTEGER T_INTEGER
                        { if ($2 == 1 || $3 == 1)
                                curr_decl->phen.deriv1 = miTRUE;
                          else if ($2 == 2 || $3 == 2)
                                curr_decl->phen.deriv2 = miTRUE;
                          if ($2 != 1 && $2 != 2 || $3 != 1 && $3 != 2)
                                mi_api_error("derivative not 1 or 2"); }
                | OBJECT SPACE
                        { curr_decl->phen.render_space = 'o'; }
                | CAMERA SPACE
                        { curr_decl->phen.render_space = 'c'; }
                | MIXED SPACE
                        { curr_decl->phen.render_space = 'm'; }
                | WORLD SPACE
                        { mi_api_warning("world space statement ignored"); }
                | PARALLEL_
                        { curr_decl->phen.parallel = miTRUE; }
                | VERSION T_INTEGER
                        { curr_decl->version = $2; }
                | APPLY apply_list
                        { curr_decl->apply = $2; }
                ;

apply_list : apply { $$ = $1; }
                | apply ',' apply_list  { $$ = $1 | $3; }
                ;

apply : LENS { $$ = miAPPLY_LENS; }
                | MATERIAL              { $$ = miAPPLY_MATERIAL;        }
                | LIGHT                 { $$ = miAPPLY_LIGHT;           }
                | SHADOW                { $$ = miAPPLY_SHADOW;          }
                | ENVIRONMENT           { $$ = miAPPLY_ENVIRONMENT;     }
                | VOLUME                { $$ = miAPPLY_VOLUME;          }
                | TEXTURE               { $$ = miAPPLY_TEXTURE;         }
                | PHOTON                { $$ = miAPPLY_PHOTON;          }
                | GEOMETRY              { $$ = miAPPLY_GEOMETRY;        }
                | DISPLACE              { $$ = miAPPLY_DISPLACE;        }
                | EMITTER               { $$ = miAPPLY_PHOTON_EMITTER;  }
                | OUTPUT                { $$ = miAPPLY_OUTPUT;          }
                ;


/*-----------------------------------------------------------------------------
 * function instance
 *---------------------------------------------------------------------------*/

function_list :
                        { funclist = miNULLTAG; }
                  func_list
                        { $$ = funclist; }
                ;

func_list : function
                        { funclist = $1; }
                | func_list function
                        { funclist = mi_api_function_append(funclist, $2); }
                ;

function : T_STRING
                        { mi_api_function_call($1); }
                  parameter_list
                        { $$ = mi_api_function_call_end(functag); functag = 0;}
                | '=' symbol
                        { $$ = mi_api_function_assign($2); }
                | '=' opt_incremental SHADER symbol function
                        { mi_api_shader_add($4, $5); $$ = $5;
                          mi_api_incremental(is_incremental); }
                ;

opt_incremental :
                        { mi_api_incremental(miFALSE); }
                | INCREMENTAL
                        { mi_api_incremental(miTRUE); }
                ;

parameter_list : '(' ')'
                | '(' parameter_seq ')'
                | '(' parameter_seq ',' ')'
                ;

parameter_seq : parameter
                | parameter_seq ',' parameter
                ;

parameter : symbol
                        { mi_api_parameter_name($1); }
                  value_list
                ;

value_list : value
                | value_list value
                ;

value : NULL_
                | boolean
                        { int value = $1;
                          mi_api_parameter_value(miTYPE_BOOLEAN, &value,0,0); }
                | T_INTEGER
                        { int value = $1;
                          mi_api_parameter_value(miTYPE_INTEGER, &value,0,0); }
                | T_FLOAT
                        { float value = $1;
                          mi_api_parameter_value(miTYPE_SCALAR,  &value,0,0); }
                | symbol
                        { mi_api_parameter_value(miTYPE_STRING,  $1, 0, 0); }
                | '=' symbol
                        { mi_api_parameter_shader($2); }
                | '=' INTERFACE_ symbol
                        { mi_api_parameter_interface($3); }
                | '{'
                        { mi_api_parameter_push(miFALSE); }
                  parameter_seq '}'
                        { mi_api_parameter_pop(); }
                | '['
                        { mi_api_parameter_push(miTRUE); }
                  array_value_seq ']'
                        { mi_api_parameter_pop(); }
                | '[' ']'
                ;

array_value_seq : { mi_api_new_array_element(); }
                  value_list
                  array_value_cont
                ;

array_value_cont:
                | ','
                        { mi_api_new_array_element(); }
                  value_list array_value_cont
                ;


/*-----------------------------------------------------------------------------
 * user data
 *---------------------------------------------------------------------------*/

userdata : DATA symbol data_label T_INTEGER
                        { curr_data = mi_api_data_begin($2, 0,
                                                        (void *)(miIntptr)$4);
                          curr_data->label = label; }
                  '[' data_bytes_list ']'
                        { mi_api_data_end(); }
                | DATA symbol data_label symbol
                        { curr_data = mi_api_data_begin($2, 1,
                                                        (void *)(miIntptr)$4);
                          curr_data->label = label;
                          mi_api_data_end(); }
                | DATA symbol data_label symbol '('
                        { mi_api_function_call($4); }
                  parameter_seq comma_rparen
                        { tag = mi_api_function_call_end(0);
                          curr_data = mi_api_data_begin($2, 2,
                                                        (void *)(miIntptr)tag);
                          curr_data->label = label;
                          mi_api_data_end(); }
                ;

data_label :
                        { label = 0; }
                | TAG T_INTEGER
                        { label = $2; }

data_bytes_list :
                | tex_bytes_list T_BYTE_STRING
                        { mi_api_data_byte_copy($2.len, $2.bytes); }
                ;

data_decl : DATA T_STRING parm_decl_list
                        { if (curr_decl = mi_api_funcdecl_begin(0, $2, $3))
                                curr_decl->type = miFUNCTION_DATA; }
                  data_decl_req END DECLARE
                        { if (curr_decl) mi_api_funcdecl_end(); }
                ;

data_decl_req : gui
                | VERSION T_INTEGER
                        { if (curr_decl) curr_decl->version = $2; }
                | APPLY apply_list
                        { if (curr_decl) curr_decl->apply = $2; }
                ;

data : DATA symbol
                        { *curr_datatag = mi_api_data_append(*curr_datatag,
                                                mi_api_data_lookup($2)); }
                | DATA NULL_
                        { *curr_datatag = 0; }
                ;


/*-----------------------------------------------------------------------------
 * phenomenon declaration
 *---------------------------------------------------------------------------*/

phenomenon_decl : PHENOMENON shret_type T_STRING parm_decl_list
                        { curr_decl = mi_api_phen_begin($2, $3, $4);
                          if (!curr_decl) curr_decl = &dummy_decl; }
                  phen_body_list
                  END DECLARE
                        { mi_api_phen_end(); }
                ;

phen_body_list :
                | phen_body phen_body_list
                ;

phen_body : SHADER symbol function_list
                        { mi_api_shader_add($2, $3); }
                | material
                | light
                | instance
                | declare_req
                | ROOT phen_root
                        { if (curr_decl->phen.root)
                                mi_api_error("multiple roots not allowed");
                          else
                                curr_decl->phen.root = $2; }
                | OUTPUT T_STRING T_STRING
                        { curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_file_def(0, 0, $2, $3)); }
                | OUTPUT T_STRING T_STRING T_STRING
                        { mi_api_output_type_identify(&tbm, &ibm, $2);
                          curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_file_def(tbm, ibm, $3, $4));}
                | OUTPUT T_STRING function
                        { mi_api_output_type_identify(&tbm, &ibm, $2);
                          curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_function_def(tbm, ibm, $3)); }
                | LENS function_list
                        { curr_decl->phen.lens = mi_api_function_append(
                                                curr_decl->phen.lens, $2); }
                | VOLUME function_list
                        { curr_decl->phen.volume = mi_api_function_append(
                                                curr_decl->phen.volume, $2); }
                | ENVIRONMENT function_list
                        { curr_decl->phen.environment = mi_api_function_append(
                                           curr_decl->phen.environment, $2); }
                | GEOMETRY function_list
                        { curr_decl->phen.geometry = mi_api_function_append(
                                                curr_decl->phen.geometry, $2);}
                | CONTOUR STORE function
                        { curr_decl->phen.contour_store = $3; }
                | CONTOUR CONTRAST function
                        { curr_decl->phen.contour_contrast = $3; }
                | OUTPUT PRIORITY T_INTEGER
                        { curr_decl->phen.output_seqnr = $3; }
                | LENS PRIORITY T_INTEGER
                        { curr_decl->phen.lens_seqnr = $3; }
                | VOLUME PRIORITY T_INTEGER
                        { curr_decl->phen.volume_seqnr = $3; }
                ;

phen_root : MATERIAL symbol
                        { if (*curr_decl->declaration != 'm') {
                                mi_api_error("not a material phenomenon");
                                $$ = 0;
                          } else
                                $$ = mi_api_material_lookup($2); }
                | LIGHT symbol
                        { if (*curr_decl->declaration != 'l') {
                                mi_api_error("not a light phenomenon");
                                $$ = 0;
                          } else
                                $$ = mi_api_light_lookup($2); }
                | function_list
                        { $$ = 0;
                          if (*curr_decl->declaration == 'm')
                                mi_api_error("must use ``root material''");
                          else if (*curr_decl->declaration == 'l')
                                mi_api_error("must use ``root light''");
                          else
                                $$ = mi_api_function_append(
                                                curr_decl->phen.root, $1); }
                ;


/*-----------------------------------------------------------------------------
 * texture
 *---------------------------------------------------------------------------*/

texture : { pyramid_filter = 0.; }
                  tex_flags tex_type TEXTURE symbol
                        { functag = mi_api_texture_begin($5, $3, $2); }
                  tex_data
                        { if (pyramid_filter > 0. && functag)
                             if (mi_db_type(functag) == miSCENE_IMAGE) {
                                mi_img_pyramid_set_filter((miImg_image *)
                                        mi_scene_edit(functag),pyramid_filter);
                                mi_scene_edit_end(functag);
                             } else
                                mi_api_nwarning(401, "cannot filter shaders");
                          functag = 0; }
                ;

tex_flags :
                        { $$ = 0; }
                | tex_flag tex_flags
                        { $$ = $1 | $2; }
                ;

tex_flag : LOCAL
                        { $$ = 1; }
                | FILTER
                        { pyramid_filter = 1.; $$ = 2; }
                | FILTER floating
                        { pyramid_filter = $2;
                          $$ = (pyramid_filter > 0.) ? 2 : 0; }
                ;

tex_type : COLOR
                        { $$ = 0; }
                | SCALAR
                        { $$ = 1; }
                | VECTOR
                        { $$ = 2; }
                ;

tex_data : '[' T_INTEGER T_INTEGER ']'
                        { mi_api_texture_array_def_begin($2, $3, 1); }
                  tex_bytes_list
                        { functag = mi_api_texture_array_def_end(); }
                | '[' T_INTEGER T_INTEGER T_INTEGER ']'
                        { mi_api_texture_array_def_begin($2, $3, $4); }
                  tex_bytes_list
                        { functag = mi_api_texture_array_def_end(); }
                | tex_func_list
                        { functag = mi_api_texture_function_def($1); }
                | T_STRING
                        { functag = mi_api_texture_file_def($1); }
                ;

tex_func_list : function
                        { $$ = $1; }
                | function tex_func_list
                        { $$ = mi_api_function_append($1, $2); }
                ;

tex_bytes_list :
                | tex_bytes_list T_BYTE_STRING
                        { mi_api_texture_byte_copy($2.len, $2.bytes); }
                ;


/*-----------------------------------------------------------------------------
 * light
 *---------------------------------------------------------------------------*/

light : LIGHT symbol
                        { curr_light = mi_api_light_begin($2);
                          light_map = 0; }
                  light_ops
                  END LIGHT
                        { switch(light_map & 6) {
                            case 2: curr_light->type = miLIGHT_ORIGIN;   break;
                            case 4: curr_light->type = miLIGHT_DIRECTION;break;
                            case 6: curr_light->type = miLIGHT_SPOT;     break;
                          }
                          mi_api_light_end(); }
                ;

light_ops :
                | light_op light_ops
                ;

light_op : function
                        { if (!(light_map & 1))
                                mi_api_function_delete(&curr_light->shader);
                          light_map |= 1;
                          curr_light->shader = mi_api_function_append(
                                                curr_light->shader, $1); }
                | EMITTER function
                        { if (!(light_map & 8))
                                mi_api_function_delete(&curr_light->emitter);
                          light_map |= 8;
                          curr_light->emitter = mi_api_function_append(
                                                curr_light->emitter, $2); }
                | SHADOWMAP
                        { curr_light->use_shadow_maps = miTRUE; }
                | SHADOWMAP boolean
                        { curr_light->use_shadow_maps = $2; }
                | ORIGIN vector
                        { curr_light->origin = $2;
                          light_map |= 2; }
                | DIRECTION vector
                        { curr_light->direction = $2;
                          mi_vector_normalize(&curr_light->direction);
                          light_map |= 4; }
                | ENERGY floating floating floating
                        { curr_light->energy.r = $2;
                          curr_light->energy.g = $3;
                          curr_light->energy.b = $4; }
                | EXPONENT floating
                        { curr_light->exponent = $2; }
                | CAUSTIC PHOTONS T_INTEGER
                        { curr_light->caustic_store_photons = $3;
                          curr_light->caustic_emit_photons = 0; }
                | CAUSTIC PHOTONS T_INTEGER T_INTEGER
                        { curr_light->caustic_store_photons = $3;
                          curr_light->caustic_emit_photons = $4; }
                | GLOBILLUM PHOTONS T_INTEGER
                        { curr_light->global_store_photons = $3;
                          curr_light->global_emit_photons = 0; }
                | GLOBILLUM PHOTONS T_INTEGER T_INTEGER
                        { curr_light->global_store_photons = $3;
                          curr_light->global_emit_photons = $4; }
                | RECTANGLE vector vector light_samples
                        { curr_light->area = miLIGHT_RECTANGLE;
                          curr_light->primitive.rectangle.edge_u = $2;
                          curr_light->primitive.rectangle.edge_v = $3; }
                | DISC vector floating light_samples
                        { curr_light->area = miLIGHT_DISC;
                          curr_light->primitive.disc.normal      = $2;
                          curr_light->primitive.disc.radius      = $3; }
                | SPHERE floating light_samples
                        { curr_light->area = miLIGHT_SPHERE;
                          curr_light->primitive.sphere.radius    = $2; }
                | CYLINDER vector floating light_samples
                        { curr_light->area = miLIGHT_CYLINDER;
                          curr_light->primitive.cylinder.axis    = $2;
                          curr_light->primitive.cylinder.radius  = $3; }
                | RECTANGLE
                        { curr_light->area = miLIGHT_NONE; }
                | DISC
                        { curr_light->area = miLIGHT_NONE; }
                | SPHERE
                        { curr_light->area = miLIGHT_NONE; }
                | CYLINDER
                        { curr_light->area = miLIGHT_NONE; }
                | SPREAD floating
                        { curr_light->spread = $2; }
                | SHADOWMAP RESOLUTION T_INTEGER
                        { curr_light->shadowmap_resolution = $3; }
                | SHADOWMAP SOFTNESS floating
                        { curr_light->shadowmap_softness = $3; }
                | SHADOWMAP SAMPLES T_INTEGER
                        { curr_light->shadowmap_samples = $3; }
                | SHADOWMAP FILE_ T_STRING
                        { mi_scene_delete(curr_light->shadowmap_file);
                          strcpy((char *)mi_scene_create(
                                        &curr_light->shadowmap_file,
                                        miSCENE_STRING, strlen($3)+1), $3);
                          mi_db_unpin(curr_light->shadowmap_file);
                          mi_mem_release($3); }
                | VISIBLE
                        { curr_light->visible = miTRUE; }
                | VISIBLE boolean
                        { curr_light->visible = $2; }
                | TAG T_INTEGER
                        { curr_light->label = $2; }
                |       { curr_datatag = &curr_light->userdata; }
                  data
                ;

light_samples :
                | T_INTEGER T_INTEGER
                        { curr_light->samples_u     = $1;
                          curr_light->samples_v     = $2; }
                | T_INTEGER T_INTEGER T_INTEGER
                        { curr_light->samples_u     = $1;
                          curr_light->samples_v     = $2;
                          curr_light->low_level     = $3; }
                | T_INTEGER T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                        { curr_light->samples_u     = $1;
                          curr_light->samples_v     = $2;
                          curr_light->low_level     = $3;
                          curr_light->low_samples_u = $4;
                          curr_light->low_samples_v = $5; }
                ;


/*-----------------------------------------------------------------------------
 * material
 *---------------------------------------------------------------------------*/

material : MATERIAL symbol
                        { curr_mtl = mi_api_material_begin($2);
                          have_d = have_s = have_v =
                          have_e = have_c = have_p = have_pv = 0; }
                  mtl_flags
                  function_list
                        { curr_mtl->shader = $5; }
                  mtl_args
                  END MATERIAL
                        { mi_api_material_end(); }
                ;

mtl_flags :
                | mtl_flag mtl_flags
                ;

mtl_flag : NOCONTOUR
                        { mi_api_warning(
                                "obsolete \"nocontour\" flag ignored"); }
                | OPAQUE_
                        { curr_mtl->opaque = miTRUE; }
                ;

mtl_args :
                | mtl_arg mtl_args
                ;

mtl_arg : DISPLACE
                        { mi_api_function_delete(&curr_mtl->displace); }
                | DISPLACE function_list
                        { if (!have_d++)
                                mi_api_function_delete(&curr_mtl->displace);
                          curr_mtl->displace = $2; }
                | SHADOW
                        { mi_api_function_delete(&curr_mtl->shadow); }
                | SHADOW function_list
                        { if (!have_s++)
                                mi_api_function_delete(&curr_mtl->shadow);
                          curr_mtl->shadow = $2; }
                | VOLUME
                        { mi_api_function_delete(&curr_mtl->volume); }
                | VOLUME function_list
                        { if (!have_v++)
                                mi_api_function_delete(&curr_mtl->volume);
                          curr_mtl->volume = $2; }
                | ENVIRONMENT
                        { mi_api_function_delete(&curr_mtl->environment); }
                | ENVIRONMENT function_list
                        { if (!have_e++)
                                mi_api_function_delete(&curr_mtl->environment);
                          curr_mtl->environment = $2; }
                | CONTOUR
                        { mi_api_function_delete(&curr_mtl->contour); }
                | CONTOUR function_list
                        { if (!have_c++)
                                mi_api_function_delete(&curr_mtl->contour);
                          curr_mtl->contour = $2; }
                | PHOTON
                        { mi_api_function_delete(&curr_mtl->photon); }
                | PHOTON function_list
                        { if (!have_p++)
                                mi_api_function_delete(&curr_mtl->photon);
                          curr_mtl->photon = $2; }
                | PHOTONVOL
                        { mi_api_function_delete(&curr_mtl->photonvol); }
                | PHOTONVOL function_list
                        { if (!have_pv++)
                              mi_api_function_delete(&curr_mtl->photonvol);
                          curr_mtl->photonvol = $2; }
                ;


/*-----------------------------------------------------------------------------
 * object
 *---------------------------------------------------------------------------*/

object : OBJECT opt_symbol
                        { curr_obj = mi_api_object_begin($2); }
                  obj_flags
                  bases_and_groups
                  END OBJECT
                        { mi_api_object_end(); }
                ;

obj_flags :
                | obj_flag obj_flags
                ;

obj_flag : VISIBLE
                        { curr_obj->visible = miTRUE; }
                | VISIBLE boolean
                        { curr_obj->shadow = $2; }
                | SHADOW
                        { curr_obj->shadow = miTRUE; }
                | SHADOW boolean
                        { curr_obj->shadow = $2; }
                | TRACE
                        { curr_obj->trace = miTRUE; }
                | TRACE boolean
                        { curr_obj->trace = $2; }
                | TAGGED
                        { curr_obj->mtl_is_label = miTRUE; }
                | TAGGED boolean
                        { curr_obj->mtl_is_label = $2; }
                | CAUSTIC
                        { curr_obj->caustic |= 3; }
                | CAUSTIC boolean
                        { curr_obj->caustic &= 0x03;
                          if (!$2)
                                  curr_obj->caustic |= 0x10; }
                | CAUSTIC T_INTEGER
                        { curr_obj->caustic &= 0x10;
                          curr_obj->caustic |= ($2 & 0x03); }
                | GLOBILLUM
                        { curr_obj->globillum |= 3; }
                | GLOBILLUM boolean
                        { curr_obj->globillum &= 0x03;
                          if (!$2)
                                  curr_obj->globillum |= 0x10; }
                | GLOBILLUM T_INTEGER
                        { curr_obj->globillum &= 0x10;
                          curr_obj->globillum |= ($2 & 0x03); }
                | TAG T_INTEGER
                        { curr_obj->label = $2; }
                |       { curr_datatag = &curr_obj->userdata; }
                  data
                | transform
                        { mi_api_object_matrix($1); }
                | MAX_ DISPLACE floating
                        { curr_obj->maxdisplace = $3; }
                ;

bases_and_groups:
                | basis bases_and_groups
                | group bases_and_groups
                ;

basis : BASIS symbol rational MATRIX T_INTEGER T_INTEGER basis_matrix
                        { mi_api_basis_add($2, $3, miBASIS_MATRIX, $5,$6,$7); }
                | BASIS symbol rational BEZIER T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_BEZIER, $5, 0, 0); }
                | BASIS symbol rational TAYLOR T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_TAYLOR, $5, 0, 0); }
                | BASIS symbol rational BSPLINE T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_BSPLINE, $5, 0, 0);}
                | BASIS symbol rational CARDINAL
                        { mi_api_basis_add($2, $3, miBASIS_CARDINAL, 0, 0, 0);}
                ;

rational :
                        { $$ = miFALSE; }
                | RATIONAL
                        { $$ = miTRUE; }
                ;

basis_matrix : { $$ = mi_api_dlist_create(miDLIST_GEOSCALAR); }
                | basis_matrix floating
                        { miGeoScalar s=$2; mi_api_dlist_add($1, &s); $$=$1; }
                ;

group : GROUP opt_symbol merge_option
                        { mi_api_object_group_begin($3);
                          mi_mem_release($2); }
                  vector_list
                  vertex_list
                  geometry_list
                  END GROUP
                        { mi_api_object_group_end(); }
                ;

merge_option :
                        { $$ = 0.0; }
                | MERGE floating
                        { $$ = $2; }
                ;

vector_list :
                | vector_list geovector
                        { mi_api_geovector_xyz_add(&$2); }
                ;

vertex_list :
                | vertex_list vertex
                ;

vertex : V T_INTEGER
                        { mi_api_vertex_add($2); }
                  n_vector
                  d_vector
                  t_vector_list
                  m_vector
                  u_vector_list
                  vertex_flag
                ;

n_vector :
                | N T_INTEGER
                        { mi_api_vertex_normal_add($2); }
                ;

d_vector :
                | D T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv_add($2, $3); }
                | D T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv2_add($2, $3, $4); }
                | D T_INTEGER T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv_add($2, $3);
                          mi_api_vertex_deriv2_add($4, $5, $6); }
                ;

m_vector :
                | M T_INTEGER
                        { mi_api_vertex_motion_add($2); }
                ;

t_vector_list :
                | t_vector_list T T_INTEGER
                        { mi_api_vertex_tex_add($3, -1, -1); }
                | t_vector_list T T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_tex_add($3, $4, $5); }
                ;

u_vector_list :
                | u_vector_list U T_INTEGER
                        { mi_api_vertex_user_add($3); }
                ;

vertex_flag :
                | CUSP
                        { mi_api_vertex_flags_add(miAPI_V_CUSP, 1); }
                | CUSP floating
                        { mi_api_vertex_flags_add(miAPI_V_CUSP, $2); }
                | CONIC
                        { mi_api_vertex_flags_add(miAPI_V_CONIC, 1); }
                | CONIC floating
                        { mi_api_vertex_flags_add(miAPI_V_CONIC, $2); }
                | CORNER
                        { mi_api_vertex_flags_add(miAPI_V_CORNER, 0); }
                | DART
                        { mi_api_vertex_flags_add(miAPI_V_DART, 0); }
                ;


geometry_list :
                | geometry_list geometry
                ;

geometry : polygon
                | curve
                | spacecurve
                | surface
                | subdivsurf
                | connection
                | approximation
        /*      | implicit_patch        */
                ;


/* polygons */

polygon : CP opt_symbol
                        { mi_api_poly_begin(1, $2); }
                  poly_indices
                        { mi_api_poly_end(); }
                | P opt_symbol
                        { mi_api_poly_begin(0, $2); }
                  poly_indices
                        { mi_api_poly_end(); }
                | STRIP opt_symbol
                        { mi_api_poly_begin(2, $2); }
                  strip_indices
                        { mi_api_poly_end(); }
                | FAN opt_symbol
                        { mi_api_poly_begin(3, $2); }
                  strip_indices
                        { mi_api_poly_end(); }
                ;

poly_indices :
                | T_INTEGER
                        { mi_api_poly_index_add($1); }
                  poly_indices
                | HOLE
                        { mi_api_poly_hole_add(); }
                  poly_indices
                ;

strip_indices :
                | T_INTEGER
                        { mi_api_poly_index_add($1); }
                  strip_indices
                ;

h_vertex_ref_seq: h_vertex_ref
                | h_vertex_ref_seq h_vertex_ref
                ;

h_vertex_ref : T_INTEGER
                        { mi_api_vertex_ref_add($1, (double)1.0); }
                | T_INTEGER T_FLOAT
                        { mi_api_vertex_ref_add($1, $2); }
                | T_INTEGER W floating
                        { mi_api_vertex_ref_add($1, $3); }
                ;


para_list : T_FLOAT
                        { miDlist *dlp =mi_api_dlist_create(miDLIST_GEOSCALAR);
                          miGeoScalar s = $1;   /* $1 is a double */
                          mi_api_dlist_add(dlp, &s);
                          $$ = dlp; }
                | para_list T_FLOAT
                        { miGeoScalar s = $2;   /* $2 is a double */
                          mi_api_dlist_add($1, &s);
                          $$ = $1; }
                ;


/* curves and space curves */

curve : CURVE symbol rational symbol
                        { mi_api_curve_begin($2, $4, $3); }
                  para_list h_vertex_ref_seq curve_spec
                        { mi_api_curve_end($6); }
                ;

curve_spec :
                | SPECIAL curve_special_list
                ;

curve_special_list
                : curve_special
                | curve_special_list curve_special
                ;

curve_special : T_INTEGER
                        { mi_api_curve_specpnt($1, -1); }
                | T_INTEGER MAPSTO T_INTEGER
                        { mi_api_curve_specpnt($1, $3); }
                ;

spacecurve : SPACE CURVE symbol
                        { mi_api_spacecurve_begin($3); }
                  spcurve_list
                        { mi_api_spacecurve_end(); }
                ;

spcurve_list : symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_spacecurve_curveseg(miTRUE, $1, &r); }
                | spcurve_list symbol floating floating
                        { miGeoRange r;
                          r.min = $3;
                          r.max = $4;
                          mi_api_spacecurve_curveseg(miFALSE, $2, &r); }
                ;


/* free-form surfaces */

surface : SURFACE symbol mtl_or_label
                        { mi_api_surface_begin($2, $3); }
                  rational symbol floating floating para_list
                        { mi_api_surface_params(miU, $6, $7, $8, $9, $5); }
                  rational symbol floating floating para_list
                        { mi_api_surface_params(miV, $12, $13, $14, $15, $11);}
                  h_vertex_ref_seq
                  tex_surf_list
                  surf_spec_list
                        { mi_api_surface_end(); }
                ;

mtl_or_label : symbol
                        { $$ = $1; }
                | T_INTEGER
                        { $$ = (char *)(miIntptr)$1; }
                ;

tex_surf_list :
                | tex_surf_list tex_surf
                ;

tex_surf : opt_volume_flag opt_vector_flag TEXTURE
                  rational symbol para_list
                  rational symbol para_list
                        { mi_api_surface_texture_begin(
                                        $1, $2, $5, $6, $4, $8, $9, $7); }
                  h_vertex_ref_seq

                | DERIVATIVE
                        { mi_api_surface_derivative(1); }
                | DERIVATIVE T_INTEGER
                        { mi_api_surface_derivative($2); }
                | DERIVATIVE T_INTEGER T_INTEGER
                        { mi_api_surface_derivative($2);
                          mi_api_surface_derivative($3); }
                ;

opt_volume_flag :
                        { $$ = miFALSE; }
                | VOLUME
                        { $$ = miTRUE; }
                ;

opt_vector_flag :
                        { $$ = miFALSE; }
                | VECTOR
                        { $$ = miTRUE; }
                ;


surf_spec_list :
                | surf_spec_list surf_spec
                ;

surf_spec : TRIM trim_spec_list
                | HOLE hole_spec_list
                | SPECIAL
                        { newloop = miTRUE; }
                  special_spec_list
                ;

trim_spec_list : symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(miTRUE, miCURVE_TRIM,$1,&r);}
                | trim_spec_list symbol floating floating
                        { miGeoRange r;
                          r.min = $3;
                          r.max = $4;
                          mi_api_surface_curveseg(miFALSE,miCURVE_TRIM,$2,&r);}
                ;

hole_spec_list : symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(miTRUE,miCURVE_HOLE,$1,&r); }
                | hole_spec_list symbol floating floating
                        { miGeoRange r;
                          r.min = $3;
                          r.max = $4;
                          mi_api_surface_curveseg(miFALSE,miCURVE_HOLE,$2,&r);}
                ;

special_spec_list
                : special_spec
                | special_spec_list special_spec
                ;

special_spec : T_INTEGER
                        { mi_api_surface_specpnt($1, -1); }
                | T_INTEGER MAPSTO T_INTEGER
                        { mi_api_surface_specpnt($1, $3); }
                | symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(newloop,
                                                  miCURVE_SPECIAL, $1, &r);
                          newloop = miFALSE; }
                ;

connection : CONNECT
                  symbol symbol floating floating
                  symbol symbol floating floating
                        { miGeoRange c1, c2;
                          c1.min = $4;
                          c1.max = $5;
                          c2.min = $8;
                          c2.max = $9;
                          mi_api_object_group_connection($2,$3,&c1,$6,$7,&c2);}
                ;


/* subdivision surfaces */

subdivsurf : SUBDIVISION SURFACE symbol
                        { mi_api_subdivsurf_begin($3); }
                  sds_base_polys END SUBDIVISION SURFACE
                        { mi_api_subdivsurf_end(); }
                ;

sds_base_polys :
                | sds_base_poly sds_base_polys
                ;

sds_base_poly : P opt_symbol
                        { mi_api_subdivsurf_poly(3);
                          mi_api_subdivsurf_mtl($2); }
                  sds_indices sds_flags sds_subdiv_base
                | Q opt_symbol
                        { mi_api_subdivsurf_poly(4);
                          mi_api_subdivsurf_mtl($2); }
                  sds_indices sds_flags sds_subdiv_base
                ;

sds_subdiv_base :
                | '{'
                        { mi_api_subdivsurf_push();
                          mi_api_subdivsurf_kit(); }
                  sds_materials sds_indices sds_flags sds_subdiv_subs '}'
                        { mi_api_subdivsurf_pop(); }
                ;

sds_subdiv_subs :
                | '{'
                        { mi_api_subdivsurf_push(); }
                  sds_sub_polys '}'
                        { mi_api_subdivsurf_pop(); }
                ;

sds_sub_polys : sds_sub_poly
                | sds_sub_poly ',' sds_sub_polys
                ;

sds_sub_poly :
                        { mi_api_subdivsurf_kit(); }
                |
                        { mi_api_subdivsurf_kit(); }
                  sds_materials sds_indices sds_flags sds_subdiv_subs
                ;

sds_materials :
                | symbol
                        { mi_api_subdivsurf_mtl($1); }
                  sds_materials
                ;

sds_indices : T_INTEGER
                        { mi_api_subdivsurf_index($1); }
                | T_INTEGER
                        { mi_api_subdivsurf_index($1); }
                  sds_indices
                ;

sds_flags :
                | CREASE floating
                        { mi_api_subdivsurf_flags(miAPI_E_CREASE, $2); }
                  sds_creaseflags
                ;

sds_creaseflags :
                | floating
                        { mi_api_subdivsurf_flags(miAPI_E_CREASE, $1); }
                  sds_creaseflags;
                ;


/*-----------------------------------------------------------------------------
 * approximations (in objects and options)
 *---------------------------------------------------------------------------*/

approximation : { miAPPROX_DEFAULT(approx); }
                  approx_body
                ;

approx_body : APPROXIMATE SURFACE s_approx_tech s_approx_names
                | APPROXIMATE SUBDIVISION SURFACE
                                       c_approx_tech sds_approx_names
                | APPROXIMATE DISPLACE s_approx_tech d_approx_names
                | APPROXIMATE CURVE    c_approx_tech c_approx_names
                | APPROXIMATE SPACE CURVE
                                       c_approx_tech spc_approx_names
                | APPROXIMATE TRIM     c_approx_tech t_approx_names
                | APPROXIMATE          s_approx_tech
                        { mi_api_poly_approx(&approx); }
                ;

s_approx_tech : s_approx_params
                        { approx.subdiv[miMIN]  = 0;
                          approx.subdiv[miMAX]  = 5;
                          approx.max            = miHUGE_INT; }
                | s_approx_params T_INTEGER T_INTEGER
                        { approx.subdiv[miMIN]  = $2;
                          approx.subdiv[miMAX]  = $3;
                          approx.max            = miHUGE_INT; }
                | s_approx_params MAX_ T_INTEGER
                        { approx.subdiv[miMIN]  = 0;
                          approx.subdiv[miMAX]  = 5;
                          approx.max            = $3; }
                | s_approx_params T_INTEGER T_INTEGER MAX_ T_INTEGER
                        { approx.subdiv[miMIN]  = $2;
                          approx.subdiv[miMAX]  = $3;
                          approx.max            = $5; }
                ;

c_approx_tech : c_approx_params
                        { approx.subdiv[miMIN]  = 0;
                          approx.subdiv[miMAX]  = 5; }
                | c_approx_params T_INTEGER T_INTEGER
                        { approx.subdiv[miMIN]  = $2;
                          approx.subdiv[miMAX]  = $3; }
                ;

s_approx_params : s_approx_param
                | s_approx_param s_approx_params
                ;

c_approx_params : c_approx_param
                | c_approx_param c_approx_params
                ;

s_approx_param : x_approx_param
                | PARAMETRIC floating floating
                        { approx.method                 = miAPPROX_PARAMETRIC;
                          approx.cnst[miCNST_UPARAM]    = $2;
                          approx.cnst[miCNST_VPARAM]    = $3; }
                | REGULAR PARAMETRIC floating floating
                        { approx.method                 = miAPPROX_REGULAR;
                          approx.cnst[miCNST_UPARAM]    = $3;
                          approx.cnst[miCNST_VPARAM]    = $4; }
                | IMPLICIT
                        { approx.method                 = miAPPROX_ALGEBRAIC; }
                ;

c_approx_param : x_approx_param
                | PARAMETRIC floating
                        { approx.method                 = miAPPROX_PARAMETRIC;
                          approx.cnst[miCNST_UPARAM]    = $2;
                          approx.cnst[miCNST_VPARAM]    = 1.0; }
                | REGULAR PARAMETRIC floating
                        { approx.method                 = miAPPROX_REGULAR;
                          approx.cnst[miCNST_UPARAM]    = $3;
                          approx.cnst[miCNST_VPARAM]    = 1.0; }
                ;

x_approx_param : VIEW
                        { approx.view_dep       = miTRUE; }
                | ANY
                        { approx.any            = miTRUE; }
                | TREE
                        { approx.style          = miAPPROX_STYLE_TREE; }
                | GRID
                        { approx.style          = miAPPROX_STYLE_GRID; }
                | DELAUNAY
                        { approx.style          = miAPPROX_STYLE_DELAUNAY; }
                | LENGTH floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_LENGTH]    = $2; }
                | DISTANCE floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_DISTANCE]  = $2; }
                | ANGLE floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_ANGLE]     = $2; }
                | SPATIAL approx_view floating
                        { approx.method                 = miAPPROX_SPATIAL;
                          approx.cnst[miCNST_LENGTH]    = $3; }
                | CURVATURE approx_view floating floating
                        { approx.method                 = miAPPROX_CURVATURE;
                          approx.cnst[miCNST_DISTANCE]  = $3;
                          approx.cnst[miCNST_ANGLE]     = $4; }
                | GRADING floating
                        { approx.grading                = $2; }
                ;

approx_view :
                | VIEW
                        { approx.view_dep               = miTRUE; }
                ;

s_approx_names : symbol
                        { mi_api_surface_approx($1, &approx); }
                | s_approx_names symbol
                        { mi_api_surface_approx($2, &approx); }
                ;

sds_approx_names: symbol
                        { mi_api_subdivsurf_approx($1, &approx); }
                | sds_approx_names symbol
                        { mi_api_subdivsurf_approx($2, &approx); }
                ;

d_approx_names : symbol
                        { mi_api_surface_approx_displace($1, &approx); }
                | s_approx_names symbol
                        { mi_api_surface_approx_displace($2, &approx); }
                ;

c_approx_names : symbol
                        { mi_api_curve_approx($1, &approx); }
                | c_approx_names symbol
                        { mi_api_curve_approx($2, &approx); }
                ;

spc_approx_names: symbol
                        { mi_api_spacecurve_approx($1, &approx); }
                | c_approx_names symbol
                        { mi_api_spacecurve_approx($2, &approx); }
                ;

t_approx_names : symbol
                        { mi_api_surface_approx_trim($1, &approx); }
                | t_approx_names symbol
                        { mi_api_surface_approx_trim($2, &approx); }
                ;


/*-----------------------------------------------------------------------------
 * user-interface commands
 *---------------------------------------------------------------------------*/

gui : GUI opt_symbol
                        { mi_api_gui_begin($2); }
                  '(' gui_attr_list ')' '{' gui_controls '}'
                        { mi_api_gui_end(); }
                | GUI opt_symbol
                        { mi_api_gui_begin($2); }
                  '{' gui_controls '}'
                        { mi_api_gui_end(); }
                ;

gui_elems :
                | gui_elem gui_elems
                ;

gui_elem : '(' gui_attr_list ')'
                | '{'
                        { mi_api_gui_push(); }
                  gui_controls '}'
                        { mi_api_gui_pop(); }
                ;

gui_controls :
                | gui_control gui_controls
                ;

gui_control : CONTROL symbol opt_symbol
                        { mi_api_gui_control_begin($3?$2:0, $3?$3:$2); }
                  gui_elems
                        { mi_api_gui_control_end(); }
                ;

gui_attr_list :
                | ','
                | gui_attr
                | gui_attr ',' gui_attr_list
                ;

gui_attr : symbol
                        { mi_api_gui_attr($1, miNTYPES, 0); }
                | symbol boolean
                        { mi_api_gui_attr($1, miTYPE_BOOLEAN, 1, $2); }
                | symbol floating
                        { mi_api_gui_attr($1, miTYPE_SCALAR, 1, $2); }
                | symbol floating floating
                        { mi_api_gui_attr($1, miTYPE_SCALAR, 2, $2, $3); }
                | symbol floating floating floating
                        { mi_api_gui_attr($1, miTYPE_SCALAR, 3, $2, $3, $4); }
                | symbol floating floating floating floating
                        { mi_api_gui_attr($1, miTYPE_SCALAR, 4, $2,$3,$4,$5); }
                | symbol symbol
                        { mi_api_gui_attr($1, miTYPE_STRING, 1, $2); }
                ;
%%


next up previous contents
Next: Bibliography Up: No Title Previous: 6.3 Shader Writing
Copyright 2000 by mental images