open_toontown_panda3d/panda/src/egg/parser.yxx

3228 lines
78 KiB
Plaintext

/**
* @file parser.yxx
* @author drose
* @date 1999-01-16
*/
%{
#include "pandabase.h"
#include "config_egg.h"
#include "parserDefs.h"
#include "lexerDefs.h"
#include "eggObject.h"
#include "eggGroup.h"
#include "eggVertex.h"
#include "eggVertexPool.h"
#include "eggVertexUV.h"
#include "eggVertexAux.h"
#include "eggPolygon.h"
#include "eggCompositePrimitive.h"
#include "eggTriangleFan.h"
#include "eggTriangleStrip.h"
#include "eggPatch.h"
#include "eggPoint.h"
#include "eggLine.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 "eggAnimPreload.h"
#include "eggTransform.h"
#include "pt_EggTexture.h"
#include "pt_EggMaterial.h"
#include "string_utils.h"
#include "filename.h"
#include "luse.h"
#include "lmatrix.h"
#include "coordinateSystem.h"
#include "pvector.h"
#include "dcast.h"
#include "thread.h"
// 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
using std::istream;
using std::ostringstream;
using std::string;
// 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 pvector< PT(EggObject) > EggStack;
static EggStack egg_stack;
// This is used just when parsing a <Transform> or <DefaultPose> entry.
static EggTransform *egg_top_transform;
// There's one "top-level" egg node, which is where we should parent
// things (e.g. implicit 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 pmap<string, PT(EggVertexPool) > VertexPools;
static VertexPools vertex_pools;
// And another one mapping texture names to textures.
typedef pmap<string, PT_EggTexture > Textures;
static Textures textures;
// And again for material names to materials.
typedef pmap<string, PT_EggMaterial > Materials;
static Materials materials;
// Group names to groups.
typedef pmap<string, PT(EggGroup) > Groups;
static Groups groups;
// 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 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();
groups.clear();
egg_stack.push_back(tos);
egg_top_node = top_node;
}
void
egg_cleanup_parser() {
// Check for undefined vertex pools.
VertexPools::const_iterator vpi;
for (vpi = vertex_pools.begin(); vpi != vertex_pools.end(); ++vpi) {
EggVertexPool *pool = (*vpi).second;
if (pool->has_forward_vertices()) {
if (!pool->has_defined_vertices()) {
eggyyerror("Undefined vertex pool " + pool->get_name());
} else {
eggyyerror("Undefined vertices in pool " + pool->get_name());
egg_cat.error(false)
<< "Undefined vertex index numbers:";
EggVertexPool::const_iterator vi;
for (vi = pool->begin(); vi != pool->end(); ++vi) {
EggVertex *vertex = (*vi);
if (vertex->is_forward_reference()) {
egg_cat.error(false)
<< " " << vertex->get_index();
}
}
egg_cat.error(false)
<< "\n";
}
}
}
// 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();
groups.clear();
}
%}
%token <_number> EGG_NUMBER
%token <_ulong> EGG_ULONG
%token <_string> EGG_STRING
%token ANIMPRELOAD
%token BEZIERCURVE BFACE BILLBOARD BILLBOARDCENTER BINORMAL BUNDLE CLOSED
%token COLLIDE COMMENT COMPONENT
%token COORDSYSTEM CV DART
%token DNORMAL DRGBA DUV DXYZ DCS DISTANCE DTREF
%token DYNAMICVERTEXPOOL EXTERNAL_FILE
%token GROUP DEFAULTPOSE
%token JOINT KNOTS INCLUDE
%token INSTANCE LINE LOOP MATERIAL MATRIX3 MATRIX4 MODEL MREF NORMAL
%token NURBSCURVE NURBSSURFACE OBJECTTYPE ORDER
%token OUTTANGENT PATCH POINTLIGHT POLYGON REF RGBA ROTATE ROTX ROTY ROTZ
%token SANIM SCALAR SCALE SEQUENCE SHADING SWITCH SWITCHCONDITION
%token TABLE TABLE_V TAG TANGENT TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE
%token TREF TRIANGLEFAN TRIANGLESTRIP
%token TRIM TXT UKNOTS UV AUX 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
%token START_TEXTURE_BODY
%token START_PRIMITIVE_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> instance
%type <_egg> joint
%type <_egg> line
%type <_egg> polygon
%type <_egg> trianglefan
%type <_egg> trianglestrip
%type <_egg> patch
%type <_egg> point_light
%type <_egg> nurbs_surface
%type <_egg> nurbs_curve
%type <_egg> table
%type <_egg> bundle
%type <_egg> anim_preload
%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 <_egg> group_name
%type <_number> real
%type <_number> integer
%type <_number> real_or_string
%%
grammar:
START_EGG egg
| START_GROUP_BODY group_body
| START_TEXTURE_BODY texture_body
| START_PRIMITIVE_BODY primitive_body
;
/*
* egg
*
* enter: TOS is EggData.
* exit: egg file has been completely read.
*
*/
egg:
empty
| egg node
{
assert(!egg_stack.empty());
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
| trianglefan
| trianglestrip
| patch
| point_light
| line
| nurbs_surface
| nurbs_curve
| table
| anim_preload
;
/*
* 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, "type") == 0) {
EggTexture::TextureType tt = EggTexture::string_texture_type(strval);
if (tt == EggTexture::TT_unspecified) {
eggyywarning("Unknown texture texture_type " + strval);
} else {
texture->set_texture_type(tt);
}
} else 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, "compression") == 0) {
EggTexture::CompressionMode w = EggTexture::string_compression_mode(strval);
if (w == EggTexture::CM_default) {
eggyywarning("Unknown texture compression mode " + strval);
} else {
texture->set_compression_mode(w);
}
} 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, "anisotropic_degree") == 0) {
texture->set_anisotropic_degree((int)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, "combine-rgb") == 0) {
EggTexture::CombineMode cm = EggTexture::string_combine_mode(strval);
if (cm == EggTexture::CM_unspecified) {
eggyywarning("Unknown combine mode " + strval);
} else {
texture->set_combine_mode(EggTexture::CC_rgb, cm);
}
} else if (cmp_nocase_uh(name, "combine-rgb-source0") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_rgb, 0, cs);
}
} else if (cmp_nocase_uh(name, "combine-rgb-operand0") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_rgb, 0, co);
}
} else if (cmp_nocase_uh(name, "combine-rgb-source1") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_rgb, 1, cs);
}
} else if (cmp_nocase_uh(name, "combine-rgb-operand1") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_rgb, 1, co);
}
} else if (cmp_nocase_uh(name, "combine-rgb-source2") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_rgb, 2, cs);
}
} else if (cmp_nocase_uh(name, "combine-rgb-operand2") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_rgb, 2, co);
}
} else if (cmp_nocase_uh(name, "combine-alpha") == 0) {
EggTexture::CombineMode cm = EggTexture::string_combine_mode(strval);
if (cm == EggTexture::CM_unspecified) {
eggyywarning("Unknown combine mode " + strval);
} else {
texture->set_combine_mode(EggTexture::CC_alpha, cm);
}
} else if (cmp_nocase_uh(name, "combine-alpha-source0") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_alpha, 0, cs);
}
} else if (cmp_nocase_uh(name, "combine-alpha-operand0") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_alpha, 0, co);
}
} else if (cmp_nocase_uh(name, "combine-alpha-source1") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_alpha, 1, cs);
}
} else if (cmp_nocase_uh(name, "combine-alpha-operand1") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_alpha, 1, co);
}
} else if (cmp_nocase_uh(name, "combine-alpha-source2") == 0) {
EggTexture::CombineSource cs = EggTexture::string_combine_source(strval);
if (cs == EggTexture::CS_unspecified) {
eggyywarning("Unknown combine source " + strval);
} else {
texture->set_combine_source(EggTexture::CC_alpha, 2, cs);
}
} else if (cmp_nocase_uh(name, "combine-alpha-operand2") == 0) {
EggTexture::CombineOperand co = EggTexture::string_combine_operand(strval);
if (co == EggTexture::CO_unspecified) {
eggyywarning("Unknown combine operand " + strval);
} else {
texture->set_combine_operand(EggTexture::CC_alpha, 2, co);
}
} else if (cmp_nocase_uh(name, "saved_result") == 0) {
texture->set_saved_result(((int)value) != 0);
} else if (cmp_nocase_uh(name, "tex_gen") == 0) {
EggTexture::TexGen tex_gen = EggTexture::string_tex_gen(strval);
if (tex_gen == EggTexture::TG_unspecified) {
eggyywarning("Unknown tex-gen " + strval);
} else {
texture->set_tex_gen(tex_gen);
}
} else if (cmp_nocase_uh(name, "quality_level") == 0) {
EggTexture::QualityLevel quality_level = EggTexture::string_quality_level(strval);
if (quality_level == EggTexture::QL_unspecified) {
eggyywarning("Unknown quality-level " + strval);
} else {
texture->set_quality_level(quality_level);
}
} else if (cmp_nocase_uh(name, "stage_name") == 0) {
texture->set_stage_name(strval);
} else if (cmp_nocase_uh(name, "priority") == 0) {
texture->set_priority((int)value);
} else if (cmp_nocase_uh(name, "multiview") == 0) {
texture->set_multiview(((int)value) != 0);
} else if (cmp_nocase_uh(name, "num_views") == 0) {
int int_value = (int)value;
if (int_value < 1) {
eggyyerror("Invalid num-views value " + strval);
} else {
texture->set_num_views(int_value);
}
} else if (cmp_nocase_uh(name, "blendr") == 0) {
LColor color = texture->get_color();
color[0] = value;
texture->set_color(color);
} else if (cmp_nocase_uh(name, "blendg") == 0) {
LColor color = texture->get_color();
color[1] = value;
texture->set_color(color);
} else if (cmp_nocase_uh(name, "blendb") == 0) {
LColor color = texture->get_color();
color[2] = value;
texture->set_color(color);
} else if (cmp_nocase_uh(name, "blenda") == 0) {
LColor color = texture->get_color();
color[3] = value;
texture->set_color(color);
} else if (cmp_nocase_uh(name, "borderr") == 0) {
LColor border_color = texture->get_border_color();
border_color[0] = value;
texture->set_border_color(border_color);
} else if (cmp_nocase_uh(name, "borderg") == 0) {
LColor border_color = texture->get_border_color();
border_color[1] = value;
texture->set_border_color(border_color);
} else if (cmp_nocase_uh(name, "borderb") == 0) {
LColor border_color = texture->get_border_color();
border_color[2] = value;
texture->set_border_color(border_color);
} else if (cmp_nocase_uh(name, "bordera") == 0) {
LColor border_color = texture->get_border_color();
border_color[3] = value;
texture->set_border_color(border_color);
} else if (cmp_nocase_uh(name, "uv_name") == 0) {
texture->set_uv_name(strval);
} else if (cmp_nocase_uh(name, "rgb_scale") == 0) {
int int_value = (int)value;
if (int_value != 1 && int_value != 2 && int_value != 4) {
eggyyerror("Invalid rgb-scale value " + strval);
} else {
texture->set_rgb_scale(int_value);
}
} else if (cmp_nocase_uh(name, "alpha_scale") == 0) {
int int_value = (int)value;
if (int_value != 1 && int_value != 2 && int_value != 4) {
eggyyerror("Invalid alpha-scale value " + strval);
} else {
texture->set_alpha_scale(int_value);
}
} else if (cmp_nocase_uh(name, "alpha") == 0) {
EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval);
if (a == EggRenderMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
texture->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "depth_write") == 0) {
EggRenderMode::DepthWriteMode m =
EggRenderMode::string_depth_write_mode(strval);
if (m == EggRenderMode::DWM_unspecified) {
eggyywarning("Unknown depth-write mode " + strval);
} else {
texture->set_depth_write_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_test") == 0) {
EggRenderMode::DepthTestMode m =
EggRenderMode::string_depth_test_mode(strval);
if (m == EggRenderMode::DTM_unspecified) {
eggyywarning("Unknown depth-test mode " + strval);
} else {
texture->set_depth_test_mode(m);
}
} else if (cmp_nocase_uh(name, "visibility") == 0) {
EggRenderMode::VisibilityMode m =
EggRenderMode::string_visibility_mode(strval);
if (m == EggRenderMode::VM_unspecified) {
eggyywarning("Unknown visibility mode " + strval);
} else {
texture->set_visibility_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_offset") == 0) {
texture->set_depth_offset((int)value);
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
texture->set_draw_order((int)value);
} else if (cmp_nocase_uh(name, "bin") == 0) {
texture->set_bin(strval);
} else if (cmp_nocase_uh(name, "alpha_file") == 0) {
texture->set_alpha_filename(strval);
} else if (cmp_nocase_uh(name, "alpha_file_channel") == 0) {
texture->set_alpha_file_channel((int)value);
} else if (cmp_nocase_uh(name, "read_mipmaps") == 0) {
texture->set_read_mipmaps(((int)value) != 0);
} else if (cmp_nocase_uh(name, "min_lod") == 0) {
texture->set_min_lod(value);
} else if (cmp_nocase_uh(name, "max_lod") == 0) {
texture->set_max_lod(value);
} else if (cmp_nocase_uh(name, "lod_bias") == 0) {
texture->set_lod_bias(value);
} else {
eggyywarning("Unsupported texture scalar: " + name);
}
}
| texture_body transform
;
/*
* 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, "baser") == 0) {
LColor base = material->get_base();
base[0] = value;
material->set_base(base);
} else if (cmp_nocase_uh(name, "baseg") == 0) {
LColor base = material->get_base();
base[1] = value;
material->set_base(base);
} else if (cmp_nocase_uh(name, "baseb") == 0) {
LColor base = material->get_base();
base[2] = value;
material->set_base(base);
} else if (cmp_nocase_uh(name, "basea") == 0) {
LColor base = material->get_base();
base[3] = value;
material->set_base(base);
} else if (cmp_nocase_uh(name, "diffr") == 0) {
LColor diff = material->get_diff();
diff[0] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "diffg") == 0) {
LColor diff = material->get_diff();
diff[1] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "diffb") == 0) {
LColor diff = material->get_diff();
diff[2] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "diffa") == 0) {
LColor diff = material->get_diff();
diff[3] = value;
material->set_diff(diff);
} else if (cmp_nocase_uh(name, "ambr") == 0) {
LColor amb = material->get_amb();
amb[0] = value;
material->set_amb(amb);
} else if (cmp_nocase_uh(name, "ambg") == 0) {
LColor amb = material->get_amb();
amb[1] = value;
material->set_amb(amb);
} else if (cmp_nocase_uh(name, "ambb") == 0) {
LColor amb = material->get_amb();
amb[2] = value;
material->set_amb(amb);
} else if (cmp_nocase_uh(name, "amba") == 0) {
LColor amb = material->get_amb();
amb[3] = value;
material->set_amb(amb);
} else if (cmp_nocase_uh(name, "emitr") == 0) {
LColor emit = material->get_emit();
emit[0] = value;
material->set_emit(emit);
} else if (cmp_nocase_uh(name, "emitg") == 0) {
LColor emit = material->get_emit();
emit[1] = value;
material->set_emit(emit);
} else if (cmp_nocase_uh(name, "emitb") == 0) {
LColor emit = material->get_emit();
emit[2] = value;
material->set_emit(emit);
} else if (cmp_nocase_uh(name, "emita") == 0) {
LColor emit = material->get_emit();
emit[3] = value;
material->set_emit(emit);
} else if (cmp_nocase_uh(name, "specr") == 0) {
LColor spec = material->get_spec();
spec[0] = value;
material->set_spec(spec);
} else if (cmp_nocase_uh(name, "specg") == 0) {
LColor spec = material->get_spec();
spec[1] = value;
material->set_spec(spec);
} else if (cmp_nocase_uh(name, "specb") == 0) {
LColor spec = material->get_spec();
spec[2] = value;
material->set_spec(spec);
} else if (cmp_nocase_uh(name, "speca") == 0) {
LColor spec = material->get_spec();
spec[3] = value;
material->set_spec(spec);
} else if (cmp_nocase_uh(name, "shininess") == 0) {
material->set_shininess(value);
} else if (cmp_nocase_uh(name, "roughness") == 0) {
material->set_roughness(value);
} else if (cmp_nocase_uh(name, "metallic") == 0) {
material->set_metallic(value);
} else if (cmp_nocase_uh(name, "ior") == 0) {
material->set_ior(value);
} else if (cmp_nocase_uh(name, "local") == 0) {
material->set_local(value != 0.0);
} 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 = nullptr;
VertexPools::const_iterator vpi = vertex_pools.find(name);
if (vpi != vertex_pools.end()) {
pool = (*vpi).second;
if (pool->has_defined_vertices()) {
eggyywarning("Duplicate vertex pool name " + name);
pool = new EggVertexPool(name);
// The egg syntax starts counting at 1 by convention.
pool->set_highest_index(0);
vertex_pools[name] = pool;
}
} else {
pool = new EggVertexPool(name);
// The egg syntax starts counting at 1 by convention.
pool->set_highest_index(0);
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() << std::ends;
eggyywarning(errmsg);
vertex_index = -1;
} else if (pool->has_vertex(vertex_index)) {
ostringstream errmsg;
errmsg << "Ignoring duplicate vertex index " << vertex_index
<< " in vertex pool " << pool->get_name() << std::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 optional_name '{'
{
EggVertex *vertex = DCAST(EggVertex, egg_stack.back());
EggVertexUV *uv = new EggVertexUV($3, LTexCoordd::zero());
egg_stack.push_back(uv);
if (vertex->has_uv($3)) {
eggyywarning("Ignoring repeated UV name " + $3);
} else {
vertex->set_uv_obj(uv);
}
}
vertex_uv_body '}'
{
egg_stack.pop_back();
}
| vertex_body AUX required_name '{'
{
EggVertex *vertex = DCAST(EggVertex, egg_stack.back());
EggVertexAux *aux = new EggVertexAux($3, LVecBase4d::zero());
egg_stack.push_back(aux);
if (vertex->has_aux($3)) {
eggyywarning("Ignoring repeated Aux name " + $3);
} else {
vertex->set_aux_obj(aux);
}
}
vertex_aux_body '}'
{
egg_stack.pop_back();
}
| 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(EggVertexUV, egg_stack.back())->set_uv(LTexCoordd($1, $2));
}
| real real real
{
DCAST(EggVertexUV, egg_stack.back())->set_uvw(LVecBase3d($1, $2, $3));
}
| vertex_uv_body TANGENT '{' real real real '}'
{
if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) {
eggyywarning("Ignoring repeated tangent");
} else {
DCAST(EggVertexUV, egg_stack.back())->set_tangent(LNormald($4, $5, $6));
}
}
| vertex_uv_body TANGENT '{' real real real real '}'
{
if (DCAST(EggVertexUV, egg_stack.back())->has_tangent()) {
eggyywarning("Ignoring repeated tangent");
} else {
DCAST(EggVertexUV, egg_stack.back())->set_tangent4(LVecBase4d($4, $5, $6, $7));
}
}
| vertex_uv_body BINORMAL '{' real real real '}'
{
if (DCAST(EggVertexUV, egg_stack.back())->has_binormal()) {
eggyywarning("Ignoring repeated binormal");
} else {
DCAST(EggVertexUV, egg_stack.back())->set_binormal(LNormald($4, $5, $6));
}
}
| vertex_uv_body DUV string '{' real real '}'
{
bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($3, LVector3d($5, $6, 0.0))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_uv_body DUV string '{' real real real '}'
{
bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($3, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $3);
}
}
| vertex_uv_body DUV '{' string real real '}'
{
bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($4, LVector3d($5, $6, 0.0))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
| vertex_uv_body DUV '{' string real real real '}'
{
bool inserted = DCAST(EggVertexUV, egg_stack.back())->_duvs.
insert(EggMorphTexCoord($4, LVector3d($5, $6, $7))).second;
if (!inserted) {
eggyywarning("Ignoring repeated morph name " + $4);
}
}
;
/*
* vertex_aux_body
*
* enter: TOS is EggVertex.
* exit: vertex Aux value has been filled.
*
*/
vertex_aux_body:
| real real real real
{
DCAST(EggVertexAux, egg_stack.back())->set_aux(LVecBase4d($1, $2, $3, $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(LNormald($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(LColor($1, $2, $3, $4));
}
| vertex_color_body DRGBA string '{' real real real real '}'
{
bool inserted = DCAST(EggVertex, egg_stack.back())->_drgbas.
insert(EggMorphColor($3, LVector4($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, LVector4($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 '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
$$ = group;
egg_stack.pop_back();
if (group->has_name()) {
groups[group->get_name()] = group;
}
Thread::consider_yield();
}
;
/*
* 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 '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
$$ = group;
egg_stack.pop_back();
if (group->has_name()) {
groups[group->get_name()] = group;
}
}
;
/*
* 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;
unsigned long ulong_value = $<_ulong>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) {
EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval);
if (a == EggRenderMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
group->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "depth_write") == 0) {
EggRenderMode::DepthWriteMode m =
EggRenderMode::string_depth_write_mode(strval);
if (m == EggRenderMode::DWM_unspecified) {
eggyywarning("Unknown depth-write mode " + strval);
} else {
group->set_depth_write_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_test") == 0) {
EggRenderMode::DepthTestMode m =
EggRenderMode::string_depth_test_mode(strval);
if (m == EggRenderMode::DTM_unspecified) {
eggyywarning("Unknown depth-test mode " + strval);
} else {
group->set_depth_test_mode(m);
}
} else if (cmp_nocase_uh(name, "visibility") == 0) {
EggRenderMode::VisibilityMode m =
EggRenderMode::string_visibility_mode(strval);
if (m == EggRenderMode::VM_unspecified) {
eggyywarning("Unknown visibility mode " + strval);
} else {
group->set_visibility_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_offset") == 0) {
group->set_depth_offset(ulong_value);
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
group->set_draw_order(ulong_value);
} else if (cmp_nocase_uh(name, "bin") == 0) {
group->set_bin(strval);
} else if (cmp_nocase_uh(name, "collide_mask") == 0) {
group->set_collide_mask(group->get_collide_mask() | ulong_value);
} else if (cmp_nocase_uh(name, "from_collide_mask") == 0) {
group->set_from_collide_mask(group->get_from_collide_mask() | ulong_value);
} else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
group->set_into_collide_mask(group->get_into_collide_mask() | ulong_value);
} else if (cmp_nocase_uh(name, "portal") == 0) {
group->set_portal_flag(value != 0);
} else if (cmp_nocase_uh(name, "occluder") == 0) {
group->set_occluder_flag(value != 0);
} else if (cmp_nocase_uh(name, "polylight") == 0) {
group->set_polylight_flag(value != 0);
} else if (cmp_nocase_uh(name, "indexed") == 0) {
group->set_indexed_flag(value != 0);
} else if (cmp_nocase_uh(name, "scroll_u") == 0) {
group->set_scroll_u(value);
} else if (cmp_nocase_uh(name, "scroll_v") == 0) {
group->set_scroll_v(value);
} else if (cmp_nocase_uh(name, "scroll_w") == 0) {
group->set_scroll_w(value);
} else if (cmp_nocase_uh(name, "scroll_r") == 0) {
group->set_scroll_r(value);
} else if (cmp_nocase_uh(name, "blend") == 0) {
EggGroup::BlendMode blend_mode =
EggGroup::string_blend_mode(strval);
if (blend_mode == EggGroup::BM_unspecified) {
eggyywarning("Unknown blend mode " + strval);
} else {
group->set_blend_mode(blend_mode);
}
} else if (cmp_nocase_uh(name, "blendop_a") == 0) {
EggGroup::BlendOperand blend_operand =
EggGroup::string_blend_operand(strval);
if (blend_operand == EggGroup::BO_unspecified) {
eggyywarning("Unknown blend operand " + strval);
} else {
group->set_blend_operand_a(blend_operand);
}
} else if (cmp_nocase_uh(name, "blendop_b") == 0) {
EggGroup::BlendOperand blend_operand =
EggGroup::string_blend_operand(strval);
if (blend_operand == EggGroup::BO_unspecified) {
eggyywarning("Unknown blend operand " + strval);
} else {
group->set_blend_operand_b(blend_operand);
}
} else if (cmp_nocase_uh(name, "blendr") == 0) {
LColor color = group->get_blend_color();
color[0] = value;
group->set_blend_color(color);
} else if (cmp_nocase_uh(name, "blendg") == 0) {
LColor color = group->get_blend_color();
color[1] = value;
group->set_blend_color(color);
} else if (cmp_nocase_uh(name, "blendb") == 0) {
LColor color = group->get_blend_color();
color[2] = value;
group->set_blend_color(color);
} else if (cmp_nocase_uh(name, "blenda") == 0) {
LColor color = group->get_blend_color();
color[3] = value;
group->set_blend_color(color);
} 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 BILLBOARDCENTER '{' real real real '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
group->set_billboard_center(LPoint3d($4, $5, $6));
}
| 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_type(value!=0 ? EggGroup::DC_default : EggGroup::DC_none);
}
| group_body DCS '{' EGG_STRING '}'
{
// The special flavor of DCS, with { sync } or { nosync }.
EggGroup *group = DCAST(EggGroup, egg_stack.back());
string strval = $4;
EggGroup::DCSType f = EggGroup::string_dcs_type(strval);
if (f == EggGroup::DC_unspecified) {
eggyywarning("Unknown DCS type " + strval);
} else {
group->set_dcs_type(f);
}
}
| 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 '{' EGG_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->add_object_type(type);
}
| group_body MODEL '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_model_flag(value!=0);
}
| group_body TAG optional_name '{' repeated_string '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
group->set_tag($3, $5);
}
| group_body TEXLIST '{' integer '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
int value = (int)$4;
group->set_texlist_flag(value!=0);
}
| group_body transform
| group_body default_pose
| group_body group_vertex_ref
| group_body switchcondition
| group_body REF '{' group_name '}'
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
if (group->get_group_type() != EggGroup::GT_instance) {
eggyyerror("<Ref> valid only within <Instance>");
} else if ($4 != nullptr) {
group->add_group_ref(DCAST(EggGroup, $4));
}
}
| 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 {
if (f == EggGroup::CST_polyset && group->get_cs_type() != EggGroup::CST_none) {
// By convention, a CST_polyset doesn't replace any existing
// contradictory type, so ignore it if this happens. This
// allows the artist to place, for instance, <ObjectType> {
// sphere } and <ObjectType> { trigger } together.
} 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
*
* enter: TOS is some kind of EggTransform.
* exit: transform matrix has been set.
*
*/
transform:
TRANSFORM
{
egg_top_transform = egg_stack.back()->as_transform();
egg_top_transform->clear_transform();
}
'{' transform_body '}'
;
/*
* default_pose
*
* enter: TOS is an EggGroup
* exit: default_pose matrix has been set.
*
*/
default_pose:
DEFAULTPOSE
{
EggGroup *group = DCAST(EggGroup, egg_stack.back());
if (group->get_group_type() != EggGroup::GT_joint) {
eggyywarning("Unexpected <DefaultPose> outside of <Joint>");
}
egg_top_transform = &group->modify_default_pose();
egg_top_transform->clear_transform();
}
'{' transform_body '}'
;
/*
* transform_body
*
* enter: egg_top_transform has been assigned.
* exit: transform has been filled in.
*
*/
transform_body:
empty
| transform_body translate2d
| transform_body translate3d
| transform_body rotate2d
| transform_body rotx
| transform_body roty
| transform_body rotz
| transform_body rotate3d
| transform_body scale2d
| transform_body scale3d
| transform_body uniform_scale
| transform_body matrix3
| transform_body matrix4
;
translate2d:
TRANSLATE '{' real real '}'
{
egg_top_transform->add_translate2d(LVector2d($3, $4));
}
;
translate3d:
TRANSLATE '{' real real real '}'
{
egg_top_transform->add_translate3d(LVector3d($3, $4, $5));
}
;
rotate2d:
ROTATE '{' real '}'
{
egg_top_transform->add_rotate2d($3);
}
;
rotx:
ROTX '{' real '}'
{
egg_top_transform->add_rotx($3);
}
;
roty:
ROTY '{' real '}'
{
egg_top_transform->add_roty($3);
}
;
rotz:
ROTZ '{' real '}'
{
egg_top_transform->add_rotz($3);
}
;
rotate3d:
ROTATE '{' real real real real '}'
{
egg_top_transform->add_rotate3d($3, LVector3d($4, $5, $6));
}
;
scale2d:
SCALE '{' real real '}'
{
egg_top_transform->add_scale2d(LVecBase2d($3, $4));
}
;
scale3d:
SCALE '{' real real real '}'
{
egg_top_transform->add_scale3d(LVecBase3d($3, $4, $5));
}
;
uniform_scale:
SCALE '{' real '}'
{
egg_top_transform->add_uniform_scale($3);
}
;
matrix3:
MATRIX3 '{' matrix3_body '}'
;
matrix3_body:
empty
| real real real
real real real
real real real
{
egg_top_transform->add_matrix3
(LMatrix3d($1, $2, $3,
$4, $5, $6,
$7, $8, $9));
}
;
matrix4:
MATRIX4 '{' matrix4_body '}'
;
matrix4_body:
empty
| real real real real
real real real real
real real real real
real real real real
{
egg_top_transform->add_matrix4
(LMatrix4d($1, $2, $3, $4,
$5, $6, $7, $8,
$9, $10, $11, $12,
$13, $14, $15, $16));
}
;
/*
* 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 != nullptr) {
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_forward_vertex(index);
if (vertex == nullptr) {
ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name()
<< std::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();
}
;
/*
* trianglefan
*
* enter:
* exit: returns a new EggTriangleFan.
*
*/
trianglefan:
TRIANGLEFAN optional_name
{
egg_stack.push_back(new EggTriangleFan($2));
}
'{' primitive_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* trianglestrip
*
* enter:
* exit: returns a new EggTriangleStrip.
*
*/
trianglestrip:
TRIANGLESTRIP optional_name
{
egg_stack.push_back(new EggTriangleStrip($2));
}
'{' primitive_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* patch
*
* enter:
* exit: returns a new EggPatch.
*
*/
patch:
PATCH optional_name
{
egg_stack.push_back(new EggPatch($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();
}
;
/*
* line
*
* enter:
* exit: returns a new EggLine.
*
*/
line:
LINE optional_name
{
egg_stack.push_back(new EggLine($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_component_body
*
* enter: TOS is EggPrimitive.
* exit: primitive attributes and vertices have been filled.
*
*/
primitive_component_body:
empty
| primitive_component_body NORMAL '{' primitive_normal_body '}'
| primitive_component_body RGBA '{' primitive_color_body '}'
;
/*
* primitive_body
*
* enter: TOS is EggPrimitive.
* exit: primitive attributes and vertices have been filled.
*
*/
primitive_body:
empty
| primitive_body COMPONENT integer '{'
{
if (!egg_stack.back()->is_of_type(EggCompositePrimitive::get_class_type())) {
eggyyerror("Not a composite primitive; components are not allowed here.");
} else {
PT(EggCompositePrimitive) comp = DCAST(EggCompositePrimitive, egg_stack.back());
if ($3 < 0 || $3 >= comp->get_num_components()) {
eggyyerror("Invalid component number");
}
}
// We temporarily add an EggPolygon to the stack, just to receive
// the component attributes.
egg_stack.push_back(new EggPolygon);
}
primitive_component_body '}'
{
PT(EggPrimitive) prim = DCAST(EggPrimitive, egg_stack.back());
egg_stack.pop_back();
PT(EggCompositePrimitive) comp = DCAST(EggCompositePrimitive, egg_stack.back());
comp->set_component((int)$3, prim);
}
| 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) {
EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval);
if (a == EggRenderMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "depth_write") == 0) {
EggRenderMode::DepthWriteMode m =
EggRenderMode::string_depth_write_mode(strval);
if (m == EggRenderMode::DWM_unspecified) {
eggyywarning("Unknown depth-write mode " + strval);
} else {
primitive->set_depth_write_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_test") == 0) {
EggRenderMode::DepthTestMode m =
EggRenderMode::string_depth_test_mode(strval);
if (m == EggRenderMode::DTM_unspecified) {
eggyywarning("Unknown depth-test mode " + strval);
} else {
primitive->set_depth_test_mode(m);
}
} else if (cmp_nocase_uh(name, "visibility") == 0) {
EggRenderMode::VisibilityMode m =
EggRenderMode::string_visibility_mode(strval);
if (m == EggRenderMode::VM_unspecified) {
eggyywarning("Unknown visibility mode " + strval);
} else {
primitive->set_visibility_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_offset") == 0) {
primitive->set_depth_offset((int)value);
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order((int)value);
} else if (cmp_nocase_uh(name, "bin") == 0) {
primitive->set_bin(strval);
} else if (cmp_nocase_uh(name, "thick") == 0) {
if (primitive->is_of_type(EggLine::get_class_type())) {
DCAST(EggLine, primitive)->set_thick(value);
} else if (primitive->is_of_type(EggPoint::get_class_type())) {
DCAST(EggPoint, primitive)->set_thick(value);
} else {
eggyywarning("scalar thick is only meaningful for points and lines.");
}
} else if (cmp_nocase_uh(name, "perspective") == 0) {
if (primitive->is_of_type(EggPoint::get_class_type())) {
DCAST(EggPoint, primitive)->set_perspective(value != 0);
} else {
eggyywarning("scalar perspective is only meaningful for points.");
}
} 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) {
EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval);
if (a == EggRenderMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "depth_write") == 0) {
EggRenderMode::DepthWriteMode m =
EggRenderMode::string_depth_write_mode(strval);
if (m == EggRenderMode::DWM_unspecified) {
eggyywarning("Unknown depth-write mode " + strval);
} else {
primitive->set_depth_write_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_test") == 0) {
EggRenderMode::DepthTestMode m =
EggRenderMode::string_depth_test_mode(strval);
if (m == EggRenderMode::DTM_unspecified) {
eggyywarning("Unknown depth-test mode " + strval);
} else {
primitive->set_depth_test_mode(m);
}
} else if (cmp_nocase_uh(name, "visibility") == 0) {
EggRenderMode::VisibilityMode m =
EggRenderMode::string_visibility_mode(strval);
if (m == EggRenderMode::VM_unspecified) {
eggyywarning("Unknown visibility mode " + strval);
} else {
primitive->set_visibility_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_offset") == 0) {
primitive->set_depth_offset((int)value);
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order((int)value);
} else if (cmp_nocase_uh(name, "bin") == 0) {
primitive->set_bin(strval);
} else if (cmp_nocase_uh(name, "u_subdiv") == 0) {
primitive->set_u_subdiv((int)value);
} else if (cmp_nocase_uh(name, "v_subdiv") == 0) {
primitive->set_v_subdiv((int)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) {
EggRenderMode::AlphaMode a = EggRenderMode::string_alpha_mode(strval);
if (a == EggRenderMode::AM_unspecified) {
eggyywarning("Unknown alpha mode " + strval);
} else {
primitive->set_alpha_mode(a);
}
} else if (cmp_nocase_uh(name, "depth_write") == 0) {
EggRenderMode::DepthWriteMode m =
EggRenderMode::string_depth_write_mode(strval);
if (m == EggRenderMode::DWM_unspecified) {
eggyywarning("Unknown depth-write mode " + strval);
} else {
primitive->set_depth_write_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_test") == 0) {
EggRenderMode::DepthTestMode m =
EggRenderMode::string_depth_test_mode(strval);
if (m == EggRenderMode::DTM_unspecified) {
eggyywarning("Unknown depth-test mode " + strval);
} else {
primitive->set_depth_test_mode(m);
}
} else if (cmp_nocase_uh(name, "visibility") == 0) {
EggRenderMode::VisibilityMode m =
EggRenderMode::string_visibility_mode(strval);
if (m == EggRenderMode::VM_unspecified) {
eggyywarning("Unknown visibility mode " + strval);
} else {
primitive->set_visibility_mode(m);
}
} else if (cmp_nocase_uh(name, "depth_offset") == 0) {
primitive->set_depth_offset((int)value);
} else if (cmp_nocase_uh(name, "draw_order") == 0) {
primitive->set_draw_order((int)value);
} else if (cmp_nocase_uh(name, "bin") == 0) {
primitive->set_bin(strval);
} else if (cmp_nocase_uh(name, "subdiv") == 0) {
primitive->set_subdiv((int)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 != nullptr) {
EggTexture *texture = DCAST(EggTexture, $1);
DCAST(EggPrimitive, egg_stack.back())->add_texture(texture);
}
}
;
/*
* primitive_texture_body
*
* enter: TOS is EggPrimitive.
* exit: primitive texture value has been filled.
*
*/
primitive_texture_body:
required_name
{
EggTexture *texture = nullptr;
// 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 != nullptr) {
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 != nullptr, 0);
DCAST(EggPrimitive, egg_stack.back())->add_texture(texture);
}
;
/*
* primitive_material_body
*
* enter: TOS is EggPrimitive.
* exit: primitive material value has been filled.
*
*/
primitive_material_body:
material_name
{
if ($1 != nullptr) {
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(LNormald($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(LColor($1, $2, $3, $4));
}
| primitive_color_body DRGBA string '{' real real real real '}'
{
bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
insert(EggMorphColor($3, LVector4($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, LVector4($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 != nullptr) {
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_forward_vertex(index);
if (vertex == nullptr) {
ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name()
<< std::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();
Thread::consider_yield();
}
;
/*
* 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));
}
;
/*
* anim_preload
*
* enter:
* exit: returns a new EggAnimPreload object.
*
*/
anim_preload:
ANIMPRELOAD optional_name
{
EggAnimPreload *anim_preload = new EggAnimPreload($2);
egg_stack.push_back(anim_preload);
}
'{' anim_preload_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* anim_preload_body
*
* enter: TOS is EggAnimPreload.
* exit: anim_preload contents have been filled.
*
*/
anim_preload_body:
empty
| anim_preload_body SCALAR required_name '{' real_or_string '}'
{
EggAnimPreload *anim_preload = DCAST(EggAnimPreload, egg_stack.back());
string name = $3;
double value = $<_number>5;
if (cmp_nocase_uh(name, "fps") == 0) {
anim_preload->set_fps(value);
} else if (cmp_nocase_uh(name, "frames") == 0) {
anim_preload->set_num_frames((int)value);
} else {
eggyywarning("Unsupported AnimPreload scalar: " + name);
}
}
;
/*
* integer_list
*
* enter:
* exit: returns a list of parsed integers.
*
*/
integer_list:
empty
{
$$ = PTA_double::empty_array(0);
}
| integer_list integer
{
$$.push_back((double)$2);
}
;
/*
* real_list
*
* enter:
* exit: returns a list of parsed reals.
*
*/
real_list:
empty
{
$$ = PTA_double::empty_array(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()) {
// This will become a forward reference.
EggVertexPool *pool = new EggVertexPool(name);
// The egg syntax starts counting at 1 by convention.
pool->set_highest_index(0);
vertex_pools[name] = pool;
$$ = pool;
} else {
$$ = (*vpi).second;
}
}
;
/*
* group_name
*
* enter:
* exit: Returns an EggGroup pointer, or NULL.
*
*/
group_name:
required_name
{
string name = $1;
Groups::iterator vpi = groups.find(name);
if (vpi == groups.end()) {
eggyyerror("Unknown group " + 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:
EGG_NUMBER
{
$$ = $<_string>1;
}
| EGG_ULONG
{
$$ = $<_string>1;
}
| EGG_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:
EGG_NUMBER
| EGG_ULONG
{
$$ = $1;
}
;
/*
* real_or_string
*
* enter:
* exit: Returns a number as ($<_number>1) or as an unsigned long
* ($<_ulong>1) or a string (as $<_string>1).
*
*/
real_or_string:
EGG_NUMBER
{
$<_number>$ = $1;
$<_ulong>$ = (unsigned long)$1;
$<_string>$ = $<_string>1;
}
| EGG_ULONG
{
$<_number>$ = $1;
$<_ulong>$ = $1;
$<_string>$ = $<_string>1;
}
| EGG_STRING
{
$<_number>$ = 0.0;
$<_ulong>$ = 0;
$<_string>$ = $1;
}
;
/*
* integer
*
* enter:
* exit: Returns an integer number (stored in a double value).
*
*/
integer:
EGG_NUMBER
{
int i = (int)$1;
if ((double)i != $1) {
eggyywarning("Integer expected.");
$$ = (double)i;
}
}
| EGG_ULONG
{
$$ = $1;
}
;
empty:
;