#include #include #include "Scene.h" #include "Light.h" #include "parser/parser.h" #include "parser/nodes.h" using namespace std; typedef vector< refptr >::const_iterator Node_Iterator; void Scene::load(const char * filename) { refptr node = parse(filename); processNode(node); } void Scene::processNode(refptr node) { if (node.isNull()) return; if ( typeid(*node) == typeid(SceneNode) ) { processChildren(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(CameraNode) ) { processCamera(node); } else if ( typeid(*node) == typeid(OptionsNode) ) { processOptions(node); } else if ( typeid(*node) == typeid(TranslateBlockNode) ) { processTransformBlock(node); } else if ( typeid(*node) == typeid(RotateBlockNode) ) { processTransformBlock(node); } else if ( typeid(*node) == typeid(ScaleBlockNode) ) { processTransformBlock(node); } else if ( typeid(*node) == typeid(MaterialDefinitionNode) ) { processMaterialDefinition(node); } else { cerr << __FILE__ << ": " << __LINE__ << ": error: unrecognized node!" << endl; } } refptr 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) ) { return processBool(node); } else if ( typeid(*node) == typeid(UnionNode) ) { return processBool(node); } else if ( typeid(*node) == typeid(SubtractNode) ) { return processBool(node); } return refptr(NULL); } void Scene::processChildren(refptr node) { std::vector< refptr > & children = node->getChildren(); for (int i = 0, sz = children.size(); i < sz; i++) { processNode(children[i]); } } 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(MultisampleNode) ) { m_multisample_level = (*it)->getInteger(); } } } void 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()); } processChildren(node); m_transforms.pop(); } void Scene::processMaterialDefinition(refptr node) { map< string, refptr >::iterator it = m_materials.find(node->getString()); if ( it == m_materials.end() ) { cout << "Creating material " << node->getString() << endl; 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()); } } return material; } refptr 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); } } refptr box = new Box(size); if ( ! material.isNull() ) box->setMaterial(material); box->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return box; } refptr 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); } } refptr 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) ) { light->setPosition((*it)->getVector()); } else if ( typeid(**it) == typeid(DiffuseNode) ) { Color c(node->getVector()); light->setDiffuseColor(c); } else if ( typeid(**it) == typeid(SpecularNode) ) { Color c(node->getVector()); light->setSpecularColor(c); } else if ( typeid(**it) == typeid(ColorNode) ) { Color c(node->getVector()); light->setDiffuseColor(c); light->setSpecularColor(c); } } return light; } refptr 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); } } refptr 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; } refptr 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); } } refptr sphere = new Sphere(radius); if ( ! material.isNull() ) sphere->setMaterial(material); sphere->setTransform(m_transforms.top()); if (restore_transform) m_transforms.pop(); return sphere; } refptr Scene::processBool(refptr node) { refptr shape1, shape2; refptr material; int shapes_seen = 0; bool restore_transform = processTransforms(node); for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++) { if ( node->isShape() ) { switch (shapes_seen) { case 0: shape1 = processShape(node); break; case 1: shape2 = processShape(node); break; } shapes_seen++; } else if ( (*it)->isMaterial() ) { material = processMaterial(*it); } } if (shapes_seen < 2 || shape1.isNull() || shape2.isNull()) { if (shapes_seen < 2) cerr << __FILE__ << ": " << __LINE__ << ": error: only saw " << shapes_seen << " child shapes!" << endl; if (shape1.isNull()) cerr << __FILE__ << ": " << __LINE__ << ": error: shape1 is null!" << endl; if (shape2.isNull()) cerr << __FILE__ << ": " << __LINE__ << ": error: shape2 is null!" << endl; exit(3); } refptr shape; if ( typeid(*node) == typeid(IntersectNode) ) shape = new Intersect(shape1, shape2); else if ( typeid(*node) == typeid(UnionNode) ) shape = new Union(shape1, shape2); else if ( typeid(*node) == typeid(SubtractNode) ) shape = new Subtract(shape1, shape2); else { cerr << __FILE__ << ": " << __LINE__ << ": error: bool object unrecognized" << endl; exit(3); } if ( ! material.isNull() ) shape->setMaterial(material); shape->setTransform(m_transforms.top()); 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; }