#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); Transform transform; refptr m = new Material(); m->setDiffuseColor(Color::white); m->setAmbientColor(Color::white); refptr shape = new Plane(0, 0, 1, 2); shape->setTransform(transform); shape->setMaterial(m); m_shapes.push_back(shape); transform.translate(1.0, 5.0, 0.5); m = new Material(); m->setDiffuseColor(Color::red); m->setAmbientColor(Color::red); shape = new Sphere(1.0); shape->setTransform(transform); shape->setMaterial(m); m_shapes.push_back(shape); transform.translate(-1.0, -5.0, -0.5); transform.translate(-1, 3, -0.5); refptr shape1 = new Sphere(0.8); shape1->setMaterial(m); shape1->setTransform(transform); refptr shape2 = new Box(new Vector(2, 2, 0.6)); m = new Material(); m->setDiffuseColor(Color::magenta); m->setAmbientColor(Color::magenta); shape2->setMaterial(m); transform.rotate(20, 0, 1, 0); shape2->setTransform(transform); shape = new Intersect(shape1, shape2); m_shapes.push_back(shape); transform.rotate(-20, 0, 1, 0); transform.translate(1, -3, 0.5); transform.translate(1.5, 3.2, -0.7); transform.rotate(15, 0, 0, 1); m = new Material(); m->setDiffuseColor(Color::magenta); m->setAmbientColor(Color::magenta); shape1 = new Box(new Vector(1, 1, 1)); shape1->setMaterial(m); shape1->setTransform(transform); m = new Material(); m->setDiffuseColor(Color::yellow); m->setAmbientColor(Color::yellow); shape2 = new Sphere(0.6); transform.translate(-0.5, -0.5, 0.5); shape2->setTransform(transform); shape2->setMaterial(m); shape = new Subtract(shape1, shape2); m_shapes.push_back(shape); transform.rotate(-15, 0, 0, 1); transform.translate(-1.0, -2.7, 0.2); transform.translate(1, 5, -1.5); m = new Material(); m->setDiffuseColor(Color::blue); m->setAmbientColor(Color::blue); shape = new Box(new Vector(1.8, 1.8, 0.5)); shape->setTransform(transform); shape->setMaterial(m); m_shapes.push_back(shape); transform.translate(-1, -5, 1.5); transform.translate(-0.5, 6.5, 1.5); transform.rotate(45, 1, 0, 0); m = new Material(); m->setDiffuseColor(Color::cyan); m->setAmbientColor(Color::cyan); shape = new Cyl(1.0, 0.0, 2.0); shape->setTransform(transform); shape->setMaterial(m); m_shapes.push_back(shape); transform.rotate(-45, 1, 0, 0); transform.translate(0.5, -6.5, -1.5); transform.translate(-2.0, 5.0, 1.5); transform.rotate(45, 0, 0, 1); transform.rotate(45, 1, 0, 0); m = new Material(); m->setDiffuseColor(Color::yellow); m->setAmbientColor(Color::yellow); shape = new Box(new Vector(1, 1, 1)); shape->setTransform(transform); shape->setMaterial(m); m_shapes.push_back(shape); transform.rotate(-45, 1, 0, 0); transform.rotate(-45, 0, 0, 1); transform.translate(2.0, -5.0, -1.5); refptr light = new PointLight(); light->setPosition(Vector(2, -1, 2)); m_lights.push_back(light); } 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 { 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) { } refptr Scene::processMaterial(refptr node) { 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 ( typeid(**it) == typeid(MaterialNode) ) { 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 ( typeid(**it) == typeid(MaterialNode) ) { 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) { return refptr(NULL); } 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 ( typeid(**it) == typeid(MaterialNode) ) { 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 ( typeid(**it) == typeid(MaterialNode) ) { 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 ( typeid(**it) == typeid(MaterialNode) ) { 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; }