// parser.H: rayshade file format parser

#ifndef _RAYSHADE_PARSER_H_
#define _RAYSHADE_PARSER_H_

#include "xrmlP.H"
#include "importer.H"
#include "scanner.H"
#include "Stack.H"
#include "Group.H"
#include "vector.H"
#include "matrix.H"

using namespace xrml;

class Vec3d: public Vec3 {
  // inherits everything from Vec3, but contains in addition
  // a constructor to convert a rayshade Vector.
public:
  Vec3d(const Vector& v) { x=v.x; y=v.y; z=v.z; }
};

class rayshade_context {
public:
  MFNode* world;    // where to add new object instances
  Grouping* aggregate; // aggregate being parsed, if any

  // attributes of object being parsed
  Mat4 transform;   // instance transform
  // surface will come here too

  rayshade_context();
  ~rayshade_context();
  void reset(void);   // resets attributes to initial values
};

class rayshade_parser: public importer, public rayshade_scanner {
protected:
  stack<class rayshade_context*> ctx_stack;
  class rayshade_context* ctx;  // current context

  // Informs that an item is not (yet) converted
  void NotConverted(char* item);
  void NotImplemented(char* what);

  // primitive objects: return an SFNode* (to a Geometry)
  // while possibly accumulating translations/scalings/rotations
  // to place the object at the right center and orientation
  class SFNode* NewHeightField(char *filename);
  class SFNode* NewPoly(MFVec3f* points);
  class SFNode* NewCone(const float radbottom, 
			const Vec3d& bottom,
			const float radtop,
			const Vec3d& top);
  class SFNode* NewCylinder(const float radius,
			    const Vec3d& bottom,
			    const Vec3d& top);
  class SFNode* NewSphere(const float radius,
			  const Vec3d& center);
  class SFNode* NewDisc(const float radius,
			const Vec3d& center,
			const Vec3d& normal);
  class SFNode* NewBox(const Vec3d& corner1,
		       const Vec3d& corner2);
  class SFNode* NewFlatTriangle(const Vec3d& p1,
				const Vec3d& p2,
				const Vec3d& p3);
  class SFNode* NewSmoothTriangle(const Vec3d& p1,
				  const Vec3d& n1,
				  const Vec3d& p2,
				  const Vec3d& n2,
				  const Vec3d& p3,
				  const Vec3d& n3);
  class SFNode* NewTexturedTriangle(const Vec3d& p1,
				    const Vec3d& n1,
				    const Vec2d& uv1,
				    const Vec3d& p2,
				    const Vec3d& n2,
				    const Vec2d& uv2,
				    const Vec3d& p3,
				    const Vec3d& n3,
				    const Vec2d& uv3);
  class SFNode* NewPlane(const Vec3d& p, const Vec3d& n);
  class SFNode* NewTorus(const float rmajor,
			 const float rminor,
			 const Vec3d& center,
			 const Vec3d& up);
 class SFNode* NewBlob(void);

  // aggregate objects
  void NewList(void);
  void NewCSGUnion(void);
  void NewCSGIntersect(void);
  void NewCSGDifference(void);
  // begins/ends an aggregate
  void BeginAggregate(class Grouping* aggregate);
  class SFNode* EndAggregate(void);

  // compose a new Children node from the primitive or aggregate
  // (Geometry* or Grouping*), that can be either stored in
  // the named nodes table, or added to the current world.
  // These routines combine the object with the current 
  // transforms, surfaces and textures
  class SFNode* NewPrimitiveObject(class SFNode* primitive);
  class SFNode* NewAggregateObject(class SFNode* aggregate);
  class SFNode* NewNamedObject(class SFNode* named);

  // adds an instance to the current aggregate
  void AddInstance(class SFNode* object);

  // defines new named node/looks up named node
  void DefineNamedObject(char* name, class SFNode* object);
  class SFNode* LookupNamedObject(char* name);

public:
  void yyerror(char *s);// parser error reporting routine
  int yyparse(void);	// bison generated parser

  YYSTYPE yylval;	// bison generated "global" variables
  int yychar;
  int yynerrs;

  inline int yylex(YYSTYPE *lvalp)
  {
    int token = rayshade_scanner::yylex(lvalp);
    xrml::current_linenr = yylineno;	// keep track of line number
    return token;
  }

  // by default, yylex fills in yylval "global" variable.
  inline int yylex(void)
  {
    return yylex(&yylval);
  }

public:
  class world *world;	// the world being parsed

  // see importer.H
  bool parse(class world *world, char **strpool);
};

#endif /*_RAYSHADE_PARSER_H_*/
