fart/main/Scene-load.cc
Josh Holtrop 0ea6e96e0a filled out Scene::processTransformBlock()
git-svn-id: svn://anubis/fart/trunk@170 7f9b0f55-74a9-4bce-be96-3c2cd072584d
2009-03-01 22:31:42 +00:00

573 lines
15 KiB
C++

#include <typeinfo>
#include <iostream>
#include "Scene.h"
#include "Light.h"
#include "parser/parser.h"
#include "parser/nodes.h"
using namespace std;
typedef vector< refptr<Node> >::const_iterator Node_Iterator;
void Scene::load(const char * filename)
{
refptr<Node> node = parse(filename);
processNode(node);
Transform transform;
refptr<Material> m = new Material();
m->setDiffuseColor(Color::white);
m->setAmbientColor(Color::white);
refptr<Shape> 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<Shape> shape1 = new Sphere(0.8);
shape1->setMaterial(m);
shape1->setTransform(transform);
refptr<Shape> 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> light = new PointLight();
light->setPosition(Vector(2, -1, 2));
m_lights.push_back(light);
}
void Scene::processNode(refptr<Node> node)
{
if (node.isNull())
return;
if ( typeid(*node) == typeid(SceneNode) )
{
processChildren(node);
}
else if ( node->isShape() )
{
refptr<Shape> shape = processShape(node);
if ( ! shape.isNull() )
m_shapes.push_back(shape);
}
else if ( typeid(*node) == typeid(LightNode) )
{
refptr<Light> 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<Shape> Scene::processShape(refptr<Node> 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<Shape>(NULL);
}
void Scene::processChildren(refptr<Node> node)
{
std::vector< refptr<Node> > & children = node->getChildren();
for (int i = 0, sz = children.size(); i < sz; i++)
{
processNode(children[i]);
}
}
void Scene::processCamera(refptr<Node> 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> 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> 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();
}
refptr<Material> Scene::processMaterial(refptr<Node> node)
{
refptr<Material> 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<Shape> Scene::processBox(refptr<Node> node)
{
refptr<Vector> size = new Vector(1, 1, 1);
refptr<Material> 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<Shape> box = new Box(size);
if ( ! material.isNull() )
box->setMaterial(material);
box->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return box;
}
refptr<Shape> Scene::processCyl(refptr<Node> node)
{
double radius1 = 1.0;
double radius2 = 1.0;
double height = 1.0;
refptr<Material> 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<Shape> 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<Light> Scene::processLight(refptr<Node> node)
{
return refptr<Light>(NULL);
}
refptr<Shape> Scene::processPlane(refptr<Node> node)
{
Vector normal(0, 0, 1);
double dist = 0;
refptr<Material> 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<Shape> 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<Shape> Scene::processSphere(refptr<Node> node)
{
double radius = 1.0;
refptr<Material> 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<Shape> sphere = new Sphere(radius);
if ( ! material.isNull() )
sphere->setMaterial(material);
sphere->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return sphere;
}
refptr<Shape> Scene::processBool(refptr<Node> node)
{
refptr<Shape> shape1, shape2;
refptr<Material> 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> 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> 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;
}