open_toontown_panda3d/panda/src/egg/parser.yxx

2254 lines
46 KiB
Plaintext

// Filename: parser.y
// Created by: drose (16Jan99)
//
////////////////////////////////////////////////////////////////////
%{
#include <pandabase.h>
#include "parserDefs.h"
#include "lexerDefs.h"
#include "eggObject.h"
#include "eggGroup.h"
#include "eggVertex.h"
#include "eggVertexPool.h"
#include "eggPolygon.h"
#include "eggPoint.h"
#include "eggNurbsSurface.h"
#include "eggNurbsCurve.h"
#include "eggTable.h"
#include "eggSAnimData.h"
#include "eggXfmSAnim.h"
#include "eggXfmAnimData.h"
#include "eggTexture.h"
#include "eggMaterial.h"
#include "eggComment.h"
#include "eggCoordinateSystem.h"
#include "eggExternalReference.h"
#include "eggData.h"
#include <string_utils.h>
#include <filename.h>
#include <luse.h>
#include <lmatrix.h>
#include <coordinateSystem.h>
#include <vector>
// Because our token type contains objects of type string, which
// require correct copy construction (and not simply memcpying), we
// cannot use bison's built-in auto-stack-grow feature. As an easy
// solution, we ensure here that we have enough yacc stack to start
// with, and that it doesn't ever try to grow.
#define YYINITDEPTH 1000
#define YYMAXDEPTH 1000
// We need a stack of EggObject pointers. Each time we encounter a
// nested EggObject of some kind, we'll allocate a new one of these
// and push it onto the stack. At any given time, the top of the
// stack is the EggObject we are currently scanning.
typedef vector<PT(EggObject)> EggStack;
static EggStack egg_stack;
// There's one "top-level" egg node, which is where we should parent
// things (e.g. textures) encountered in the egg file that don't have
// an explicit place in the tree. If this is NULL, such things won't
// be parented anywhere.
static EggGroupNode *egg_top_node;
// We need a table mapping vertex pool names to vertex pools.
typedef map<string, PT(EggVertexPool)> VertexPools;
static VertexPools vertex_pools;
// And another one mapping texture names to textures.
typedef map<string, PT(EggTexture)> Textures;
static Textures textures;
// And again for material names to materials.
typedef map<string, PT(EggMaterial)> Materials;
static Materials materials;
// We need to be able to save the index number requested for a vertex
// temporarily.
static int vertex_index;
// We need to hold a matrix for a little bit while parsing the
// <Transform> entries.
static LMatrix4d matrix_3d;
static LMatrix3d matrix_2d;
////////////////////////////////////////////////////////////////////
// Defining the interface to the parser.
////////////////////////////////////////////////////////////////////
void
egg_init_parser(istream &in, const string &filename,
EggObject *tos, EggGroupNode *top_node) {
egg_init_lexer(in, filename);
egg_stack.clear();
vertex_pools.clear();
textures.clear();
materials.clear();
egg_stack.push_back(tos);
egg_top_node = top_node;
}
void
egg_cleanup_parser() {
// Clean these out after we're done, so we don't keep big memory
// structures around needlessly.
egg_stack.clear();
vertex_pools.clear();
textures.clear();
materials.clear();
}
%}
%token <_number> NUMBER
%token <_string> STRING
%token BEZIERCURVE BFACE BILLBOARD BUNDLE CLOSED COLLIDE COMMENT
%token COORDSYSTEM CV DART
%token DNORMAL DRGBA DUV DXYZ DCS DISTANCE DTREF
%token DYNAMICVERTEXPOOL EXTERNAL_FILE
%token FLIGHT GROUP HIP INTANGENT
%token JOINT KNOTS INCLUDE
%token INSTANCE LOOP MATERIAL MATRIX3 MATRIX4 MODEL MREF NORMAL
%token NURBSCURVE NURBSSURFACE OBJECTTYPE ORDER
%token OUTTANGENT POINTLIGHT POLYGON REF RGBA ROTATE ROTX ROTY ROTZ
%token SANIM SCALAR SCALE SEQUENCE SHADING SWITCH SWITCHCONDITION
%token TABLE TABLE_V TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE
%token TREF TRIM TXT UKNOTS UV VKNOTS VERTEX VERTEXANIM
%token VERTEXPOOL VERTEXREF
%token XFMANIM XFMSANIM
/* These special tokens are used to set the starting state of the
parser. The lexer places the appropriate one of these on the head
of the input stream. */
%token START_EGG
%token START_GROUP_BODY
%type <_egg> node
%type <_egg> coordsystem
%type <_egg> comment
%type <_egg> texture
%type <_egg> material
%type <_egg> external_reference
%type <_egg> vertex_pool
%type <_egg> group
%type <_egg> joint
%type <_egg> instance
%type <_egg> polygon
%type <_egg> point_light
%type <_egg> nurbs_surface
%type <_egg> nurbs_curve
%type <_egg> table
%type <_egg> bundle
%type <_egg> sanim
%type <_egg> xfmanim
%type <_egg> xfm_s_anim
%type <_string> required_name optional_name
%type <_string> required_string optional_string
%type <_string> string
%type <_string> repeated_string repeated_string_body
%type <_number> group_vertex_membership
%type <_number_list> integer_list
%type <_number_list> real_list
%type <_egg> texture_name
%type <_egg> material_name
%type <_egg> vertex_pool_name
%type <_number> real
%type <_number> integer
%type <_number> real_or_string
%%
grammar:
START_EGG egg
| START_GROUP_BODY group_body
;
/*
* egg
*
* enter: TOS is EggData.
* exit: egg file has been completely read.
*
*/
egg:
empty
| egg node
{
DCAST(EggData, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
;
/*
* node
*
* enter:
* exit: returns a new EggNode of some kind.
*
*/
node:
coordsystem
| comment
| texture
| material
| external_reference
| vertex_pool
| group
| joint
| instance
| polygon
| point_light
| nurbs_surface
| nurbs_curve
| table
;
/*
* coordsystem
*
* enter:
* exit: returns a new EggCoordinateSystem.
*
*/
coordsystem:
COORDSYSTEM '{' required_string '}'
{
string strval = $3;
EggCoordinateSystem *cs = new EggCoordinateSystem;
CoordinateSystem f = parse_coordinate_system_string(strval);
if (f == CS_invalid) {
eggyywarning("Unknown coordinate system " + strval);
} else {
cs->set_value(f);
}
$$ = cs;
}
;
/*
* comment
*
* enter:
* exit: returns a new EggComment.
*
*/
comment:
COMMENT optional_name '{' repeated_string '}'
{
$$ = new EggComment($2, $4);
}
;
/*
* texture
*
* enter:
* exit: returns a new EggTexture.
*
*/
texture:
TEXTURE required_name '{' required_string
{
string tref_name = $2;
Filename filename = $4;
EggTexture *texture = new EggTexture(tref_name, filename);
if (textures.find(tref_name) != textures.end()) {
eggyywarning("Duplicate texture name " + tref_name);
}
textures[tref_name] = texture;
egg_stack.push_back(texture);
}
texture_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* texture_body
*
* enter: TOS is EggTexture; filename has already been read.
* exit: texture contents have been filled.
*
*/
texture_body:
empty
| texture_body SCALAR required_name '{' real_or_string '}'
{
EggTexture *texture = DCAST(EggTexture, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "format") == 0) {
EggTexture::Format f = EggTexture::string_format(strval);
if (f == EggTexture::F_unspecified) {
eggyywarning("Unknown texture format " + strval);
} else {
texture->set_format(f);
}
} else if (cmp_nocase_uh(name, "wrap") == 0) {
EggTexture::WrapMode w = EggTexture::string_wrap_mode(strval);
if (w == EggTexture::WM_unspecified) {
eggyywarning("Unknown texture wrap mode " + strval);
} else {
texture->set_wrap_mode(w);
}
} else if (cmp_nocase_uh(name, "wrapu") == 0) {
EggTexture::WrapMode w = EggTexture::string_wrap_mode(strval);
if (w == EggTexture::WM_unspecified) {
eggyywarning("Unknown texture wrap mode " + strval);
} else {
texture->set_wrap_u(w);
}
} else if (cmp_nocase_uh(name, "wrapv") == 0) {
EggTexture::WrapMode w = EggTexture::string_wrap_mode(strval);
if (w == EggTexture::WM_unspecified) {
eggyywarning("Unknown texture wrap mode " + strval);
} else {
texture->set_wrap_v(w);
}
} else if (cmp_nocase_uh(name, "minfilter") == 0) {
EggTexture::FilterType f = EggTexture::string_filter_type(strval);
if (f == EggTexture::FT_unspecified) {
eggyywarning("Unknown texture filter type " + strval);
} else {
texture->set_minfilter(f);
}
} else if (cmp_nocase_uh(name, "magfilter") == 0) {
EggTexture::FilterType f = EggTexture::string_filter_type(strval);
if (f == EggTexture::FT_unspecified) {
eggyywarning("Unknown texture filter type " + strval);
} else {
texture->set_magfilter(f);
}
} else if (cmp_nocase_uh(name, "magfilteralpha") == 0) {
EggTexture::FilterType f = EggTexture::string_filter_type(strval);
if (f == EggTexture::FT_unspecified) {
eggyywarning("Unknown texture filter type " + strval);
} else {
texture->set_magfilteralpha(f);
}
} else if (cmp_nocase_uh(name, "magfiltercolor") == 0) {
EggTexture::FilterType f = EggTexture::string_filter_type(strval);
if (f == EggTexture::FT_unspecified) {
eggyywarning("Unknown texture filter type " + strval);
} else {
texture->set_magfiltercolor(f);
}
} else if (cmp_nocase_uh(name, "anisotropic_degree") == 0) {
texture->set_anisotropic_degree(value);
} else if (cmp_nocase_uh(name, "envtype") == 0) {
EggTexture::EnvType e = EggTexture::string_env_type(strval);
if (e == EggTexture::ET_unspecified) {
eggyywarning("Unknown texture env type " + strval);
} else {
texture->set_env_type(e);
}
} else if (cmp_nocase_uh(name, "alpha") == 0) {
EggAlphaMode::AlphaMode a = EggAlphaMode::string_alpha_mode(strval);
if (a == EggAlphaMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
texture->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
texture->set_draw_order(value);
} else if (cmp_nocase_uh(name, "alpha_file") == 0) {
texture->set_alpha_file(strval);
} else {
eggyywarning("Unsupported texture scalar: " + name);
}
}
| texture_body transform_2d
;
/*
* material
*
* enter:
* exit: returns a new EggMaterial.
*
*/
material:
MATERIAL required_name '{'
{
string mref_name = $2;
EggMaterial *material = new EggMaterial(mref_name);
if (materials.find(mref_name) != materials.end()) {
eggyywarning("Duplicate material name " + mref_name);
}
materials[mref_name] = material;
egg_stack.push_back(material);
}
material_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* material_body
*
* enter: TOS is EggMaterial; filename has already been read.
* exit: material contents have been filled.
*
*/
material_body:
empty
| material_body SCALAR required_name '{' real_or_string '}'
{
EggMaterial *material = DCAST(EggMaterial, egg_stack.back());
string name = $3;
double value = $<_number>5;
if (cmp_nocase_uh(name, "diffr") == 0) {
Colorf diff = material->get_diff();
diff[0] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "diffg") == 0) {
Colorf diff = material->get_diff();
diff[1] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "diffb") == 0) {
Colorf diff = material->get_diff();
diff[2] = value;
material->set_diff(diff);
} else {
eggyywarning("Unsupported material scalar: " + name);
}
}
;
/*
* external_reference
*
* enter:
* exit: returns a new EggExternalReference.
*
*/
external_reference:
EXTERNAL_FILE optional_name '{' required_string '}'
{
string node_name = $2;
Filename filename = $4;
EggExternalReference *ref = new EggExternalReference(node_name, filename);
$$ = ref;
}
| string EXTERNAL_FILE optional_name '{' required_string '}'
{
if (cmp_nocase_uh($1, "group") != 0) {
eggyyerror("keyword 'group' expected");
}
string node_name = $3;
Filename filename = $5;
EggExternalReference *ref = new EggExternalReference(node_name, filename);
$$ = ref;
}
;
/*
* vertex_pool
*
* enter:
* exit: returns a new EggVertexPool.
*
*/
vertex_pool:
VERTEXPOOL required_name
{
string name = $2;
EggVertexPool *pool = new EggVertexPool(name);
if (vertex_pools.find(name) != vertex_pools.end()) {
eggyywarning("Duplicate vertex pool name " + name);
}
vertex_pools[name] = pool;
egg_stack.push_back(pool);
}
'{' vertex_pool_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* vertex_pool_body
*
* enter: TOS is EggVertexPool.
* exit: vertex pool contents have been filled.
*
*/
vertex_pool_body:
empty
| vertex_pool_body vertex
;
/*
* vertex
*
* enter: TOS is EggVertexPool.
* exit: new vertex has been added to vertex pool.
*
*/
vertex:
VERTEX
{
egg_stack.push_back(new EggVertex);
}
'{' vertex_body '}'
{
PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back());
egg_stack.pop_back();
DCAST(EggVertexPool, egg_stack.back())->add_vertex(vtx);
}
| VERTEX integer
{
vertex_index = (int)$2;
EggVertexPool *pool = DCAST(EggVertexPool, egg_stack.back());
if (vertex_index < 0) {
ostringstream errmsg;
errmsg << "Ignoring invalid vertex index " << vertex_index
<< " in vertex pool " << pool->get_name() << ends;
eggyywarning(errmsg);
vertex_index = -1;
} else if (pool->get_vertex(vertex_index) != NULL) {
ostringstream errmsg;
errmsg << "Ignoring duplicate vertex index " << vertex_index
<< " in vertex pool " << pool->get_name() << ends;
eggyywarning(errmsg);
vertex_index = -1;
}
// Even if we didn't like the vertex index number, we still need to
// go ahead and parse the vertex. We just won't save it.
egg_stack.push_back(new EggVertex);
}
'{' vertex_body '}'
{
PT(EggVertex) vtx = DCAST(EggVertex, egg_stack.back());
egg_stack.pop_back();
EggVertexPool *pool = DCAST(EggVertexPool, egg_stack.back());
if (vertex_index != -1) {
pool->add_vertex(vtx, vertex_index);
}
}
;
/*
* vertex_body
*
* enter: TOS is EggVertex.
* exit: vertex contents have been filled.
*
*/
vertex_body:
real
{
DCAST(EggVertex, egg_stack.back())->set_pos($1);
}
| real real
{
DCAST(EggVertex, egg_stack.back())->set_pos(LPoint2d($1, $2));
}
| real real real
{
DCAST(EggVertex, egg_stack.back())->set_pos(LPoint3d($1, $2, $3));
}
| real real real real
{
DCAST(EggVertex, egg_stack.back())->set_pos(LPoint4d($1, $2, $3, $4));
}
| vertex_body UV '{' vertex_uv_body '}'
| vertex_body NORMAL '{' vertex_normal_body '}'
| vertex_body RGBA '{' vertex_color_body '}'
| vertex_body DXYZ string '{' real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs.
insert(EggMorphVertex($3, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_body DXYZ '{' string real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_dxyzs.
insert(EggMorphVertex($4, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* vertex_uv_body
*
* enter: TOS is EggVertex.
* exit: vertex UV value has been filled.
*
*/
vertex_uv_body:
real real
{
DCAST(EggVertex, egg_stack.back())->set_uv(TexCoordd($1, $2));
}
| vertex_uv_body DUV string '{' real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($3, LVector2d($5, $6))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_uv_body DUV '{' string real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($4, LVector2d($5, $6))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* vertex_normal_body
*
* enter: TOS is EggVertex.
* exit: vertex normal value has been filled.
*
*/
vertex_normal_body:
real real real
{
DCAST(EggVertex, egg_stack.back())->set_normal(Normald($1, $2, $3));
}
| vertex_normal_body DNORMAL string '{' real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals.
insert(EggMorphNormal($3, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_normal_body DNORMAL '{' string real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_dnormals.
insert(EggMorphNormal($4, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* vertex_color_body
*
* enter: TOS is EggVertex.
* exit: vertex color value has been filled.
*
*/
vertex_color_body:
real real real real
{
DCAST(EggVertex, egg_stack.back())->set_color(Colorf($1, $2, $3, $4));
}
| vertex_color_body DRGBA string '{' real real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas.
insert(EggMorphColor($3, LVector4f($5, $6, $7, $8))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_color_body DRGBA '{' string real real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas.
insert(EggMorphColor($4, LVector4f($5, $6, $7, $8))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* group
*
* enter:
* exit: returns a new EggGroup.
*
*/
group:
GROUP optional_name
{
EggGroup *group = new EggGroup($2);
egg_stack.push_back(group);
}
'{' group_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* joint
*
* enter:
* exit: returns a new EggGroup, as a joint.
*
*/
joint:
JOINT optional_name
{
EggGroup *group = new EggGroup($2);
group->set_group_type(EggGroup::GT_joint);
egg_stack.push_back(group);
}
'{' group_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* instance
*
* enter:
* exit: returns a new EggGroup, as an instance.
*
*/
instance:
INSTANCE optional_name
{
EggGroup *group = new EggGroup($2);
group->set_group_type(EggGroup::GT_instance);
egg_stack.push_back(group);
}
'{' group_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* group_body
*
* enter: TOS is EggGroup.
* exit: group contents have been filled, including children.
*
*/
group_body:
empty
| group_body SCALAR required_name '{' real_or_string '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "fps") == 0) {
group->set_switch_fps(value);
} else if (cmp_nocase_uh(name, "no_fog") == 0) {
group->set_nofog_flag(value != 0);
} else if (cmp_nocase_uh(name, "decal") == 0) {
group->set_decal_flag(value != 0);
} else if (cmp_nocase_uh(name, "direct") == 0) {
group->set_direct_flag(value != 0);
} else if (cmp_nocase_uh(name, "alpha") == 0) {
EggAlphaMode::AlphaMode a = EggAlphaMode::string_alpha_mode(strval);
if (a == EggAlphaMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
group->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
group->set_draw_order(value);
} else if (cmp_nocase_uh(name, "collide_mask") == 0) {
group->set_collide_mask(value);
} else if (cmp_nocase_uh(name, "from_collide_mask") == 0) {
group->set_from_collide_mask(value);
} else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
group->set_into_collide_mask(value);
} else {
eggyywarning("Unknown group scalar " + name);
}
}
| group_body BILLBOARD '{' string '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string strval = $4;
EggGroup::BillboardType f = EggGroup::string_billboard_type(strval);
if (f == EggGroup::BT_none) {
eggyywarning("Unknown billboard type " + strval);
} else {
group->set_billboard_type(f);
}
}
| group_body COLLIDE optional_name '{' cs_type collide_flags '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string name = $3;
group->set_collision_name(name);
}
| group_body DCS '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_dcs_flag(value!=0);
}
| group_body DART '{' integer '}'
{
// The traditional flavor of DART, with { 0 } or { 1 }.
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_dart_type(value!=0 ? EggGroup::DT_default : EggGroup::DT_none);
}
| group_body DART '{' STRING '}'
{
// The special flavor of DART, with { sync } or { nosync }.
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string strval = $4;
EggGroup::DartType f = EggGroup::string_dart_type(strval);
if (f == EggGroup::DT_none) {
eggyywarning("Unknown dart type " + strval);
} else {
group->set_dart_type(f);
}
}
| group_body SWITCH '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_switch_flag(value!=0);
}
| group_body OBJECTTYPE '{' required_string '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string type = $4;
group->set_objecttype(type);
}
| group_body MODEL '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_model_flag(value!=0);
}
| group_body TEXLIST '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_texlist_flag(value!=0);
}
| group_body transform_3d
| group_body group_vertex_ref
| group_body switchcondition
| group_body node
{
DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
;
/*
* cs_type
*
* enter: TOS is EggGroup.
* exit: group's cs_type value is set according to parsed symbol.
*
*/
cs_type:
string
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string strval = $1;
EggGroup::CollisionSolidType f = EggGroup::string_cs_type(strval);
if (f == EggGroup::CST_none) {
eggyywarning("Unknown collision solid type " + strval);
} else {
group->set_cs_type(f);
}
}
;
/*
* collide_flags
*
* enter: TOS is EggGroup.
* exit: group's collide flags have been set according to parsed flags.
*
*/
collide_flags:
empty
| collide_flags string
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string strval = $2;
EggGroup::CollideFlags f = EggGroup::string_collide_flags(strval);
if (f == EggGroup::CF_none) {
eggyywarning("Unknown collision flag " + strval);
} else {
group->set_collide_flags(group->get_collide_flags() | f);
}
}
;
/*
* transform_3d
*
* enter: TOS is EggGroup.
* exit: group's transform matrix has been set.
*
*/
transform_3d:
TRANSFORM
{
matrix_3d = LMatrix4d::ident_mat();
}
'{' transform_3d_body '}'
{
DCAST(EggGroup, egg_stack.back())->set_transform(matrix_3d);
}
;
/*
* transform_3d_body
*
* enter: matrix_3d contains some sensible value.
* exit: matrix_3d has been transformed by the parsed transformation.
*
*/
transform_3d_body:
empty
| transform_3d_body matrix3_3d
| transform_3d_body matrix4_3d
| transform_3d_body translate_3d
| transform_3d_body rotx_3d
| transform_3d_body roty_3d
| transform_3d_body rotz_3d
| transform_3d_body rotate_3d
| transform_3d_body scale_3d
;
translate_3d: TRANSLATE '{' real real real '}'
{
matrix_3d *= LMatrix4d::translate_mat($3, $4, $5);
}
;
rotx_3d: ROTX '{' real '}'
{
matrix_3d *= LMatrix4d::rotate_mat($3, LVector3d(1.0, 0.0, 0.0));
}
;
roty_3d: ROTY '{' real '}'
{
matrix_3d *= LMatrix4d::rotate_mat($3, LVector3d(0.0, 1.0, 0.0));
}
;
rotz_3d: ROTZ '{' real '}'
{
matrix_3d *= LMatrix4d::rotate_mat($3, LVector3d(0.0, 0.0, 1.0));
}
;
rotate_3d: ROTATE '{' real real real real '}'
{
matrix_3d *= LMatrix4d::rotate_mat($3, LVector3d($4, $5, $6));
}
;
scale_3d: SCALE '{' real real real '}'
{
matrix_3d *= LMatrix4d::scale_mat($3, $4, $5);
}
;
matrix4_3d:
MATRIX4 '{' matrix4_3d_body '}'
;
matrix4_3d_body:
empty
| real real real real
real real real real
real real real real
real real real real
{
matrix_3d *= LMatrix4d($1, $2, $3, $4,
$5, $6, $7, $8,
$9, $10, $11, $12,
$13, $14, $15, $16);
}
;
matrix3_3d: MATRIX3 '{' matrix3_3d_body '}'
;
matrix3_3d_body:
empty
| real real real
real real real
real real real
{
matrix_3d *= LMatrix4d(LMatrix3d($1, $2, $3,
$4, $5, $6,
$7, $8, $9));
}
;
/*
* transform_2d
*
* enter: TOS is EggTexture.
* exit: texture's transform matrix has been set.
*
*/
transform_2d:
TRANSFORM
{
matrix_2d = LMatrix3d::ident_mat();
}
'{' transform_2d_body '}'
{
DCAST(EggTexture, egg_stack.back())->set_transform(matrix_2d);
}
;
/*
* transform_2d_body
*
* enter: matrix contains some sensible value.
* exit: matrix has been transformed by the parsed transformation.
*
*/
transform_2d_body:
empty
| transform_2d_body matrix3_2d
| transform_2d_body translate_2d
| transform_2d_body rotate_2d
| transform_2d_body scale_2d
;
translate_2d: TRANSLATE '{' real real '}'
{
matrix_2d *= LMatrix3d::translate_mat($3, $4);
}
;
rotate_2d: ROTATE '{' real '}'
{
matrix_2d *= LMatrix3d::rotate_mat($3);
}
;
scale_2d: SCALE '{' real real '}'
{
matrix_2d *= LMatrix3d::scale_mat($3, $4);
}
;
matrix3_2d: MATRIX3 '{' matrix3_2d_body '}'
;
matrix3_2d_body:
empty
| real real real
real real real
real real real
{
matrix_2d *= LMatrix3d($1, $2, $3,
$4, $5, $6,
$7, $8, $9);
}
;
/*
* group_vertex_ref
*
* enter: TOS is EggGroup.
* exit: group vertex list has been filled.
*
*/
group_vertex_ref:
VERTEXREF '{' integer_list group_vertex_membership REF '{' vertex_pool_name '}' '}'
{
if ($7 != (EggVertexPool *)NULL) {
EggVertexPool *pool = DCAST(EggVertexPool, $7);
EggGroup *group = DCAST(EggGroup, egg_stack.back());
PTA_double nums = $3;
double membership = $4;
for (int i = 0; i < (int)nums.size(); i++) {
int index = (int)nums[i];
EggVertex *vertex = pool->get_vertex(index);
if (vertex == NULL) {
ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name()
<< ends;
eggyyerror(errmsg);
} else {
group->ref_vertex(vertex, membership);
}
}
}
}
;
/*
* group_vertex_membership
*
* enter:
* exit: returns membership component if specified, or 1.0.
*
*/
group_vertex_membership:
empty
{
$$ = 1.0;
}
| group_vertex_membership SCALAR required_name '{' real_or_string '}'
{
string name = $3;
double value = $<_number>5;
double result = $1;
if (cmp_nocase_uh(name, "membership") == 0) {
result = value;
} else {
eggyywarning("Unknown group vertex scalar " + name);
}
$$ = result;
}
;
/*
* switchcondition
*
* enter: TOS is EggGroup.
* exit: group switchcondition value has been filled.
*
*/
switchcondition:
SWITCHCONDITION '{' switchcondition_body '}'
;
/*
* switchcondition_body
*
* enter: TOS is EggGroup.
* exit: group switchcondition value has been filled.
*
*/
switchcondition_body:
DISTANCE '{' real real VERTEX '{' real real real '}' '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
group->set_lod(EggSwitchConditionDistance($3, $4, LPoint3d($7, $8, $9)));
}
| DISTANCE '{' real real real VERTEX '{' real real real '}' '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
group->set_lod(EggSwitchConditionDistance($3, $4, LPoint3d($8, $9, $10), $5));
}
;
/*
* polygon
*
* enter:
* exit: returns a new EggPolygon.
*
*/
polygon:
POLYGON optional_name
{
egg_stack.push_back(new EggPolygon($2));
}
'{' primitive_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* point_light
*
* enter:
* exit: returns a new EggPoint.
*
*/
point_light:
POINTLIGHT optional_name
{
egg_stack.push_back(new EggPoint($2));
}
'{' primitive_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* nurbs_surface
*
* enter:
* exit: returns a new EggNurbsSurface.
*
*/
nurbs_surface:
NURBSSURFACE optional_name
{
egg_stack.push_back(new EggNurbsSurface($2));
}
'{' nurbs_surface_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* nurbs_curve
*
* enter:
* exit: returns a new EggNurbsCurve.
*
*/
nurbs_curve:
NURBSCURVE optional_name
{
egg_stack.push_back(new EggNurbsCurve($2));
}
'{' nurbs_curve_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* primitive_body
*
* enter: TOS is EggPrimitive.
* exit: primitive attributes and vertices have been filled.
*
*/
primitive_body:
empty
| primitive_body TREF '{' primitive_tref_body '}'
| primitive_body TEXTURE '{' primitive_texture_body '}'
| primitive_body MREF '{' primitive_material_body '}'
| primitive_body primitive_vertex_ref
| primitive_body NORMAL '{' primitive_normal_body '}'
| primitive_body RGBA '{' primitive_color_body '}'
| primitive_body BFACE '{' primitive_bface_body '}'
| primitive_body SCALAR required_name '{' real_or_string '}'
{
EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "alpha") == 0) {
EggAlphaMode::AlphaMode a = EggAlphaMode::string_alpha_mode(strval);
if (a == EggAlphaMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order(value);
} else {
eggyywarning("Unknown scalar " + name);
}
}
;
/*
* nurbs_surface_body
*
* enter: TOS is EggNurbsSurface.
* exit: primitive attributes and vertices have been filled.
*
*/
nurbs_surface_body:
empty
| nurbs_surface_body TREF '{' primitive_tref_body '}'
| nurbs_surface_body TEXTURE '{' primitive_texture_body '}'
| nurbs_surface_body MREF '{' primitive_material_body '}'
| nurbs_surface_body primitive_vertex_ref
| nurbs_surface_body NORMAL '{' primitive_normal_body '}'
| nurbs_surface_body RGBA '{' primitive_color_body '}'
| nurbs_surface_body BFACE '{' primitive_bface_body '}'
| nurbs_surface_body ORDER '{' nurbs_surface_order_body '}'
| nurbs_surface_body UKNOTS '{' nurbs_surface_uknots_body '}'
| nurbs_surface_body VKNOTS '{' nurbs_surface_vknots_body '}'
| nurbs_surface_body nurbs_curve
{
EggNurbsCurve *curve = DCAST(EggNurbsCurve, $2);
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
nurbs->_curves_on_surface.push_back(curve);
}
| nurbs_surface_body TRIM '{' nurbs_surface_trim_body '}'
| nurbs_surface_body SCALAR required_name '{' real_or_string '}'
{
EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "alpha") == 0) {
EggAlphaMode::AlphaMode a = EggAlphaMode::string_alpha_mode(strval);
if (a == EggAlphaMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order(value);
} else if (cmp_nocase_uh(name, "u_subdiv") == 0) {
primitive->set_u_subdiv(value);
} else if (cmp_nocase_uh(name, "v_subdiv") == 0) {
primitive->set_v_subdiv(value);
} else {
eggyywarning("Unknown scalar " + name);
}
}
;
/*
* nurbs_curve_body
*
* enter: TOS is EggNurbsCurve.
* exit: primitive attributes and vertices have been filled.
*
*/
nurbs_curve_body:
empty
| nurbs_curve_body TREF '{' primitive_tref_body '}'
| nurbs_curve_body TEXTURE '{' primitive_texture_body '}'
| nurbs_curve_body MREF '{' primitive_material_body '}'
| nurbs_curve_body primitive_vertex_ref
| nurbs_curve_body NORMAL '{' primitive_normal_body '}'
| nurbs_curve_body RGBA '{' primitive_color_body '}'
| nurbs_curve_body BFACE '{' primitive_bface_body '}'
| nurbs_curve_body ORDER '{' nurbs_curve_order_body '}'
| nurbs_curve_body KNOTS '{' nurbs_curve_knots_body '}'
| nurbs_curve_body SCALAR required_name '{' real_or_string '}'
{
EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "alpha") == 0) {
EggAlphaMode::AlphaMode a = EggAlphaMode::string_alpha_mode(strval);
if (a == EggAlphaMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order(value);
} else if (cmp_nocase_uh(name, "subdiv") == 0) {
primitive->set_subdiv(value);
} else if (cmp_nocase_uh(name, "type") == 0) {
EggCurve::CurveType a = EggCurve::string_curve_type(strval);
if (a == EggCurve::CT_none) {
eggyywarning("Unknown curve type " + strval);
} else {
primitive->set_curve_type(a);
}
} else {
eggyywarning("Unknown scalar " + name);
}
}
;
/*
* primitive_tref_body
*
* enter: TOS is EggPrimitive.
* exit: primitive TREF value has been filled.
*
*/
primitive_tref_body:
texture_name
{
if ($1 != (EggTexture *)NULL) {
EggTexture *texture = DCAST(EggTexture, $1);
DCAST(EggPrimitive, egg_stack.back())->set_texture(texture);
}
}
;
/*
* primitive_texture_body
*
* enter: TOS is EggPrimitive.
* exit: primitive texture value has been filled.
*
*/
primitive_texture_body:
required_name
{
EggTexture *texture = NULL;
// Defining a texture on-the-fly.
Filename filename = $1;
string tref_name = filename.get_basename();
Textures::iterator vpi = textures.find(tref_name);
if (vpi == textures.end()) {
// The texture was not yet defined. Define it.
texture = new EggTexture(tref_name, filename);
textures[tref_name] = texture;
if (egg_top_node != NULL) {
egg_top_node->add_child(texture);
}
} else {
// The texture already existed. Use it.
texture = (*vpi).second;
if (filename != texture->get_filename()) {
eggyywarning(string("Using previous path: ") +
texture->get_filename().get_fullpath());
}
}
nassertr(texture != NULL, 0);
DCAST(EggPrimitive, egg_stack.back())->set_texture(texture);
}
;
/*
* primitive_material_body
*
* enter: TOS is EggPrimitive.
* exit: primitive material value has been filled.
*
*/
primitive_material_body:
material_name
{
if ($1 != (EggMaterial *)NULL) {
EggMaterial *material = DCAST(EggMaterial, $1);
DCAST(EggPrimitive, egg_stack.back())->set_material(material);
}
}
;
/*
* primitive_normal_body
*
* enter: TOS is EggPrimitive.
* exit: primitive normal value has been filled.
*
*/
primitive_normal_body:
real real real
{
DCAST(EggPrimitive, egg_stack.back())->set_normal(Normald($1, $2, $3));
}
| primitive_normal_body DNORMAL string '{' real real real '}'
{
bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
insert(EggMorphNormal($3, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| primitive_normal_body DNORMAL '{' string real real real '}'
{
bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
insert(EggMorphNormal($4, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* primitive_color_body
*
* enter: TOS is EggPrimitive.
* exit: primitive color value has been filled.
*
*/
primitive_color_body:
real real real real
{
DCAST(EggPrimitive, egg_stack.back())->set_color(Colorf($1, $2, $3, $4));
}
| primitive_color_body DRGBA string '{' real real real real '}'
{
bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
insert(EggMorphColor($3, LVector4f($5, $6, $7, $8))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| primitive_color_body DRGBA '{' string real real real real '}'
{
bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
insert(EggMorphColor($4, LVector4f($5, $6, $7, $8))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* primitive_bface_body
*
* enter: TOS is EggPrimitive.
* exit: primitive BFace value has been filled.
*
*/
primitive_bface_body:
integer
{
EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
int value = (int)$1;
primitive->set_bface_flag(value!=0);
}
;
/*
* primitive_vertex_ref
*
* enter: TOS is EggPrimitive.
* exit: primitive vertex list has been filled.
*
*/
primitive_vertex_ref:
VERTEXREF '{' integer_list REF '{' vertex_pool_name '}' '}'
{
if ($6 != (EggVertexPool *)NULL) {
EggVertexPool *pool = DCAST(EggVertexPool, $6);
EggPrimitive *prim = DCAST(EggPrimitive, egg_stack.back());
PTA_double nums = $3;
for (int i = 0; i < (int)nums.size(); i++) {
int index = (int)nums[i];
EggVertex *vertex = pool->get_vertex(index);
if (vertex == NULL) {
ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name()
<< ends;
eggyyerror(errmsg);
} else {
prim->add_vertex(vertex);
}
}
}
}
;
/*
* nurbs_surface_order_body
*
* enter: TOS is EggNurbsSurface.
* exit: U-order and V-order have been set.
*
*/
nurbs_surface_order_body:
integer integer
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
int u_order = (int)$1;
int v_order = (int)$2;
nurbs->set_u_order(u_order);
nurbs->set_v_order(v_order);
}
;
/*
* nurbs_surface_uknots_body
*
* enter: TOS is EggNurbsSurface.
* exit: U-Knots list has been set.
*
*/
nurbs_surface_uknots_body:
real_list
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
PTA_double nums = $1;
nurbs->set_num_u_knots(nums.size());
for (int i = 0; i < (int)nums.size(); i++) {
nurbs->set_u_knot(i, nums[i]);
}
}
;
/*
* nurbs_surface_vknots_body
*
* enter: TOS is EggNurbsSurface.
* exit: V-Knots list has been set.
*
*/
nurbs_surface_vknots_body:
real_list
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
PTA_double nums = $1;
nurbs->set_num_v_knots(nums.size());
for (int i = 0; i < (int)nums.size(); i++) {
nurbs->set_v_knot(i, nums[i]);
}
}
;
/*
* nurbs_surface_trim_body
*
* enter: TOS is EggNurbsSurface.
* exit: A trim curve sequence has been defined.
*
*/
nurbs_surface_trim_body:
empty
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
nurbs->_trims.push_back(EggNurbsSurface::Trim());
}
| nurbs_surface_trim_body LOOP '{' nurbs_surface_trim_loop_body '}'
;
/*
* nurbs_surface_trim_loop_body
*
* enter: TOS is EggNurbsSurface, with at least one trim curve started.
* exit: A trim curve loop has been defined.
*
*/
nurbs_surface_trim_loop_body:
empty
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
nassertr(!nurbs->_trims.empty(), 0);
nurbs->_trims.back().push_back(EggNurbsSurface::Loop());
}
| nurbs_surface_trim_loop_body nurbs_curve
{
EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
nassertr(!nurbs->_trims.empty(), 0);
nassertr(!nurbs->_trims.back().empty(), 0);
EggNurbsCurve *curve = DCAST(EggNurbsCurve, $2);
nurbs->_trims.back().back().push_back(curve);
}
;
/*
* nurbs_curve_order_body
*
* enter: TOS is EggNurbsCurve.
* exit: U-order and V-order have been set.
*
*/
nurbs_curve_order_body:
integer
{
EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
int order = (int)$1;
nurbs->set_order(order);
}
;
/*
* nurbs_curve_knots_body
*
* enter: TOS is EggNurbsCurve.
* exit: U-Knots list has been set.
*
*/
nurbs_curve_knots_body:
real_list
{
EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
PTA_double nums = $1;
nurbs->set_num_knots(nums.size());
for (int i = 0; i < (int)nums.size(); i++) {
nurbs->set_knot(i, nums[i]);
}
}
;
/*
* table
*
* enter:
* exit: returns a new EggTable, corresponding to a <Table> entry.
*
*/
table:
TABLE optional_name
{
EggTable *table = new EggTable($2);
table->set_table_type(EggTable::TT_table);
egg_stack.push_back(table);
}
'{' table_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* bundle
*
* enter:
* exit: returns a new EggTable, corresponding to a <Bundle> entry.
*
*/
bundle:
BUNDLE optional_name
{
EggTable *table = new EggTable($2);
table->set_table_type(EggTable::TT_bundle);
egg_stack.push_back(table);
}
'{' table_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* table_body
*
* enter: TOS is EggTable.
* exit: table contents have been filled, including children.
*
*/
table_body:
empty
| table_body table
{
DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
| table_body bundle
{
DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
| table_body sanim
{
DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
| table_body xfmanim
{
DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
| table_body xfm_s_anim
{
DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
;
/*
* sanim
*
* enter:
* exit: returns a new EggSAnimData.
*
*/
sanim:
SANIM optional_name
{
EggSAnimData *anim_data = new EggSAnimData($2);
egg_stack.push_back(anim_data);
}
'{' sanim_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* sanim_body
*
* enter: TOS is EggSAnimData.
* exit: sanim contents have been filled.
*
*/
sanim_body:
empty
| sanim_body SCALAR required_name '{' real_or_string '}'
{
EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back());
string name = $3;
double value = $<_number>5;
if (cmp_nocase_uh(name, "fps") == 0) {
anim_data->set_fps(value);
} else {
eggyywarning("Unsupported S$Anim scalar: " + name);
}
}
| sanim_body TABLE_V '{' real_list '}'
{
DCAST(EggSAnimData, egg_stack.back())->set_data($4);
}
;
/*
* xfmanim
*
* enter:
* exit: returns a new EggXfmAnimData.
*
*/
xfmanim:
XFMANIM optional_name
{
EggXfmAnimData *anim_data = new EggXfmAnimData($2);
egg_stack.push_back(anim_data);
}
'{' xfmanim_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* xfmanim_body
*
* enter: TOS is EggXfmAnimData.
* exit: xfmanim contents have been filled, including children.
*
*/
xfmanim_body:
empty
| xfmanim_body SCALAR required_name '{' real_or_string '}'
{
EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "fps") == 0) {
anim_data->set_fps(value);
} else if (cmp_nocase_uh(name, "order") == 0) {
anim_data->set_order(strval);
} else if (cmp_nocase_uh(name, "contents") == 0) {
anim_data->set_contents(strval);
} else {
eggyywarning("Unsupported Xfm$Anim scalar: " + name);
}
}
| xfmanim_body TABLE_V '{' real_list '}'
{
DCAST(EggXfmAnimData, egg_stack.back())->set_data($4);
}
;
/*
* xfm_s_anim
*
* enter:
* exit: returns a new EggXfmSAnim.
*
*/
xfm_s_anim:
XFMSANIM optional_name
{
EggXfmSAnim *anim_group = new EggXfmSAnim($2);
egg_stack.push_back(anim_group);
}
'{' xfm_s_anim_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* xfm_s_anim_body
*
* enter: TOS is EggXfmSAnim.
* exit: xfm_s_anim contents have been filled, including children.
*
*/
xfm_s_anim_body:
empty
| xfm_s_anim_body SCALAR required_name '{' real_or_string '}'
{
EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back());
string name = $3;
double value = $<_number>5;
string strval = $<_string>5;
if (cmp_nocase_uh(name, "fps") == 0) {
anim_group->set_fps(value);
} else if (cmp_nocase_uh(name, "order") == 0) {
anim_group->set_order(strval);
} else {
eggyywarning("Unsupported Xfm$Anim_S$ scalar: " + name);
}
}
| xfm_s_anim_body sanim
{
DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, $2));
}
;
/*
* integer_list
*
* enter:
* exit: returns a list of parsed integers.
*
*/
integer_list:
empty
{
$$ = PTA_double(0);
}
| integer_list integer
{
$$.push_back((double)$2);
}
;
/*
* real_list
*
* enter:
* exit: returns a list of parsed reals.
*
*/
real_list:
empty
{
$$ = PTA_double(0);
}
| real_list real
{
$$.push_back($2);
}
;
/*
* texture_name
*
* enter:
* exit: Returns an EggTexture pointer, or NULL.
*
*/
texture_name:
required_name
{
string name = $1;
Textures::iterator vpi = textures.find(name);
if (vpi == textures.end()) {
eggyyerror("Unknown texture " + name);
$$ = PT(EggObject)();
} else {
$$ = (*vpi).second;
}
}
;
/*
* material_name
*
* enter:
* exit: Returns an EggMaterial pointer, or NULL.
*
*/
material_name:
required_name
{
string name = $1;
Materials::iterator vpi = materials.find(name);
if (vpi == materials.end()) {
eggyyerror("Unknown material " + name);
$$ = PT(EggObject)();
} else {
$$ = (*vpi).second;
}
}
;
/*
* vertex_pool_name
*
* enter:
* exit: Returns an EggVertexPool pointer, or NULL.
*
*/
vertex_pool_name:
required_name
{
string name = $1;
VertexPools::iterator vpi = vertex_pools.find(name);
if (vpi == vertex_pools.end()) {
eggyyerror("Unknown vertex pool " + name);
$$ = PT(EggObject)();
} else {
$$ = (*vpi).second;
}
}
;
/*
* required_name
*
* enter:
* exit: Returns a nonempty string as the name of an EggObject.
*
*/
required_name:
empty
{
eggyyerror("Name required.");
$$ = "";
}
| string
;
/*
* optional_name
*
* enter:
* exit: Returns a possibly-empty string as the name of an EggObject.
*
*/
optional_name:
optional_string
;
/*
* required_string
*
* enter:
* exit: Returns a nonempty string.
*
*/
required_string:
empty
{
eggyyerror("String required.");
$$ = "";
}
| string
;
/*
* optional_string
*
* enter:
* exit: Returns a possibly-empty string.
*
*/
optional_string:
empty
{
$$ = "";
}
| string
;
/*
* string
*
* enter:
* exit: Returns a nonempty string. This is different from required_string
* in that the grammar requires it to be nonempty, so that: (a)
* error messages are more obtuse, and (b) the grammar is less
* ambiguous. Use it whenever required_string does not work.
*
*/
string:
NUMBER
{
$$ = $<_string>1;
}
| STRING
;
/*
* repeated_string
*
* enter:
* exit: Returns a possibly-empty string, which might consist of a number
* of strings or numbers in a row, concatenated together with an
* implicit newline between.
*
*/
repeated_string:
empty
{
$$ = "";
}
| repeated_string_body
{
$$ = $1;
}
;
/*
* repeated_string_body
*
* enter:
* exit: Returns a nonempty string, which might consist of a number
* of strings or numbers in a row, concatenated together with an
* implicit newline between.
*
*/
repeated_string_body:
string
{
$$ = $1;
}
| repeated_string_body string
{
$$ = $1 + "\n" + $2;
}
;
/*
* real
*
* enter:
* exit: Returns an integer or floating-pointer number.
*
*/
real:
NUMBER
;
/*
* real_or_string
*
* enter:
* exit: Returns a number as ($<_number>1) or a string (as $<_string>1).
*
*/
real_or_string:
NUMBER
{
$<_number>$ = $1;
$<_string>$ = $<_string>1;
}
| STRING
{
$<_number>$ = 0.0;
$<_string>$ = $1;
}
;
/*
* integer
*
* enter:
* exit: Returns an integer number (stored in a double value).
*
*/
integer:
NUMBER
{
int i = (int)$1;
if ((double)i != $1) {
eggyywarning("Integer expected.");
$$ = (double)i;
}
}
;
empty:
;