diff --git a/main/Scene-load.cc b/main/Scene-load.cc index 9a4c75a..0dec38c 100644 --- a/main/Scene-load.cc +++ b/main/Scene-load.cc @@ -9,6 +9,7 @@ #include "parser/parser.h" #include "parser/nodes.h" #include "util/Polygon.h" +#include "util/Scope.h" using namespace std; @@ -16,64 +17,16 @@ typedef vector< refptr >::const_iterator Node_Iterator; void Scene::load(const char * filename) { - refptr node = parse(filename); - processNode(node); -} + refptr scope = new Scope(); + refptr node = parse(filename, scope); + if ( ! node.isNull() ) + { + /* evaluate any scripting nodes in the node tree */ + refptr processed_scene = node->evaluate(); + node->evaluateChildren(processed_scene); -void Scene::processNode(refptr node) -{ - if (node.isNull()) - return; - - if ( typeid(*node) == typeid(SceneNode) ) - { - processScene(node); - } - else if ( node->isShape() ) - { - refptr shape = processShape(node); - if ( ! shape.isNull() ) - m_shapes.push_back(shape); - } - else if ( typeid(*node) == typeid(LightNode) ) - { - refptr light = processLight(node); - if ( ! light.isNull() ) - m_lights.push_back(light); - } - else if ( typeid(*node) == typeid(OptionsNode) ) - { - processOptions(node); - } - else if (node->isTransformBlock()) - { - vector< refptr > shapes = processTransformBlock(node); - for (int i = 0, sz = shapes.size(); i < sz; i++) - { - m_shapes.push_back(shapes[i]); - } - } - else if ( typeid(*node) == typeid(MaterialDefinitionNode) ) - { - processMaterialDefinition(node); - } - else if ( typeid(*node) == typeid(ShapeDefinitionNode) ) - { - processShapeDefinition(node); - } - else - { - cerr << __FILE__ << ": " << __LINE__ - << ": error: unrecognized node!" << endl; - } -} - -void Scene::processChildren(refptr node) -{ - std::vector< refptr > & children = node->getChildren(); - for (int i = 0, sz = children.size(); i < sz; i++) - { - processNode(children[i]); + /* now we have a new node tree under 'dummy' with no scripting nodes */ + processScene(processed_scene); } } @@ -98,18 +51,34 @@ void Scene::processScene(refptr node) } } + /* then any other scene-specific items */ for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { - if ( typeid(**it) != typeid(CameraNode) ) + if ( typeid(**it) == typeid(LightNode) ) { - processNode(*it); + refptr light = processLight(*it); + if ( ! light.isNull() ) + m_lights.push_back(light); } + else if ( typeid(**it) == typeid(OptionsNode) ) + { + processOptions(*it); + } + } + + /* then any general items */ + vector shapes = processGeneralItems(node); + for (vector::iterator it = shapes.begin(); + it != shapes.end(); + it++) + { + m_shapes.push_back(*it); } } -refptr Scene::processShape(refptr node) +ShapeRef Scene::processShape(refptr node) { if ( typeid(*node) == typeid(BoxNode) ) { @@ -147,7 +116,7 @@ refptr Scene::processShape(refptr node) exit(3); } - return refptr(NULL); + return ShapeRef(NULL); } void Scene::processCamera(refptr node) @@ -220,7 +189,7 @@ void Scene::processOptions(refptr node) } } -vector< refptr > Scene::processTransformBlock(refptr node) +vector Scene::processTransformBlock(refptr node) { if ( typeid(*node) == typeid(TranslateBlockNode) ) { @@ -238,8 +207,22 @@ vector< refptr > Scene::processTransformBlock(refptr node) m_transforms.push(m_transforms.top()); m_transforms.top().scale(node->getVector()); } + else + { + cerr << "Unknown transformation block node type!" << endl; + exit(4); + } - vector< refptr > shapes; + vector shapes = processGeneralItems(node); + + m_transforms.pop(); + + return shapes; +} + +vector Scene::processGeneralItems(refptr node) +{ + vector shapes, incoming; for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); @@ -247,30 +230,27 @@ vector< refptr > Scene::processTransformBlock(refptr node) { if ((*it)->isTransformBlock()) { - vector< refptr > in = processTransformBlock(*it); - for (int i = 0, sz = in.size(); i < sz; i++) - { - shapes.push_back(in[i]); - } + incoming = processTransformBlock(*it); } - else if ( (*it)->isShape() ) + else if ( typeid(**it) == typeid(MaterialDefinitionNode) ) { - shapes.push_back(processShape(*it)); + processMaterialDefinition(*it); } else if ( typeid(**it) == typeid(ShapeDefinitionNode) ) { processShapeDefinition(*it); } - else + else if ( (*it)->isShape() ) { - cerr << "Unknown transform block item: " << typeid(**it).name() - << endl; - exit(3); + shapes.push_back(processShape(*it)); + } + while (incoming.size() > 0) + { + shapes.push_back(incoming[0]); + incoming.erase(incoming.begin()); } } - m_transforms.pop(); - return shapes; } @@ -346,7 +326,7 @@ refptr Scene::processMaterial(refptr node) return material; } -refptr Scene::processBox(refptr node) +ShapeRef Scene::processBox(refptr node) { refptr size = new Vector(1, 1, 1); refptr material; @@ -367,7 +347,7 @@ refptr Scene::processBox(refptr node) } } - refptr box = new Box(size); + ShapeRef box = new Box(size); if ( ! material.isNull() ) box->setMaterial(material); box->setTransform(m_transforms.top()); @@ -378,7 +358,7 @@ refptr Scene::processBox(refptr node) return box; } -refptr Scene::processCyl(refptr node) +ShapeRef Scene::processCyl(refptr node) { double radius1 = 1.0; double radius2 = 1.0; @@ -404,7 +384,7 @@ refptr Scene::processCyl(refptr node) } } - refptr cyl = new Cyl(radius1, radius2, height); + ShapeRef cyl = new Cyl(radius1, radius2, height); if ( ! material.isNull() ) cyl->setMaterial(material); cyl->setTransform(m_transforms.top()); @@ -457,7 +437,7 @@ refptr Scene::processLight(refptr node) return light; } -refptr Scene::processPlane(refptr node) +ShapeRef Scene::processPlane(refptr node) { Vector normal(0, 0, 1); double dist = 0; @@ -480,7 +460,7 @@ refptr Scene::processPlane(refptr node) } } - refptr plane = new Plane(normal[0], + ShapeRef plane = new Plane(normal[0], normal[1], normal[2], dist); @@ -494,7 +474,7 @@ refptr Scene::processPlane(refptr node) return plane; } -refptr Scene::processSphere(refptr node) +ShapeRef Scene::processSphere(refptr node) { double radius = 1.0; refptr material; @@ -515,7 +495,7 @@ refptr Scene::processSphere(refptr node) } } - refptr sphere = new Sphere(radius); + ShapeRef sphere = new Sphere(radius); if ( ! material.isNull() ) sphere->setMaterial(material); sphere->setTransform(m_transforms.top()); @@ -526,9 +506,9 @@ refptr Scene::processSphere(refptr node) return sphere; } -refptr Scene::processBool(refptr node) +ShapeRef Scene::processBool(refptr node) { - vector< refptr > shapes; + vector shapes; refptr material; bool restore_transform = processTransforms(node); @@ -540,7 +520,7 @@ refptr Scene::processBool(refptr node) { if ( (*it)->isShape() ) { - refptr shape = processShape(*it); + ShapeRef shape = processShape(*it); if ( ! shape.isNull() ) shapes.push_back(shape); } @@ -550,7 +530,7 @@ refptr Scene::processBool(refptr node) } else if ( (*it)->isTransformBlock() ) { - vector< refptr > in = processTransformBlock(*it); + vector in = processTransformBlock(*it); for (int i = 0, sz = in.size(); i < sz; i++) { shapes.push_back(in[i]); @@ -569,7 +549,7 @@ refptr Scene::processBool(refptr node) exit(3); } - refptr shape; + ShapeRef shape; if ( typeid(*node) == typeid(IntersectNode) ) shape = new Intersect(shapes); else if ( typeid(*node) == typeid(UnionNode) ) @@ -594,7 +574,7 @@ refptr Scene::processBool(refptr node) return shape; } -refptr Scene::processExtrude(refptr node) +ShapeRef Scene::processExtrude(refptr node) { refptr material; Extrude * extrude = new Extrude(); @@ -706,7 +686,7 @@ refptr Scene::processNGon(refptr node) return p; } -refptr Scene::processShapeRef(refptr node) +ShapeRef Scene::processShapeRef(refptr node) { if (m_shape_definitions.find(node->getString()) == m_shape_definitions.end()) @@ -717,7 +697,7 @@ refptr Scene::processShapeRef(refptr node) } refptr material; - refptr shape = m_shape_definitions[node->getString()]->clone(); + ShapeRef shape = m_shape_definitions[node->getString()]->clone(); bool restore_transform = processTransforms(node); diff --git a/main/Scene.h b/main/Scene.h index ed3ff37..eb789d2 100644 --- a/main/Scene.h +++ b/main/Scene.h @@ -58,25 +58,25 @@ class Scene /* In Scene-load.cc */ void load(const char * filename); - void processNode(refptr node); - void processChildren(refptr node); void processScene(refptr node); refptr processMaterial(refptr node); - refptr processBox(refptr node); - refptr processCyl(refptr node); + ShapeRef processBox(refptr node); + ShapeRef processCyl(refptr node); refptr processLight(refptr node); - refptr processPlane(refptr node); - refptr processSphere(refptr node); - refptr processShape(refptr node); - refptr processBool(refptr node); - refptr processExtrude(refptr node); - refptr processShapeRef(refptr node); + ShapeRef processPlane(refptr node); + ShapeRef processSphere(refptr node); + ShapeRef processShape(refptr node); + ShapeRef processBool(refptr node); + ShapeRef processExtrude(refptr node); + ShapeRef processShapeRef(refptr node); refptr processPolygon(refptr node); refptr processNGon(refptr node); bool processTransforms(refptr node); void processCamera(refptr node); void processOptions(refptr node); - std::vector< refptr > processTransformBlock(refptr node); + std::vector processTransformBlock(refptr node); + std::vector processGeneralItems(refptr node); + std::vector processForNode(refptr node); void processMaterialDefinition(refptr node); void processShapeDefinition(refptr node); @@ -91,8 +91,8 @@ class Scene int m_ambient_occlusion_level; /* private data */ - std::vector< refptr > m_shapes; - std::map< std::string, refptr > m_shape_definitions; + std::vector m_shapes; + std::map m_shape_definitions; std::vector< refptr > m_lights; std::stack m_transforms; double m_view_plane_dist; diff --git a/parser/nodes.cc b/parser/nodes.cc index f98008a..ba934b9 100644 --- a/parser/nodes.cc +++ b/parser/nodes.cc @@ -1,14 +1,49 @@ +#include + +#include +#include +#include + #include "nodes.h" -#include + using namespace std; -void Node::addChildren(refptr other) +void Node::evaluateChildren(refptr parent) +{ + /* recursively evaluate all children nodes */ + for (std::vector< refptr >::iterator it = m_children.begin(); + it != m_children.end(); + it++) + { + refptr evaluated = (*it)->evaluate(); + if ( ! evaluated.isNull() ) + { + if (typeid(*evaluated) == typeid(EvaluatePropagateNode)) + { + for (vector::iterator it2 + = evaluated->getChildren().begin(); + it2 != evaluated->getChildren().end(); + it2++) + { + parent->addChild(*it2); + } + } + else + { + (*it)->evaluateChildren(evaluated); + parent->addChild(evaluated); + } + } + } +} + +void Node::addChildren(NodeRef other) { if (other.isNull()) return; - for (vector< refptr >::const_iterator it = other->m_children.begin(); + for (vector::const_iterator it = other->m_children.begin(); it != other->m_children.end(); it++) { @@ -19,3 +54,110 @@ void Node::addChildren(refptr other) Node::~Node() { } + +NodeRef BinOpNode::evaluate() +{ + double o = one->evaluate()->getNumber(); + double t = two->evaluate()->getNumber(); + double r = 0.0; + switch (m_op) + { + case '*': + r = o * t; + break; + case '/': + r = o / t; + break; + case '+': + r = o + t; + break; + case '-': + r = o - t; + break; + default: + cerr << "Error: BinOpNode created with op '" << m_op << "'" << endl; + exit(-3); + } + return new NumberNode(r); +} + +NodeRef BoolExpressionNode::evaluate() +{ + double o, t; + double r = 0; + if (m_op != '!') + { + o = one->evaluate()->getNumber(); + t = two->evaluate()->getNumber(); + } + switch (m_op) + { + case '<': + r = o < t ? 0 : 1; + break; + case '>': + r = o > t ? 0 : 1; + break; + case '=': + r = o == t ? 0 : 1; + break; + case 'n': + r = o != t ? 0 : 1; + break; + case '!': + r = ! one->evaluate()->getInteger(); + break; + case 'T': + r = 1; + break; + } + return new NumberNode(r); +} + +NodeRef ForNode::evaluate() +{ + NodeRef eval = new EvaluatePropagateNode(); + + if (!m_nodes[0].isNull()) + { + m_nodes[0]->evaluate(); + } + + while (m_nodes[1]->evaluate()->getInteger() != 0) + { + for (vector::iterator it = m_children.begin(); + it != m_children.end(); + it++) + { + NodeRef n = (*it)->evaluate(); + if ( ! n.isNull() ) + { + if (typeid(*n) == typeid(EvaluatePropagateNode)) + { + for (vector::iterator it2 = n->getChildren().begin(); + it2 != n->getChildren().end(); + it2++) + { + eval->addChild(*it2); + } + } + else + { + eval->addChild(n); + } + } + } + + if (!m_nodes[2].isNull()) + { + m_nodes[2]->evaluate(); + } + } + + /* clear out all child nodes so that evaluateChildren() doesn't + * attempt to evaluate them */ + m_children.clear(); + + return eval; +} + diff --git a/parser/nodes.h b/parser/nodes.h index 275b871..2171053 100644 --- a/parser/nodes.h +++ b/parser/nodes.h @@ -2,10 +2,17 @@ #ifndef NODES_H #define NODES_H NODES_H -#include "util/refptr.h" -#include "util/Vector.h" +#include /* exit() */ + #include #include +#include + +#include "util/refptr.h" +#include "util/Vector.h" +#include "util/Scope.h" + +extern refptr parser_scope; class Node { @@ -15,119 +22,211 @@ class Node void addChildren(refptr other); std::vector< refptr > & getChildren() { return m_children; } - virtual int getInteger() { return 0; } - virtual double getNumber() { return 0.0; } + virtual int getInteger() { return getNumber(); } + + virtual double getNumber() + { + std::cerr << "Warning: Node::getNumber() called!" << std::endl; + return 0.0; + } virtual refptr getVector() { + std::cerr << "Warning: Node::getVector() called!" << std::endl; return refptr(NULL); } + virtual std::string getString() + { + std::cerr << "Warning: Node::getString() called!" << std::endl; + return ""; + } + virtual refptr evaluate() + { + std::cerr << "Warning: Node::evaluate() called!" << std::endl; + return NULL; + } + virtual void evaluateChildren(refptr parent); + virtual bool isShape() { return false; } virtual bool isMaterial() { return false; } virtual bool isTransformBlock() { return false; } - virtual std::string getString() { return ""; } + virtual bool isExpression() { return false; } protected: std::vector< refptr > m_children; }; +typedef refptr NodeRef; -class IntegerNode : public Node -{ - public: - IntegerNode(int number) { m_number = number; } - int getInteger() { return m_number; } - double getNumber() { return m_number; } - - protected: - int m_number; -}; class NumberNode : public Node { public: - NumberNode(double number) { m_number = number; } - double getNumber() { return m_number; } + NumberNode(double number) + : m_number(number), m_direct(true) + { + } + NumberNode(NodeRef expr) + : m_direct(false) + { + m_expr = expr; + } + virtual double getNumber() + { + return m_direct ? m_number : m_expr->getNumber(); + } + virtual refptr evaluate() + { + return m_direct + ? new NumberNode(m_number) + : new NumberNode(m_expr->evaluate()); + } protected: double m_number; + bool m_direct; + NodeRef m_expr; }; class VectorNode : public Node { public: - VectorNode(refptr vector) { m_vector = vector; } - refptr getVector() { return m_vector; } - + VectorNode(NodeRef a, NodeRef b, NodeRef c) + : m_a(a), m_b(b), m_c(c), m_direct(true) + { + } + VectorNode(NodeRef node) + : m_vector(node), m_direct(false) + { + } + refptr getVector() + { + return m_direct + ? new Vector(m_a->getNumber(), + m_b->getNumber(), + m_c->getNumber()) + : m_vector->getVector(); + } + virtual NodeRef evaluate() + { + return m_direct + ? new VectorNode(m_a->evaluate(), + m_b->evaluate(), + m_c->evaluate()) + : m_vector->evaluate(); + } protected: - refptr m_vector; + NodeRef m_a, m_b, m_c, m_vector; + bool m_direct; }; class AmbientNode : public VectorNode { public: - AmbientNode(refptr vector) : VectorNode(vector) {} + AmbientNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new AmbientNode(m_vector->evaluate()); + } }; -class AmbientOcclusionNode : public IntegerNode +class AmbientOcclusionNode : public NumberNode { public: - AmbientOcclusionNode(int i) : IntegerNode(i) {} + AmbientOcclusionNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new AmbientOcclusionNode(m_expr->evaluate()); + } }; class BoxNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() + { + return new BoxNode(); + } }; class CameraNode : public Node { + public: + virtual NodeRef evaluate() + { + return new CameraNode(); + } }; class ColorNode : public VectorNode { public: - ColorNode(refptr vector) : VectorNode(vector) {} + ColorNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new ColorNode(m_vector->evaluate()); + } }; class CylNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() + { + return new CylNode(); + } }; class DiffuseNode : public VectorNode { public: - DiffuseNode(refptr vector) : VectorNode(vector) {} + DiffuseNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new DiffuseNode(m_vector->evaluate()); + } }; class ExposureNode : public NumberNode { public: - ExposureNode(double d) : NumberNode(d) {} + ExposureNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new ExposureNode(m_expr->evaluate()); + } }; class ExtrudeNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() + { + return new ExtrudeNode(); + } }; -class HeightNode : public IntegerNode +class HeightNode : public NumberNode { public: - HeightNode(int i) : IntegerNode(i) {} + HeightNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new HeightNode(m_expr->evaluate()); + } }; class IdentifierNode : public Node { public: IdentifierNode(const std::string & str) { m_string = str; } - std::string getString() + std::string getString() { return m_string; } + virtual NodeRef evaluate() { - return m_string; + return new IdentifierNode(m_string); } protected: std::string m_string; @@ -137,38 +236,62 @@ class IntersectNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() + { + return new IntersectNode(); + } }; class ItemsNode : public Node { + public: + virtual NodeRef evaluate() + { + return new ItemsNode(); + } }; -class JitterNode : public IntegerNode +class JitterNode : public NumberNode { public: - JitterNode(int i) : IntegerNode(i) {} + JitterNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new JitterNode(m_expr->evaluate()); + } }; class LightNode : public Node { + public: + virtual NodeRef evaluate() { return new LightNode(); } }; class LookAtNode : public VectorNode { public: - LookAtNode(refptr vector) : VectorNode(vector) {} + LookAtNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new LookAtNode(m_vector->evaluate()); + } }; class MaterialNode : public Node { public: bool isMaterial() { return true; } + virtual NodeRef evaluate() { return new MaterialNode(); } }; class MaterialDefinitionNode : public IdentifierNode { public: MaterialDefinitionNode(const std::string & str) : IdentifierNode(str) {} + virtual NodeRef evaluate() + { + return new MaterialDefinitionNode(m_string); + } }; class MaterialRefNode : public IdentifierNode @@ -176,123 +299,195 @@ class MaterialRefNode : public IdentifierNode public: MaterialRefNode(const std::string & str) : IdentifierNode(str) {} bool isMaterial() { return true; } + virtual NodeRef evaluate() { return new MaterialRefNode(m_string); } }; -class MaxDepthNode : public IntegerNode +class MaxDepthNode : public NumberNode { public: - MaxDepthNode(int i) : IntegerNode(i) {} + MaxDepthNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new MaxDepthNode(m_expr->evaluate()); + } }; -class MultisampleNode : public IntegerNode +class MultisampleNode : public NumberNode { public: - MultisampleNode(int i) : IntegerNode(i) {} + MultisampleNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new MultisampleNode(m_expr->evaluate()); + } }; -class NGonNode : public IntegerNode +class NGonNode : public NumberNode { public: - NGonNode(int i) : IntegerNode(i) {} + NGonNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new NGonNode(m_expr->evaluate()); + } }; class OffsetNode : public NumberNode { public: - OffsetNode(double d) : NumberNode(d) {} + OffsetNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new OffsetNode(m_expr->evaluate()); + } }; class OptionsNode : public Node { + public: + virtual NodeRef evaluate() { return new OptionsNode(); } }; class PlaneNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() { return new PlaneNode(); } }; -class PlanePositionNode : public Node +class PlanePositionNode : public VectorNode { public: - PlanePositionNode(refptr vec, double dist) + PlanePositionNode(NodeRef vec_node, NodeRef dist) + : VectorNode(vec_node) { - m_vector = vec; m_dist = dist; } - refptr getVector() { return m_vector; } - double getNumber() { return m_dist; } + double getNumber() { return m_dist->getNumber(); } + virtual NodeRef evaluate() + { + return new PlanePositionNode(m_vector->evaluate(), + m_dist->evaluate()); + } protected: - refptr m_vector; - double m_dist; + NodeRef m_dist; }; class PolygonNode : public Node { + public: + virtual NodeRef evaluate() { return new PolygonNode(); } }; class PositionNode : public VectorNode { public: - PositionNode(refptr vector) : VectorNode(vector) {} + PositionNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new PositionNode(m_vector->evaluate()); + } }; class RadiusNode : public NumberNode { public: - RadiusNode(double d) : NumberNode(d) {} + RadiusNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new RadiusNode(m_expr->evaluate()); + } }; class ReflectanceNode : public NumberNode { public: - ReflectanceNode(double d) : NumberNode(d) {} + ReflectanceNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new ReflectanceNode(m_expr->evaluate()); + } }; class RotateNode : public VectorNode { public: - RotateNode(double angle, refptr vector) - : VectorNode(vector) + RotateNode(NodeRef angle, NodeRef vec_node) + : VectorNode(vec_node) { m_angle = angle; } - double getNumber() { return m_angle; } + double getNumber() { return m_angle->getNumber(); } + virtual NodeRef evaluate() + { + return new RotateNode(m_angle->evaluate(), m_vector->evaluate()); + } protected: - double m_angle; + NodeRef m_angle; }; class RotateBlockNode : public RotateNode { public: - RotateBlockNode(double angle, refptr vector) - : RotateNode(angle, vector) {} + RotateBlockNode(NodeRef angle, NodeRef vec_node) + : RotateNode(angle, vec_node) {} bool isTransformBlock() { return true; } + virtual NodeRef evaluate() + { + return new RotateBlockNode(m_angle->evaluate(), m_vector->evaluate()); + } }; class ScaleNode : public VectorNode { public: - ScaleNode(refptr vector) : VectorNode(vector) {} + ScaleNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new ScaleNode(m_vector->evaluate()); + } }; class ScaleBlockNode : public ScaleNode { public: - ScaleBlockNode(refptr vector) : ScaleNode(vector) {} + ScaleBlockNode(NodeRef vector) : ScaleNode(vector) {} bool isTransformBlock() { return true; } + virtual NodeRef evaluate() + { + return new ScaleBlockNode(m_vector->evaluate()); + } +}; + +class ScaleScalarNode : public Node +{ + public: + ScaleScalarNode(NodeRef expr) + : m_expr(expr) + { + } + virtual NodeRef evaluate() + { + NodeRef n = m_expr->evaluate(); + return new VectorNode(n, n, n); + } + protected: + NodeRef m_expr; }; class SceneNode : public Node { + public: + virtual NodeRef evaluate() { return new SceneNode(); } }; class ShapeDefinitionNode : public IdentifierNode { public: ShapeDefinitionNode(const std::string & str) : IdentifierNode(str) {} + virtual NodeRef evaluate() { return new ShapeDefinitionNode(m_string); } }; class ShapeRefNode : public IdentifierNode @@ -300,79 +495,247 @@ class ShapeRefNode : public IdentifierNode public: ShapeRefNode(const std::string & str) : IdentifierNode(str) {} bool isShape() { return true; } + virtual NodeRef evaluate() { return new ShapeRefNode(m_string); } }; class ShininessNode : public NumberNode { public: - ShininessNode(double d) : NumberNode(d) {} + ShininessNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new ShininessNode(m_expr->evaluate()); + } }; class SizeNode : public VectorNode { public: - SizeNode(refptr vector) : VectorNode(vector) {} + SizeNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new SizeNode(m_vector->evaluate()); + } }; class SpecularNode : public VectorNode { public: - SpecularNode(refptr vector) : VectorNode(vector) {} + SpecularNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new SpecularNode(m_vector->evaluate()); + } }; class SphereNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() { return new SphereNode(); } }; class SubtractNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() { return new SubtractNode(); } }; class TranslateNode : public VectorNode { public: - TranslateNode(refptr vector) : VectorNode(vector) {} + TranslateNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new TranslateNode(m_vector->evaluate()); + } }; class TranslateBlockNode : public TranslateNode { public: - TranslateBlockNode(refptr vector) : TranslateNode(vector) {} + TranslateBlockNode(NodeRef vector) : TranslateNode(vector) {} bool isTransformBlock() { return true; } + virtual NodeRef evaluate() + { + return new TranslateBlockNode(m_vector->evaluate()); + } }; class TransparencyNode : public NumberNode { public: - TransparencyNode(double d) : NumberNode(d) {} + TransparencyNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new TransparencyNode(m_expr->evaluate()); + } }; class UnionNode : public Node { public: bool isShape() { return true; } + virtual NodeRef evaluate() { return new UnionNode(); } }; class UpNode : public VectorNode { public: - UpNode(refptr vector) : VectorNode(vector) {} + UpNode(NodeRef vector) : VectorNode(vector) {} + virtual NodeRef evaluate() + { + return new UpNode(m_vector->evaluate()); + } }; class VFOVNode : public NumberNode { public: - VFOVNode(double d) : NumberNode(d) {} + VFOVNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new VFOVNode(m_expr->evaluate()); + } }; -class WidthNode : public IntegerNode +class WidthNode : public NumberNode { public: - WidthNode(int i) : IntegerNode(i) {} + WidthNode(NodeRef e) : NumberNode(e) {} + virtual NodeRef evaluate() + { + return new WidthNode(m_expr->evaluate()); + } +}; + +/******** scripting nodes ********/ + +class ExpressionNode : public Node +{ + public: + bool isExpression() { return true; } + virtual NodeRef evaluate() = 0; +}; + +class AssignmentNode : public ExpressionNode +{ + public: + AssignmentNode(NodeRef varref, NodeRef expr) + : m_varref(varref), m_expr(expr) + { + } + std::string getString() { return m_varref->getString(); } + virtual NodeRef evaluate() + { + double n = m_expr->evaluate()->getNumber(); + parser_scope->putGlobal(getString(), n); + return new NumberNode(n); + } + protected: + NodeRef m_varref; + NodeRef m_expr; +}; + +class LocalAssignmentNode : public ExpressionNode +{ + public: + LocalAssignmentNode(NodeRef varref, NodeRef expr) + : m_varref(varref), m_expr(expr) + { + } + std::string getString() { return m_varref->getString(); } + virtual NodeRef evaluate() + { + double n = m_expr->evaluate()->getNumber(); + parser_scope->putLocal(getString(), n); + return new NumberNode(n); + } + protected: + NodeRef m_varref; + NodeRef m_expr; +}; + +class LocalDeclNode : public ExpressionNode +{ + public: + LocalDeclNode(NodeRef varref) : m_varref(varref) { } + virtual NodeRef evaluate() + { + parser_scope->putLocal(m_varref->getString(), 0.0); + return NULL; + } + protected: + NodeRef m_varref; +}; + +class BinOpNode : public ExpressionNode +{ + public: + BinOpNode(char op, NodeRef one, NodeRef two) + : m_op(op), one(one), two(two) + { + } + virtual NodeRef evaluate(); + protected: + char m_op; + NodeRef one; + NodeRef two; +}; + +class BoolExpressionNode : public Node +{ + public: + BoolExpressionNode(char op, NodeRef one, NodeRef two) + : m_op(op), one(one), two(two) + { + } + virtual NodeRef evaluate(); + protected: + char m_op; + NodeRef one; + NodeRef two; +}; + +class VarRefNode : public Node +{ + public: + VarRefNode(const std::string & str) { m_string = str; } + std::string getString() { return m_string; } + virtual NodeRef evaluate() + { + if (parser_scope->contains(m_string)) + { + return new NumberNode(parser_scope->get(m_string)); + } + std::cerr << "Error: No identifier '" << m_string << "' in scope" + << std::endl; + exit(4); + } + protected: + std::string m_string; +}; + +class ForNode : public Node +{ + public: + ForNode(NodeRef e1, NodeRef e2, NodeRef e3) + { + m_nodes[0] = e1; + m_nodes[1] = e2; + m_nodes[2] = e3; + } + virtual NodeRef evaluate(); + protected: + NodeRef m_nodes[3]; +}; + +/* this class is only used to hold a set of items coming out of a class's + * evaluate() from above. the evaluateChildren() top-level method will + * propagate children of this class up to the level of their parent */ +class EvaluatePropagateNode : public Node +{ }; #endif diff --git a/parser/parser.h b/parser/parser.h index 158c90c..a231518 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -4,9 +4,10 @@ #include "nodes.h" #include "util/refptr.h" +#include "util/Scope.h" #define YYSTYPE refptr -refptr parse(const char * fileName); +refptr parse(const char * fileName, refptr scope); #endif diff --git a/parser/parser.lex b/parser/parser.lex index 6b1ffc5..112fd89 100644 --- a/parser/parser.lex +++ b/parser/parser.lex @@ -14,9 +14,13 @@ \+ return PLUS; - return MINUS; -\* return STAR; +\* return TIMES; \/ return DIVIDE; % return MOD; +:= return ASSIGN; += return EQUALS; +!= return NOTEQUALS; +! return NOT; ; return SEMICOLON; : return COLON; @@ -36,8 +40,8 @@ \< return LESS; \> return GREATER; --?[0-9]+ *yylval = new IntegerNode(atoi(yytext)); return DEC_NUMBER; --?[0-9]*\.[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER; +[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER; +[0-9]*\.[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER; ambient return AMBIENT; ambient_occlusion return AMBIENT_OCCLUSION; @@ -81,10 +85,21 @@ up return UP; vfov return VFOV; width return WIDTH; +else return ELSE; +elsif return ELSIF; +for return FOR; +if return IF; +while return WHILE; +local return LOCAL; + [a-zA-Z_][a-zA-Z_0-9]* { *yylval = new IdentifierNode(yytext); return IDENTIFIER; } +\$[a-zA-Z_][a-zA-Z_0-9]* { + *yylval = new VarRefNode(yytext+1); + return VARREF; +} #.*\n yylloc->first_line++; yylloc->last_line++; \n yylloc->first_line++; yylloc->last_line++; diff --git a/parser/parser.yy b/parser/parser.yy index ebcb092..16f4cd6 100644 --- a/parser/parser.yy +++ b/parser/parser.yy @@ -5,6 +5,7 @@ #include #include "util/Vector.h" #include "util/refptr.h" +#include "util/Scope.h" #include "nodes.h" #include "parser.h" #include "parser.tab.hh" /* bison-generated header with YY[SL]TYPE */ @@ -24,6 +25,7 @@ int yywrap() } static refptr parsed_scene_node; +refptr parser_scope; %} @@ -33,9 +35,13 @@ static refptr parsed_scene_node; %token PLUS; %token MINUS; -%token STAR; +%token TIMES; %token DIVIDE; %token MOD; +%token ASSIGN; +%token EQUALS; +%token NOTEQUALS; +%token NOT; %token SEMICOLON; %token COLON; @@ -55,7 +61,6 @@ static refptr parsed_scene_node; %token LESS; %token GREATER; -%token DEC_NUMBER; %token REAL_NUMBER; %token AMBIENT; @@ -101,6 +106,19 @@ static refptr parsed_scene_node; %token WIDTH; %token IDENTIFIER; +%token VARREF; + +%token ELSE; +%token ELSIF; +%token FOR; +%token IF; +%token WHILE; +%token LOCAL; + +%right ASSIGN +%left PLUS MINUS +%left TIMES DIVIDE +%left UMINUS %% @@ -140,7 +158,7 @@ box_items: /* empty */ ; box_item: SIZE vector3 { - $$ = new SizeNode($2->getVector()); + $$ = new SizeNode($2); } | shape_item { $$ = $1; } ; @@ -160,16 +178,16 @@ camera_items: /* empty */ ; camera_item: POSITION vector3 { - $$ = new PositionNode($2->getVector()); + $$ = new PositionNode($2); } | LOOKAT vector3 { - $$ = new LookAtNode($2->getVector()); + $$ = new LookAtNode($2); } | UP vector3 { - $$ = new UpNode($2->getVector()); + $$ = new UpNode($2); } - | VFOV number { - $$ = new VFOVNode($2->getNumber()); + | VFOV expression { + $$ = new VFOVNode($2); } ; @@ -188,7 +206,7 @@ cyl_items: /* empty */ ; cyl_item: SIZE vector3 { - $$ = new SizeNode($2->getVector()); + $$ = new SizeNode($2); } | shape_item { $$ = $1; } ; @@ -213,14 +231,30 @@ extrude_item: polygon { $$ = $1; } | shape_item { $$ = $1; } ; +general_items: /* empty */ + | general_item general_items { + $$ = new ItemsNode(); + $$->addChild($1); + $$->addChildren($2); + } + ; + +general_item: transform_block { $$ = $1; } + | material_definition { $$ = $1; } + | shape_definition { $$ = $1; } + | shape { $$ = $1; } + | for { $$ = $1; } + | stmt_expression { $$ = $1; } + ; + intersect: INTERSECT LCURLY bool_items RCURLY { $$ = new IntersectNode(); $$->addChildren($3); } ; -jitter: JITTER number { - $$ = new JitterNode($2->getInteger()); +jitter: JITTER expression { + $$ = new JitterNode($2); } ; @@ -239,16 +273,16 @@ light_items: /* empty */ ; light_item: POSITION vector3 { - $$ = new PositionNode($2->getVector()); + $$ = new PositionNode($2); } | DIFFUSE vector3 { - $$ = new DiffuseNode($2->getVector()); + $$ = new DiffuseNode($2); } | SPECULAR vector3 { - $$ = new SpecularNode($2->getVector()); + $$ = new SpecularNode($2); } | COLOR vector3 { - $$ = new ColorNode($2->getVector()); + $$ = new ColorNode($2); } | radius { $$ = $1; @@ -273,25 +307,25 @@ material_items: /* empty */ ; material_item: COLOR vector3 { - $$ = new ColorNode($2->getVector()); + $$ = new ColorNode($2); } | AMBIENT vector3 { - $$ = new AmbientNode($2->getVector()); + $$ = new AmbientNode($2); } | DIFFUSE vector3 { - $$ = new DiffuseNode($2->getVector()); + $$ = new DiffuseNode($2); } | SPECULAR vector3 { - $$ = new SpecularNode($2->getVector()); + $$ = new SpecularNode($2); } - | REFLECTANCE number { - $$ = new ReflectanceNode($2->getNumber()); + | REFLECTANCE expression { + $$ = new ReflectanceNode($2); } - | SHININESS number { - $$ = new ShininessNode($2->getNumber()); + | SHININESS expression { + $$ = new ShininessNode($2); } - | TRANSPARENCY number { - $$ = new TransparencyNode($2->getNumber()); + | TRANSPARENCY expression { + $$ = new TransparencyNode($2); } ; @@ -306,21 +340,20 @@ material_ref: MATERIAL IDENTIFIER { } ; -number: DEC_NUMBER { $$ = $1; } - | REAL_NUMBER { $$ = $1; } +number: REAL_NUMBER { $$ = $1; } ; -ngon: NGON DEC_NUMBER COMMA number { - $$ = new NGonNode($2->getInteger()); - $$->addChild(new RadiusNode($4->getNumber())); +ngon: NGON expression COMMA expression { + $$ = new NGonNode($2); + $$->addChild(new RadiusNode($4)); } ; -offset: OFFSET number { - $$ = new OffsetNode($2->getNumber()); +offset: OFFSET expression { + $$ = new OffsetNode($2); } - | OFFSET number LCURLY offset_items RCURLY { - $$ = new OffsetNode($2->getNumber()); + | OFFSET expression LCURLY offset_items RCURLY { + $$ = new OffsetNode($2); $$->addChildren($4); } ; @@ -333,15 +366,14 @@ offset_items: /* empty */ } ; -offset_item: SCALE number { - $$ = new ScaleNode(new Vector($2->getNumber(), $2->getNumber(), - $2->getNumber())); +offset_item: SCALE expression { + $$ = new ScaleNode(new ScaleScalarNode($2)); } | SCALE vector2 { - $$ = new ScaleNode($2->getVector()); + $$ = new ScaleNode($2); } | POSITION vector2 { - $$ = new PositionNode($2->getVector()); + $$ = new PositionNode($2); } ; @@ -359,26 +391,26 @@ options_items: /* empty */ } ; -options_item: WIDTH DEC_NUMBER { - $$ = new WidthNode($2->getInteger()); +options_item: WIDTH expression { + $$ = new WidthNode($2); } - | HEIGHT DEC_NUMBER { - $$ = new HeightNode($2->getInteger()); + | HEIGHT expression { + $$ = new HeightNode($2); } - | MULTISAMPLE DEC_NUMBER { - $$ = new MultisampleNode($2->getInteger()); + | MULTISAMPLE expression { + $$ = new MultisampleNode($2); } - | MAXDEPTH DEC_NUMBER { - $$ = new MaxDepthNode($2->getInteger()); + | MAXDEPTH expression { + $$ = new MaxDepthNode($2); } - | EXPOSURE number { - $$ = new ExposureNode($2->getNumber()); + | EXPOSURE expression { + $$ = new ExposureNode($2); } | AMBIENT vector3 { - $$ = new AmbientNode($2->getVector()); + $$ = new AmbientNode($2); } - | AMBIENT_OCCLUSION DEC_NUMBER { - $$ = new AmbientOcclusionNode($2->getInteger()); + | AMBIENT_OCCLUSION expression { + $$ = new AmbientOcclusionNode($2); } ; @@ -396,8 +428,8 @@ plane_items: /* empty */ } ; -plane_item: POSITION vector3 COMMA number { - $$ = new PlanePositionNode($2->getVector(), $4->getNumber()); +plane_item: POSITION vector3 COMMA expression { + $$ = new PlanePositionNode($2, $4); } | shape_item { $$ = $1; } ; @@ -419,8 +451,8 @@ polygon_items: /* empty */ polygon_item: vector2 { $$ = $1; } ; -radius: RADIUS number { - $$ = new RadiusNode($2->getNumber()); +radius: RADIUS expression { + $$ = new RadiusNode($2); } ; @@ -433,12 +465,9 @@ scene_items: /* empty */ ; scene_item: camera { $$ = $1; } - | shape { $$ = $1; } - | options { $$ = $1; } | light { $$ = $1; } - | transform_block { $$ = $1; } - | material_definition { $$ = $1; } - | shape_definition { $$ = $1; } + | options { $$ = $1; } + | general_item { $$ = $1; } ; shape: plane { $$ = $1; } @@ -506,77 +535,125 @@ subtract: SUBTRACT LCURLY bool_items RCURLY { ; transform: TRANSLATE vector3 { - $$ = new TranslateNode($2->getVector()); + $$ = new TranslateNode($2); } - | ROTATE number COMMA vector3 { - $$ = new RotateNode($2->getNumber(), $4->getVector()); + | ROTATE expression COMMA vector3 { + $$ = new RotateNode($2, $4); } | SCALE vector3 { - $$ = new ScaleNode($2->getVector()); + $$ = new ScaleNode($2); } - | SCALE number { - $$ = new ScaleNode(new Vector($2->getNumber(), - $2->getNumber(), $2->getNumber())); + | SCALE expression { + $$ = new ScaleNode(new ScaleScalarNode($2)); } ; -transform_block: TRANSLATE vector3 LCURLY transform_block_items RCURLY { - $$ = new TranslateBlockNode($2->getVector()); +transform_block: TRANSLATE vector3 LCURLY general_items RCURLY { + $$ = new TranslateBlockNode($2); $$->addChildren($4); } - | ROTATE number COMMA vector3 LCURLY transform_block_items RCURLY { - $$ = new RotateBlockNode($2->getNumber(), $4->getVector()); + | ROTATE expression COMMA vector3 LCURLY general_items RCURLY { + $$ = new RotateBlockNode($2, $4); $$->addChildren($6); } - | SCALE vector3 LCURLY transform_block_items RCURLY { - $$ = new ScaleBlockNode($2->getVector()); + | SCALE vector3 LCURLY general_items RCURLY { + $$ = new ScaleBlockNode($2); $$->addChildren($4); } - | SCALE number LCURLY transform_block_items RCURLY { - $$ = new ScaleBlockNode( - new Vector($2->getNumber(), $2->getNumber(), - $2->getNumber())); + | SCALE expression LCURLY general_items RCURLY { + $$ = new ScaleBlockNode(new ScaleScalarNode($2)); $$->addChildren($4); } ; -transform_block_items: /* empty */ - | transform_block_item transform_block_items { - $$ = new ItemsNode(); - $$->addChild($1); - $$->addChildren($2); - } - ; - -transform_block_item: transform_block { $$ = $1; } - | shape { $$ = $1; } - | shape_definition { $$ = $1; } - ; - union: UNION LCURLY bool_items RCURLY { $$ = new UnionNode(); $$->addChildren($3); } ; -vector2: LESS number COMMA number GREATER { - refptr vec = - new Vector($2->getNumber(), $4->getNumber(), 0.0); - $$ = new VectorNode(vec); +vector2: LESS expression COMMA expression GREATER { + $$ = new VectorNode($2, $4, new NumberNode(0.0)); } ; -vector3: LESS number COMMA number COMMA number GREATER { - refptr vec = - new Vector($2->getNumber(), $4->getNumber(), $6->getNumber()); - $$ = new VectorNode(vec); +vector3: LESS expression COMMA expression COMMA expression GREATER { + $$ = new VectorNode($2, $4, $6); } ; +expression: term { $$ = $1; } + | expression TIMES term { $$ = new BinOpNode('*', $1, $3); } + | expression DIVIDE term { $$ = new BinOpNode('/', $1, $3); } + | MINUS expression %prec UMINUS { + $$ = new BinOpNode('-', new NumberNode(0.0), $2); + } + | stmt_expression { $$ = $1; } + ; + +maybe_expression: /* empty */ + | expression { $$ = $1; } + ; + +stmt_expression: assignment { $$ = $1; } + | local_assignment { $$ = $1; } + | local_decl { $$ = $1; } + ; + +bool_expression: expression LESS expression { + $$ = new BoolExpressionNode('<', $1, $3); + } + | expression GREATER expression { + $$ = new BoolExpressionNode('>', $1, $3); + } + | expression EQUALS expression { + $$ = new BoolExpressionNode('=', $1, $3); + } + | expression NOTEQUALS expression { + $$ = new BoolExpressionNode('n', $1, $3); + } + | NOT bool_expression { + $$ = new BoolExpressionNode('!', $2, NULL); + } + ; + +term: factor { $$ = $1; } + | term PLUS factor { $$ = new BinOpNode('+', $1, $3); } + | term MINUS factor { $$ = new BinOpNode('-', $1, $3); } + ; + +factor: number { $$ = $1; } + | VARREF { $$ = $1; } + | LPAREN expression RPAREN { $$ = $2; } + ; + +assignment: VARREF ASSIGN expression { + $$ = new AssignmentNode($1, $3); + } + ; + +local_assignment: LOCAL VARREF ASSIGN expression { + $$ = new LocalAssignmentNode($2, $4); + } + ; + +local_decl: LOCAL VARREF { + $$ = new LocalDeclNode($2); + } + ; + +for: FOR LPAREN maybe_expression SEMICOLON bool_expression SEMICOLON maybe_expression RPAREN LCURLY general_items RCURLY { + $$ = new ForNode($3, $5, $7); + $$->addChildren($10); + } + ; + %% -refptr parse(const char * fileName) +refptr parse(const char * fileName, refptr scope) { + parser_scope = scope; + yyin = fopen(fileName, "r"); if (yyin == NULL) { diff --git a/shapes/Shape.h b/shapes/Shape.h index 5e78d41..df6d083 100644 --- a/shapes/Shape.h +++ b/shapes/Shape.h @@ -125,6 +125,7 @@ class Shape refptr m_material; }; +typedef refptr ShapeRef; #endif diff --git a/util/Scope.h b/util/Scope.h new file mode 100644 index 0000000..1c58051 --- /dev/null +++ b/util/Scope.h @@ -0,0 +1,73 @@ + +#ifndef SCOPE_H +#define SCOPE_H + +#include +#include +#include + +class Scope +{ + public: + Scope() { push(); } + bool contains(const std::string & key) + { + for (m_list_type::const_reverse_iterator it = m_list.rbegin(); + it != m_list.rend(); + it++) + { + if (it->find(key) != it->end()) + { + return true; + } + } + return false; + } + double get(const std::string & key) + { + for (m_list_type::reverse_iterator it = m_list.rbegin(); + it != m_list.rend(); + it++) + { + if (it->find(key) != it->end()) + { + return (*it)[key]; + } + } + return 0.0; + } + void putLocal(const std::string & key, double val) + { + (*m_list.rbegin())[key] = val; + } + void putGlobal(const std::string & key, double val) + { + for (m_list_type::reverse_iterator it = m_list.rbegin(); + it != m_list.rend(); + it++) + { + if (it->find(key) != it->end()) + { + (*it)[key] = val; + return; + } + } + putLocal(key, val); + } + void push() + { + m_list.push_back(std::map< std::string, double >()); + } + void pop() + { + if (m_list.size() > 1) + { + m_list.pop_back(); + } + } + protected: + typedef std::list< std::map< std::string, double > > m_list_type; + m_list_type m_list; +}; + +#endif