00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <typeinfo>
00021 #include <string>
00022 #include <vector>
00023
00024 #include <archon/util/color.H>
00025 #include <archon/util/image.H>
00026
00027 #include "exception.H"
00028 #include "surface.H"
00029 #include "light.H"
00030 #include "object.H"
00031 #include "world.H"
00032
00033 #include "sceneloader.H"
00034
00035 using namespace std;
00036
00037 namespace Archon
00038 {
00039 using namespace Math;
00040 using namespace X3D;
00041
00042 namespace Raytracer
00043 {
00044 class SceneLoader
00045 {
00046 Ref<const Material> defaultMaterial;
00047 World *world;
00048 vector<View> *views;
00049 vector<pair<Vector3, const LightNode *> > *lights;
00050 Logger *logger;
00051
00052 Image loadTexture(const ImageTexture *imageTexture)
00053 {
00054 Ref<const Loader::ImageContents> c(dynamic_cast<const Loader::ImageContents *>(imageTexture->getContents().get()));
00055 return c ? c->image : Image();
00056 }
00057
00058 public:
00059 SceneLoader(Ref<const Material> defaultMaterial,
00060 World *world,
00061 vector<View> *views,
00062 vector<pair<Vector3, const LightNode *> > *lights,
00063 Logger *logger):
00064 defaultMaterial(defaultMaterial), world(world), views(views),
00065 lights(lights), logger(logger) {}
00066
00067 void doGroupingNode(const GroupingNode *g, const CoordSystem3x3 &coordSystem)
00068 {
00069 GroupingNode::const_iterator c=g->begin();
00070 while(c!=g->end()) dispatchChildNode(c++->get(), coordSystem);
00071 }
00072
00073 void dispatchGroupingNode(const GroupingNode *g, const CoordSystem3x3 &s)
00074 {
00075 if(const Transform *t = dynamic_cast<const Transform *>(g))
00076 doTransform(t, s);
00077 else doGroupingNode(g, s);
00078 }
00079
00080 void doTransform(const Transform *t, const CoordSystem3x3 &s)
00081 {
00082 CoordSystem3x3 u = s;
00083
00084 u.translate(t->getTranslation());
00085 u.translate(t->getCenter());
00086 u.basis.rotate(t->getRotation());
00087 u.basis.rotate(t->getScaleOrientation());
00088 u.basis.scale(t->getScale());
00089 u.basis.rotate(-t->getScaleOrientation());
00090 u.translate(-t->getCenter());
00091
00092 doGroupingNode(t, u);
00093 }
00094
00095 void dispatchChildNode(const ChildNode *child, const CoordSystem3x3 &coordSystem)
00096 {
00097 if(const Viewpoint *v = dynamic_cast<const Viewpoint *>(child))
00098 doViewpoint(v, coordSystem);
00099 else if(const LightNode *l = dynamic_cast<const LightNode *>(child))
00100 dispatchLightNode(l, coordSystem);
00101 else if(const Shape *s = dynamic_cast<const Shape *>(child))
00102 doShape(s, coordSystem);
00103 else if(const GroupingNode *g = dynamic_cast<const GroupingNode *>(child))
00104 dispatchGroupingNode(g, coordSystem);
00105 }
00106
00107 void doViewpoint(const Viewpoint *viewPoint,
00108 const CoordSystem3x3 &coordSystem)
00109 {
00110 if(!views) return;
00111 views->push_back(View(coordSystem *
00112 CoordSystem3x3(viewPoint->getPosition(),
00113 Matrix3x3(viewPoint->getOrientation())),
00114 viewPoint->getFieldOfView(),
00115 viewPoint->getName(),
00116 viewPoint->getDescription()));
00117 }
00118
00119
00120
00121 void dispatchLightNode(const LightNode *light,
00122 const CoordSystem3x3 &coordSystem)
00123 {
00124 if(const PointLight *p = dynamic_cast<const PointLight *>(light))
00125 doPointLight(p, coordSystem);
00126 else ARCHON_THROW1(InternalException, "'" + light->getType()->getName() +
00127 "' is not supported yet");
00128 }
00129
00130 void doPointLight(const PointLight *pointLight,
00131 const CoordSystem3x3 &coordSystem)
00132 {
00133 if(lights)
00134 lights->push_back(make_pair(coordSystem(pointLight->getLocation()), pointLight));
00135
00136 if(!world) return;
00137 if(!pointLight->getOn()) return;
00138
00139 world->addLight(new Light(coordSystem(pointLight->getLocation()), pointLight->getColor() * pointLight->getIntensity()));
00140 }
00141
00142 inline double maxCoord(const Vector3 &v)
00143 {
00144 const double c = v[0] > v[1] ? v[0] : v[1];
00145 return c > v[2] ? c : v[2];
00146 }
00147
00148 void doShape(const Shape *shape, const CoordSystem3x3 &coordSystem)
00149 {
00150 if(!world) return;
00151 const GeometryNode *geometry = shape->getGeometry().get();
00152 if(!geometry) return;
00153
00154 const AppearanceNode *appearanceNode =
00155 shape->getAppearance().get();
00156 const Appearance *appearance = dynamic_cast<const Appearance *>(appearanceNode);
00157 if(appearanceNode && !appearance)
00158 ARCHON_THROW1(InternalException, "'" + appearanceNode->getType()->getName() +
00159 "' is not supported yet");
00160 const MaterialNode *materialNode =
00161 appearance ? appearance->getMaterial().get() : 0;
00162 const Material *material = dynamic_cast<const Material *>(materialNode);
00163 if(materialNode && !material)
00164 ARCHON_THROW1(InternalException, "'" + materialNode->getType()->getName() +
00165 "' is not supported yet");
00166 const TextureNode *textureNode =
00167 appearance ? appearance->getTexture().get() : 0;
00168 const ImageTexture *imageTexture = dynamic_cast<const ImageTexture *>(textureNode);
00169 if(textureNode && !imageTexture)
00170 ARCHON_THROW1(InternalException, "'" + textureNode->getType()->getName() +
00171 "' is not supported yet");
00172
00173 if(!imageTexture->getContents()) imageTexture = 0;
00174
00175 Surface *surface = 0;
00176 if(!surface)
00177 {
00178 if(!material) material = defaultMaterial.get();
00179 double f = (maxCoord(material->getDiffuseColor()) +
00180 maxCoord(material->getSpecularColor()) +
00181 material->getTransparency())/0.9;
00182 if(f == 0) f = 1;
00183 double exponent = pow(160, material->getShininess());
00184 if(imageTexture)
00185 surface = new Texture(loadTexture(imageTexture),
00186 material->getAmbientIntensity(),
00187 maxCoord(material->getDiffuseColor())/f,
00188 maxCoord(material->getSpecularColor())/f,
00189 material->getTransparency()/f,
00190 exponent,
00191 exponent,
00192 material->getRefractiveIndex(),
00193 1, 1);
00194 else
00195 {
00196 surface =
00197 new StandardSurface(material->getDiffuseColor(),
00198 material->getAmbientIntensity(),
00199 maxCoord(material->getDiffuseColor())/f,
00200 maxCoord(material->getSpecularColor())/f,
00201 material->getTransparency()/f,
00202 exponent,
00203 exponent,
00204 material->getRefractiveIndex());
00205 }
00206 world->addSurface(surface);
00207 }
00208
00209 if(const Box *box = dynamic_cast<const Box *>(geometry))
00210 {
00211 const double x = box->getSize()[0]/2;
00212 const double y = box->getSize()[1]/2;
00213 const double z = box->getSize()[2]/2;
00214
00215 Vector3 *v0 = new Vector3(coordSystem * Vector3(-x, -y, -z));
00216 Vector3 *v1 = new Vector3(coordSystem * Vector3(-x, -y, z));
00217 Vector3 *v2 = new Vector3(coordSystem * Vector3( x, -y, z));
00218 Vector3 *v3 = new Vector3(coordSystem * Vector3( x, -y, -z));
00219 Vector3 *v4 = new Vector3(coordSystem * Vector3(-x, y, -z));
00220 Vector3 *v5 = new Vector3(coordSystem * Vector3(-x, y, z));
00221 Vector3 *v6 = new Vector3(coordSystem * Vector3( x, y, z));
00222 Vector3 *v7 = new Vector3(coordSystem * Vector3( x, y, -z));
00223
00224 world->addVertex(v0);
00225 world->addVertex(v1);
00226 world->addVertex(v2);
00227 world->addVertex(v3);
00228 world->addVertex(v4);
00229 world->addVertex(v5);
00230 world->addVertex(v6);
00231 world->addVertex(v7);
00232
00233 vector<Vector3 *> vertices;
00234 vector<Polygon *> polygons;
00235
00236
00237 vertices.push_back(v0);
00238 vertices.push_back(v1);
00239 vertices.push_back(v5);
00240 vertices.push_back(v4);
00241 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00242 Vector2(1, 0), Vector2(1, 1)));
00243 vertices.clear();
00244
00245
00246 vertices.push_back(v2);
00247 vertices.push_back(v3);
00248 vertices.push_back(v7);
00249 vertices.push_back(v6);
00250 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00251 Vector2(1, 0), Vector2(1, 1)));
00252 vertices.clear();
00253
00254
00255 vertices.push_back(v0);
00256 vertices.push_back(v3);
00257 vertices.push_back(v2);
00258 vertices.push_back(v1);
00259 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00260 Vector2(1, 0), Vector2(1, 1)));
00261 vertices.clear();
00262
00263
00264 vertices.push_back(v5);
00265 vertices.push_back(v6);
00266 vertices.push_back(v7);
00267 vertices.push_back(v4);
00268 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00269 Vector2(1, 0), Vector2(1, 1)));
00270 vertices.clear();
00271
00272
00273 vertices.push_back(v3);
00274 vertices.push_back(v0);
00275 vertices.push_back(v4);
00276 vertices.push_back(v7);
00277 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00278 Vector2(1, 0), Vector2(1, 1)));
00279 vertices.clear();
00280
00281
00282 vertices.push_back(v1);
00283 vertices.push_back(v2);
00284 vertices.push_back(v6);
00285 vertices.push_back(v5);
00286 polygons.push_back(new Polygon(surface, vertices, Vector2(0, 0),
00287 Vector2(1, 0), Vector2(1, 1)));
00288
00289 world->addObject(new ConvexPolyhedron(polygons));
00290 }
00291 else if(const X3D::Cylinder *cylinder = dynamic_cast<const X3D::Cylinder *>(geometry))
00292 {
00293 CoordSystem3x3 s = coordSystem;
00294 s.basis.x *= cylinder->getRadius();
00295 s.basis.y *= cylinder->getHeight()/2;
00296 s.basis.z *= cylinder->getRadius();
00297 if(!cylinder->getSide() || !cylinder->getTop() || !cylinder->getBottom() && logger)
00298 logger->log("Non-solid sylinders are not supported by the raytracer");
00299 world->addObject(new Cylinder(surface, s));
00300 }
00301 else if(const X3D::Sphere *sphere = dynamic_cast<const X3D::Sphere *>(geometry))
00302 {
00303 CoordSystem3x3 s = coordSystem;
00304 s.basis *= sphere->getRadius();
00305 world->addObject(new Sphere(surface, s));
00306 }
00307 else if(const X3D::Torus *torus = dynamic_cast<const X3D::Torus *>(geometry))
00308 {
00309 world->addObject(new Torus(surface, coordSystem,
00310 torus->getMajorRadius(),
00311 torus->getMinorRadius()));
00312 }
00313 else if(const IndexedFaceSet *set = dynamic_cast<const IndexedFaceSet *>(geometry))
00314 {
00315 vector<Vector3 *> vertices;
00316 vector<Vector2> texVertices;
00317 for(unsigned i=0; i<=set->getCoordIndex().size(); ++i)
00318 {
00319 int j;
00320 if(i==set->getCoordIndex().size())
00321 {
00322 if(vertices.empty()) break;
00323 j = -1;
00324 }
00325 else j = set->getCoordIndex()[i];
00326
00327 if(j == -1)
00328 {
00329 if(!set->getCCW())
00330 {
00331 reverse(vertices.begin(), vertices.end());
00332 reverse(texVertices.begin(), texVertices.end());
00333 }
00334
00335 world->addObject(new Polygon(surface, vertices,
00336 imageTexture ? texVertices[0] : Vector2(0, 0),
00337 imageTexture ? texVertices[1] : Vector2(0, 0),
00338 imageTexture ? texVertices[2] : Vector2(0, 0)));
00339
00340 vertices.clear();
00341 texVertices.clear();
00342 }
00343 else
00344 {
00345 Vector3 *v = new Vector3(coordSystem((dynamic_cast<const Coordinate *>(set->getCoord().get()))->getPoint()[j]));
00346 world->addVertex(v);
00347 vertices.push_back(v);
00348 if(imageTexture)
00349 {
00350 int k = set->getTexCoordIndex().empty() ? j : set->getTexCoordIndex()[i];
00351 texVertices.push_back((dynamic_cast<const TextureCoordinate *>(set->getTexCoord().get()))->getPoint()[k]);
00352 }
00353 }
00354 }
00355 }
00356 else ARCHON_THROW1(InternalException, "Unexpected geometry type '" +
00357 geometry->getType()->getName() + "'");
00358 }
00359 };
00360
00361 void get_scene(Ref<const Scene> scene,
00362 Ref<const Material> defaultMaterial,
00363 World *world,
00364 vector<View> *views,
00365 vector<pair<Vector3, const LightNode *> > *lights,
00366 Logger *logger)
00367 {
00368 SceneLoader sceneLoader(defaultMaterial, world, views, lights, logger);
00369 sceneLoader.dispatchGroupingNode(scene->getRootGroup().get(), CoordSystem3x3::identity());
00370 }
00371 }
00372 }