#include #include #include #include "Scene.h" #include "Light.h" #include "parser/parser.h" #include "parser/nodes.h" #include "util/Polygon.h" #include "util/Scope.h" using namespace std; typedef vector< refptr >::const_iterator Node_Iterator; void Scene::load(const char * filename) { 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); /* now we have a new node tree under 'dummy' with no scripting nodes */ processScene(processed_scene); } } void Scene::processScene(refptr node) { /* first process any cameras present */ int cameras_found = 0; for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(CameraNode) ) { cameras_found++; if (cameras_found == 1) processCamera(*it); else { cerr << "Error: multiple camera definitions found!" << endl; exit(5); } } } /* then any other scene-specific items */ for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(LightNode) ) { 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); } } ShapeRef Scene::processShape(refptr node) { if ( typeid(*node) == typeid(BoxNode) ) { return processBox(node); } else if ( typeid(*node) == typeid(PlaneNode) ) { return processPlane(node); } else if ( typeid(*node) == typeid(SphereNode) ) { return processSphere(node); } else if ( typeid(*node) == typeid(CylNode) ) { return processCyl(node); } else if ( typeid(*node) == typeid(IntersectNode) || typeid(*node) == typeid(UnionNode) || typeid(*node) == typeid(SubtractNode) ) { return processBool(node); } else if ( typeid(*node) == typeid(ExtrudeNode) ) { return processExtrude(node); } else if ( typeid(*node) == typeid(ShapeRefNode) ) { return processShapeRef(node); } else { cerr << "Error: Unknown shape!" << endl; exit(3); } return ShapeRef(NULL); } void Scene::processCamera(refptr node) { Vector position(0, 0, 0); Vector look_at(0, 1, 0); Vector up(0, 0, 1); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(PositionNode) ) { position = * (*it)->getVector(); } else if ( typeid(**it) == typeid(LookAtNode) ) { look_at = * (*it)->getVector(); } else if ( typeid(**it) == typeid(UpNode) ) { up = * (*it)->getVector(); } else if ( typeid(**it) == typeid(VFOVNode) ) { m_vfov = (*it)->getNumber(); } } m_transforms.top().lookAt(position, look_at, up); } void Scene::processOptions(refptr node) { for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(WidthNode) ) { m_width = (*it)->getInteger(); } else if ( typeid(**it) == typeid(HeightNode) ) { m_height = (*it)->getInteger(); } else if ( typeid(**it) == typeid(ExposureNode) ) { m_exposure = (*it)->getNumber(); if (m_exposure < 0.0) m_exposure = 0.0; } else if ( typeid(**it) == typeid(MultisampleNode) ) { m_multisample_level = (*it)->getInteger(); } else if ( typeid(**it) == typeid(MaxDepthNode) ) { m_max_depth = (*it)->getInteger(); } else if ( typeid(**it) == typeid(AmbientNode) ) { setAmbientLight(Color((*it)->getVector())); } else if ( typeid(**it) == typeid(AmbientOcclusionNode) ) { m_ambient_occlusion_level = (*it)->getInteger(); } } } vector Scene::processTransformBlock(refptr node) { if ( typeid(*node) == typeid(TranslateBlockNode) ) { m_transforms.push(m_transforms.top()); m_transforms.top().translate(node->getVector()); } else if ( typeid(*node) == typeid(RotateBlockNode) ) { m_transforms.push(m_transforms.top()); m_transforms.top().rotate(node->getNumber(), node->getVector()); } else if ( typeid(*node) == typeid(ScaleBlockNode) ) { m_transforms.push(m_transforms.top()); m_transforms.top().scale(node->getVector()); } else { cerr << "Unknown transformation block node type!" << endl; exit(4); } 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(); it++) { if ((*it)->isTransformBlock()) { incoming = processTransformBlock(*it); } else if ( typeid(**it) == typeid(MaterialDefinitionNode) ) { processMaterialDefinition(*it); } else if ( typeid(**it) == typeid(ShapeDefinitionNode) ) { processShapeDefinition(*it); } else if ( (*it)->isShape() ) { shapes.push_back(processShape(*it)); } while (incoming.size() > 0) { shapes.push_back(incoming[0]); incoming.erase(incoming.begin()); } } return shapes; } void Scene::processMaterialDefinition(refptr node) { map< string, refptr >::iterator it = m_materials.find(node->getString()); if ( it == m_materials.end() ) { m_materials[node->getString()] = processMaterial(node); } else { cerr << "Error: duplicate material definition for material '" << node->getString() << "'" << endl; exit(4); } } refptr Scene::processMaterial(refptr node) { if ( typeid(*node) == typeid(MaterialRefNode) ) { map< string, refptr >::iterator it = m_materials.find(node->getString()); if ( it == m_materials.end() ) { cerr << "Undefined material '" << node->getString() << "' requested!" << endl; exit(4); } return m_materials[node->getString()]; } refptr material = new Material(); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(ColorNode) ) { material->setDiffuseColor(Color((*it)->getVector())); material->setAmbientColor(Color((*it)->getVector())); } else if ( typeid(**it) == typeid(AmbientNode) ) { material->setAmbientColor(Color((*it)->getVector())); } else if ( typeid(**it) == typeid(DiffuseNode) ) { material->setDiffuseColor(Color((*it)->getVector())); } else if ( typeid(**it) == typeid(SpecularNode) ) { material->setSpecularColor(Color((*it)->getVector())); } else if ( typeid(**it) == typeid(ReflectanceNode) ) { material->setReflectance((*it)->getNumber()); } else if ( typeid(**it) == typeid(ShininessNode) ) { material->setShininess((*it)->getNumber()); } else if ( typeid(**it) == typeid(TransparencyNode) ) { material->setTransparency((*it)->getNumber()); } } return material; } ShapeRef Scene::processBox(refptr node) { refptr size = new Vector(1, 1, 1); refptr material; bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(SizeNode) ) { size = (*it)->getVector(); } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } ShapeRef box = new Box(size); if ( ! material.isNull() ) box->setMaterial(material); box->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return box; } ShapeRef Scene::processCyl(refptr node) { double radius1 = 1.0; double radius2 = 1.0; double height = 1.0; refptr material; bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(SizeNode) ) { const Vector & v = *(*it)->getVector(); radius1 = v[0]; radius2 = v[1]; height = v[2]; } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } ShapeRef cyl = new Cyl(radius1, radius2, height); if ( ! material.isNull() ) cyl->setMaterial(material); cyl->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return cyl; } refptr Scene::processLight(refptr node) { refptr light = new PointLight(); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(PositionNode) ) { refptr v = (*it)->getVector(); light->setPosition(m_transforms.top().transform_point(*v)); } else if ( typeid(**it) == typeid(DiffuseNode) ) { Color c((*it)->getVector()); light->setDiffuseColor(c); } else if ( typeid(**it) == typeid(SpecularNode) ) { Color c((*it)->getVector()); light->setSpecularColor(c); } else if ( typeid(**it) == typeid(ColorNode) ) { Color c((*it)->getVector()); light->setDiffuseColor(c); light->setSpecularColor(c); } else if ( typeid(**it) == typeid(RadiusNode) ) { light->setRadius((*it)->getNumber()); } else if ( typeid(**it) == typeid(JitterNode) ) { light->setJitter((*it)->getInteger()); } } return light; } ShapeRef Scene::processPlane(refptr node) { Vector normal(0, 0, 1); double dist = 0; refptr material; bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(PlanePositionNode) ) { normal = *(*it)->getVector(); dist = (*it)->getNumber(); } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } ShapeRef plane = new Plane(normal[0], normal[1], normal[2], dist); if ( ! material.isNull() ) plane->setMaterial(material); plane->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return plane; } ShapeRef Scene::processSphere(refptr node) { double radius = 1.0; refptr material; bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(RadiusNode) ) { radius = (*it)->getNumber(); } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } ShapeRef sphere = new Sphere(radius); if ( ! material.isNull() ) sphere->setMaterial(material); sphere->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return sphere; } ShapeRef Scene::processBool(refptr node) { vector shapes; refptr material; bool restore_transform = processTransforms(node); m_transforms.push(Transform()); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( (*it)->isShape() ) { ShapeRef shape = processShape(*it); if ( ! shape.isNull() ) shapes.push_back(shape); } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } else if ( (*it)->isTransformBlock() ) { vector in = processTransformBlock(*it); for (int i = 0, sz = in.size(); i < sz; i++) { shapes.push_back(in[i]); } } else if ( typeid(**it) == typeid(ShapeDefinitionNode) ) { processShapeDefinition(*it); } } if (shapes.size() < 2) { cerr << "Error: boolean objects must have 2 or more sub-objects!" << endl; exit(3); } ShapeRef shape; if ( typeid(*node) == typeid(IntersectNode) ) shape = new Intersect(shapes); else if ( typeid(*node) == typeid(UnionNode) ) shape = new Union(shapes); else if ( typeid(*node) == typeid(SubtractNode) ) shape = new Subtract(shapes); else { cerr << __FILE__ << ": " << __LINE__ << ": error: bool object unrecognized" << endl; exit(3); } if ( ! material.isNull() ) shape->setMaterial(material); m_transforms.pop(); shape->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return shape; } ShapeRef Scene::processExtrude(refptr node) { refptr material; Extrude * extrude = new Extrude(); bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(PolygonNode) ) { extrude->addPolygon(processPolygon(*it)); } else if ( typeid(**it) == typeid(NGonNode) ) { extrude->addPolygon(processNGon(*it)); } else if ( typeid(**it) == typeid(OffsetNode) ) { double distance = (*it)->getNumber(); if (distance <= 0.0) { cerr << "Error: extrude distance must be positive" << endl; exit(3); } Vector scale(1, 1, 1); Vector position(0, 0, 0); for (Node_Iterator it2 = (*it)->getChildren().begin(); it2 != (*it)->getChildren().end(); it2++) { if ( typeid(**it2) == typeid(ScaleNode) ) { scale = * (*it2)->getVector(); } else if ( typeid(**it2) == typeid(PositionNode) ) { position = * (*it2)->getVector(); } } if (scale[0] < 0.0 || scale[1] < 0.0) { cerr << "Error: extrude scale cannot be negative" << endl; exit(3); } extrude->addOffset(distance, scale, position); } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } if ( ! material.isNull() ) extrude->setMaterial(material); extrude->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return extrude; } refptr Scene::processPolygon(refptr node) { refptr p = new Polygon(); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(VectorNode) ) { p->push_back((*it)->getVector()); } else { cerr << "Error: Unknown polygon sub-object" << endl; exit(3); } } if (p->size() < 3) { cerr << "Error: Polygon with fewer than three points!" << endl; exit(3); } return p; } refptr Scene::processNGon(refptr node) { refptr p = new Polygon(); double radius = node->getChildren()[0]->getNumber(); int n = node->getInteger(); int step = n < 0 ? -1 : 1; n = abs(n); if (n < 3) n = 3; int pos = 0; double astep = 2.0 * M_PI / n; for (int i = 0; i < n; i++) { p->push_back(new Vector( radius * cos(pos * astep), radius * sin(pos * astep), 0.0)); pos += step; } return p; } ShapeRef Scene::processShapeRef(refptr node) { if (m_shape_definitions.find(node->getString()) == m_shape_definitions.end()) { cerr << "Error: no shape definition for '" << node->getString() << "' found!" << endl; exit(3); } refptr material; ShapeRef shape = m_shape_definitions[node->getString()]->clone(); bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } if ( ! material.isNull() ) shape->setMaterial(material); shape->setTransform(m_transforms.top() * shape->getTransform()); if (restore_transform) m_transforms.pop(); return shape; } bool Scene::processTransforms(refptr node) { bool did_any = false; for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( typeid(**it) == typeid(TranslateNode) ) { if (did_any == false) { m_transforms.push(m_transforms.top()); did_any = true; } m_transforms.top().translate((*it)->getVector()); } else if ( typeid(**it) == typeid(RotateNode) ) { if (did_any == false) { m_transforms.push(m_transforms.top()); did_any = true; } m_transforms.top().rotate((*it)->getNumber(), (*it)->getVector()); } else if ( typeid(**it) == typeid(ScaleNode) ) { if (did_any == false) { m_transforms.push(m_transforms.top()); did_any = true; } m_transforms.top().scale((*it)->getVector()); } } return did_any; } void Scene::processShapeDefinition(refptr node) { m_transforms.push(Transform()); m_shape_definitions[node->getString()] = processShape(node->getChildren()[0]); m_transforms.pop(); }