sceneloader.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
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           // Left
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           // Right
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           // Bottom
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           // Top
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           // Back
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           // Front
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 }

Generated on Sun Jul 30 22:55:51 2006 for Archon by  doxygen 1.4.4