Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

scenebuilder.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "scenebuilder.h"   // include first
00024 #include "common/math/point2.h"
00025 #include "common/math/quaternion.h"
00026 #include "common/meshio/aseloader.h"
00027 #include "common/meshio/meshmodifier.h"
00028 #include "common/meshio/objloader.h"
00029 #include "common/meshio/smartloader.h"
00030 #include "common/meshio/triloader.h"
00031 #include "common/misc/iclonable.h"
00032 #include "common/misc/stringutils.h"
00033 #include "common/misc/xercesmanager.h"
00034 #include "common/misc/xercesutils.h"
00035 #include "parametermap.h"
00036 #include "renderer/basicsurfaceshader.h"
00037 #include "renderer/collection.h"
00038 #include "renderer/constanttexture.h"
00039 #include "renderer/framebuffer.h"
00040 #include "renderer/ibdf.h"
00041 #include "renderer/iedf.h"
00042 #include "renderer/ilight.h"
00043 #include "renderer/isurfaceshader.h"
00044 #include "renderer/itexture.h"
00045 #include "renderer/lambertianbrdf.h"
00046 #include "renderer/lambertianedf.h"
00047 #include "renderer/map2.h"
00048 #include "renderer/meshbuilder.h"
00049 #include "renderer/octree.h"
00050 #include "renderer/perfectspecularbrdf.h"
00051 #include "renderer/scene.h"
00052 
00053 // Cameras.
00054 #include "renderer/pinholecamera.h"
00055 #include "renderer/thinlenscamera.h"
00056 
00057 // Lights.
00058 #include "renderer/pointlight.h"
00059 
00060 // Objects.
00061 #include "renderer/cube.h"
00062 #include "renderer/mesh.h"
00063 #include "renderer/plane.h"
00064 #include "renderer/ring.h"
00065 #include "renderer/sphere.h"
00066 #include "renderer/square.h"
00067 
00068 #include <xercesc/parsers/XercesDOMParser.hpp>
00069 #include <xercesc/sax/ErrorHandler.hpp>
00070 #include <xercesc/sax/SAXParseException.hpp>
00071 
00072 #include <algorithm>
00073 #include <cassert>
00074 #include <sstream>
00075 #include <vector>
00076 
00077 using namespace sheep;
00078 using namespace std;
00079 using namespace toxic;
00080 using namespace xercesc;
00081 
00082 //! Default horizontal field of view in degrees (for all camera types).
00083 const Real DEFAULT_CAMERA_HFOV = 70.0;
00084 
00085 SceneBuilder::SceneBuilder(const Context &context,
00086                            const Framebuffer *framebuffer,
00087                            const string &filename,
00088                            const string &home_path,
00089                            ConsoleProgressMonitor *progmon) :
00090     m_context(context),
00091     m_framebuffer(framebuffer),
00092     m_path(StringUtils::GetPath(filename)),
00093     m_progmon(progmon),
00094     m_scene(new Scene()),
00095     m_camera(0)
00096 {
00097     assert(m_framebuffer);
00098     assert(m_progmon);
00099 
00100     // The root object is always a collection (even if we're going to use
00101     // an octree, we'll still need a collection to store unbounded objects
00102     // like infinite planes).
00103     m_root = new Collection(Matrix4::Identity());
00104     m_scene->SetRootObject(m_root);
00105 
00106     //!\todo Choose between Collection and Octree at runtime, depending
00107     //! of the number of objects (with a user-defined thresold).
00108     bool use_octree = true;
00109 
00110     if(use_octree) {
00111         // Insert an octree into which we'll store bounded objects.
00112         m_octree = new Octree(Matrix4::Identity());
00113         m_root->Insert(m_octree);
00114     } else m_octree = 0;
00115 
00116 //  m_progmon->Reset("     * Loading '" + GetFilename(filename) + "'");
00117 //  m_progmon->StartJob(0.0, 1.0);
00118     parse_file(filename, home_path);
00119 //  m_progmon->Done();
00120 
00121     if(!m_camera.get())
00122         throw LoadErrorException("No camera defined.");
00123 
00124     m_progmon->Reset("     * Finalizing");
00125     m_progmon->StartJob(0.0, 1.0);
00126 
00127     // Finalize objects of the scene.
00128     m_root->Finalize(context);
00129 
00130     // Finalize the camera.
00131     m_camera->Finalize(context, m_scene.get());
00132 
00133     m_progmon->Done();
00134 }
00135 
00136 SceneBuilder::~SceneBuilder() {}
00137 
00138 auto_ptr<Scene> SceneBuilder::GetScene() {
00139     return m_scene;
00140 }
00141 
00142 auto_ptr<ICamera> SceneBuilder::GetCamera() {
00143     return m_camera;
00144 }
00145 
00146 namespace {
00147     class DefaultErrorHandler : public ErrorHandler {
00148     public:
00149         virtual void warning(const SAXParseException &e) {
00150             throw SceneBuilder::LoadErrorException(StrX(e.getMessage()));
00151         }
00152 
00153         virtual void error(const SAXParseException &e) {
00154             throw SceneBuilder::LoadErrorException(StrX(e.getMessage()));
00155         }
00156 
00157         virtual void fatalError(const SAXParseException &e) {
00158             throw SceneBuilder::LoadErrorException(StrX(e.getMessage()));
00159         }
00160 
00161         virtual void resetErrors() {}
00162     };
00163 
00164     class Dictionary {
00165     public:
00166         void Insert(const string &s) {
00167             m_strings[s] = true;
00168         }
00169 
00170         bool Contains(const string &s) const {
00171             return m_strings.find(s) != m_strings.end();
00172         }
00173 
00174     private:
00175         map<string, bool> m_strings;
00176     };
00177 
00178     template<typename T>
00179     vector<T> parse_sequence(const string &s) {
00180         stringstream ss;
00181         vector<T> v;
00182         T x;
00183 
00184         ss << s;
00185 
00186         while(ss >> x)
00187             v.push_back(x);
00188 
00189         return v;
00190     }
00191 }
00192 
00193 Vector3 SceneBuilder::parse_vector3(const string &s) const {
00194     const vector<Real> u = parse_sequence<Real>(s);
00195     Vector3 v;
00196 
00197     switch(u.size()) {
00198     case 0:
00199         throw ParseErrorException("Invalid vector format.");
00200     case 1:
00201         v.m_x = v.m_y = v.m_z = u[0];
00202         break;
00203     case 3:
00204         v.m_x = u[0];
00205         v.m_y = u[1];
00206         v.m_z = u[2];
00207         break;
00208     default:
00209         throw ParseErrorException("Invalid vector format.");
00210     }
00211 
00212     return v;
00213 }
00214 
00215 Color3 SceneBuilder::parse_color3(const string &s) const {
00216     const vector<Real> v = parse_sequence<Real>(s);
00217     Color3 c;
00218 
00219     switch(v.size()) {
00220     case 0:
00221         throw ParseErrorException("Invalid color format.");
00222     case 1:
00223         c.m_r = c.m_g = c.m_b = v[0];
00224         break;
00225     case 3:
00226         c.m_r = v[0];
00227         c.m_g = v[1];
00228         c.m_b = v[2];
00229         break;
00230     default:
00231         throw ParseErrorException("Invalid color format.");
00232     }
00233 
00234     return c;
00235 }
00236 
00237 void SceneBuilder::parse_parameter(const DOMNode *node,
00238                                    string *name,
00239                                    string *value) const
00240 {
00241     assert(node);
00242     assert(name);
00243     assert(value);
00244 
00245     const DOMElement *element = static_cast<const DOMElement *>(node);
00246 
00247     *name = StrX(element->getAttribute(XStr("name")));
00248     *value = StrX(element->getAttribute(XStr("value")));
00249 }
00250 
00251 void SceneBuilder::store_parameter(const string &name,
00252                                    const string &value,
00253                                    ParameterMap *params) const
00254 {
00255     assert(params);
00256 
00257     try {
00258         params->Insert(name, value);
00259     }
00260     catch(const ParameterMap::DuplicateKeyException &e) {
00261         throw ParseErrorException("Duplicate parameter: '" + e.m_key + "'.");
00262     }
00263 }
00264 
00265 void SceneBuilder::parse_file(const string &filename, const string &home_path) {
00266     XercesManager::Initialize();
00267 
00268     // Create the XML DOM parser.
00269     XercesDOMParser *parser = new XercesDOMParser();
00270 
00271     // Configure the parser.
00272     parser->setValidationScheme(XercesDOMParser::Val_Always);
00273     parser->setDoNamespaces(true);
00274     parser->setDoSchema(true);
00275     parser->setValidationSchemaFullChecking(true);
00276     parser->setExternalNoNamespaceSchemaLocation((home_path + "schemas/toxicscene.xsd").c_str());
00277 
00278     // Install the error handler.
00279     ErrorHandler *error_handler = new DefaultErrorHandler();
00280     parser->setErrorHandler(error_handler);
00281 
00282     // Parse the XML file and create the DOM document.
00283     try {
00284         parser->parse(filename.c_str());
00285     }
00286     catch(const XMLException &e) {
00287         throw ParseErrorException(StrX(e.getMessage()));
00288     }
00289     catch(const DOMException &e) {
00290         throw ParseErrorException(StrX(e.msg));
00291     }
00292 
00293     // Traverse the document.
00294     parse_root(parser->getDocument()->getDocumentElement());
00295 
00296     // Clean up.
00297     delete error_handler;
00298     delete parser;
00299 
00300     XercesManager::Shutdown();
00301 }
00302 
00303 void SceneBuilder::parse_root(const DOMNode *node) {
00304     DOMNodeList *childs = node->getChildNodes();
00305 
00306     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00307         DOMNode *child = childs->item(i);
00308 
00309         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00310             continue;
00311 
00312         const string name = StrX(child->getNodeName());
00313 
00314         if(name == "SurfaceShader")
00315             surface_shader_builder(child);
00316         else if(name == "Frame")
00317             parse_frame(child);
00318     }
00319 }
00320 
00321 void SceneBuilder::parse_frame(const DOMNode *node) {
00322     ParameterMap params;
00323 
00324     DOMNodeList *childs = node->getChildNodes();
00325 
00326     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00327         DOMNode *child = childs->item(i);
00328 
00329         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00330             continue;
00331 
00332         const string name = StrX(child->getNodeName());
00333 
00334         if(name == "Parameter") {
00335             string name, value;
00336             parse_parameter(child, &name, &value);
00337             store_parameter(name, value, &params);  // just to detect duplicate parameters
00338 
00339             if(name == "ambientillum")
00340                 m_scene->SetAmbientIllumination(parse_color3(value));
00341             else if(name == "backgroundcolor")
00342                 m_scene->SetBackgroundColor(parse_color3(value));
00343         }
00344         else if(name == "Object")
00345             object_builder(child);
00346         else if(name == "SurfaceShader")
00347             surface_shader_builder(child);
00348     }
00349 }
00350 
00351 const IBDF *SceneBuilder::bdf_builder(const DOMNode *node) const {
00352     const DOMElement *element = static_cast<const DOMElement *>(node);
00353     const string type = StrX(element->getAttribute(XStr("type")));
00354 
00355     if(type == "lambertian")
00356         return new LambertianBRDF();
00357     else if(type == "perfectspecular")
00358         return new PerfectSpecularBRDF();
00359     else throw ParseErrorException("Invalid BDF type.");
00360 
00361     return 0;   // keep the compiler happy
00362 }
00363 
00364 const ConstantTexture *SceneBuilder::constant_texture_builder(const DOMNode *node) const {
00365     const DOMElement *element = static_cast<const DOMElement *>(node);
00366     const string value = StrX(element->getAttribute(XStr("value")));
00367 
00368     return new ConstantTexture(parse_color3(value));
00369 }
00370 
00371 const IEDF *SceneBuilder::edf_builder(const DOMNode *node) const {
00372     const DOMElement *element = static_cast<const DOMElement *>(node);
00373     const string type = StrX(element->getAttribute(XStr("type")));
00374 
00375     if(type == "none")
00376         return 0;
00377     else if(type == "lambertian")
00378         return new LambertianEDF();
00379     else throw ParseErrorException("Invalid EDF type.");
00380 
00381     return 0;   // keep the compiler happy
00382 }
00383 
00384 const ImageTexture *SceneBuilder::image_texture_builder(const DOMNode *node) const {
00385     const DOMElement *element = static_cast<const DOMElement *>(node);
00386     const string href = StrX(element->getAttribute(XStr("href")));
00387 
00388     const Map2 *map;
00389 
00390     try {
00391         map = new Map2(m_path + href);
00392     }
00393     catch(const Map2::FileNotFoundException &e) {
00394         throw ParseErrorException("Could not load image file '" + e.m_filename + "'.");
00395     }
00396 
00397     return new ImageTexture(map);
00398 }
00399 
00400 Matrix4 SceneBuilder::matrix_builder(const DOMNode *node) const {
00401     DOMNodeList *childs = node->getChildNodes();
00402 
00403     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00404         DOMNode *child = childs->item(i);
00405 
00406         if(child->getNodeType() != DOMNode::TEXT_NODE)
00407             continue;
00408 
00409         const vector<Real> v = parse_sequence<Real>(StrX(child->getTextContent()));
00410 
00411         if(v.size() != 16)  // 4x4 matrix -> 16 coefficients
00412             break;
00413 
00414         Matrix4 m;
00415 
00416         for(int j = 0; j < 16; ++j)
00417             m[j] = v[j];
00418 
00419         return m;
00420     }
00421 
00422     throw ParseErrorException("Invalid matrix format.");
00423 
00424     return Matrix4::Identity(); // keep the compiler happy
00425 }
00426 
00427 void SceneBuilder::object_builder(const DOMNode *node) {
00428     const DOMElement *element = static_cast<const DOMElement *>(node);
00429     const string object_type = StrX(element->getAttribute(XStr("type")));
00430     const string object_name = StrX(element->getAttribute(XStr("name")));
00431     const string object_base = StrX(element->getAttribute(XStr("base")));
00432 
00433     // Default values.
00434     Matrix4 transform(Matrix4::Identity());
00435     ParameterMap params;
00436 
00437     DOMNodeList *childs = node->getChildNodes();
00438     Dictionary dictionary;
00439 
00440     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00441         DOMNode *child = childs->item(i);
00442 
00443         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00444             continue;
00445 
00446         const string name = StrX(child->getNodeName());
00447 
00448         // Special handling of <Parameter> elements.
00449         if(name == "Parameter") {
00450             string name, value;
00451             parse_parameter(child, &name, &value);
00452             store_parameter(name, value, &params);
00453             continue;
00454         }
00455 
00456         if(dictionary.Contains(name))
00457             throw MultipleDefinitionException(name);
00458         else dictionary.Insert(name);
00459 
00460         if(name == "Transform")
00461             transform = transform_builder(child);
00462     }
00463 
00464     try {
00465         // Cameras.
00466         if(object_type == "pinholecamera") {
00467             if(m_camera.get())
00468                 throw ParseErrorException("Camera redefinition.");
00469             else m_camera.reset(pinholecamera_builder(transform, params));
00470         }
00471         else if(object_type == "thinlenscamera") {
00472             if(m_camera.get())
00473                 throw ParseErrorException("Camera redefinition.");
00474             else m_camera.reset(thinlenscamera_builder(transform, params));
00475         }
00476 
00477         // Lights.
00478         else if(object_type == "pointlight") {
00479             m_scene->InsertLight(pointlight_builder(transform, params));
00480         }
00481 
00482         // Objects.
00483         else {
00484             IObject::IntersectionMask intersection_mask;
00485 
00486             // Extract value of the "visible" parameter.
00487             if(params.GetOptionalValue<bool>("visible", true))
00488                 intersection_mask = IObject::INTERSECT_ALL_RAYS;
00489             else intersection_mask = IObject::INTERSECT_VISIBILITY_RAYS;
00490 
00491             // Unbounded objects.
00492             if(object_type == "plane") {
00493                 Plane *plane = plane_builder(
00494                     transform,
00495                     intersection_mask,
00496                     params
00497                 );
00498 
00499                 // Insert the object into object repository.
00500                 insert_into_repository(object_name, plane);
00501 
00502                 // Insert the object into the scene.
00503                 insert_into_scene(plane);
00504             }
00505 
00506             // Composite objects.
00507             else if(object_type == "mesh") {
00508                 const MeshBuilder::MeshVector meshes = mesh_builder(
00509                     transform,
00510                     intersection_mask,
00511                     params
00512                 );
00513 
00514                 if(meshes.size() > 0) {
00515                     // Insert all meshes into the scene.
00516                     for(MeshBuilder::MeshVector::const_iterator i = meshes.begin(),
00517                         e = meshes.end(); i != e; ++i)
00518                     {
00519                         Mesh *mesh = *i;
00520 
00521                         if(mesh->GetSurfaceShader() == 0) {
00522                             throw ParseErrorException("One or several meshes have no surface shader.");
00523                         }
00524 
00525                         // Insert mesh into the scene.
00526                         insert_into_scene(mesh);
00527                     }
00528 
00529                     const IObject *front_object = meshes.front();
00530 
00531                     // Insert the first mesh into object repository.
00532                     insert_into_repository(object_name, front_object);
00533 
00534                     // If meshes emit light, insert them into the scene's list of light.
00535                     if( front_object->GetSurfaceShader()->GetEDF() &&
00536                         !front_object->GetSurfaceShader()->GetRadiantExitance().IsBlack())
00537                     {
00538                         for(MeshBuilder::MeshVector::const_iterator i = meshes.begin(), e = meshes.end(); i != e; ++i) {
00539                             m_scene->InsertLight(*i);
00540                         }
00541                     }
00542                 }
00543             }
00544 
00545             // Bounded objects.
00546             else {
00547                 IAreaLight *object;
00548 
00549                 if(object_type == "cube")
00550                     object = cube_builder(
00551                         transform,
00552                         intersection_mask,
00553                         params
00554                     );
00555                 else if(object_type == "ring")
00556                     object = ring_builder(
00557                         transform,
00558                         intersection_mask,
00559                         params
00560                     );
00561                 else if(object_type == "sphere")
00562                     object = sphere_builder(
00563                         transform,
00564                         intersection_mask,
00565                         params
00566                     );
00567                 else if(object_type == "square")
00568                     object = square_builder(
00569                         transform,
00570                         intersection_mask,
00571                         params
00572                     );
00573                 else throw ParseErrorException("Invalid object type: '" + object_type + "'.");
00574 
00575                 // Insert the object into object repository.
00576                 insert_into_repository(object_name, object);
00577 
00578                 // Insert the object into the scene.
00579                 insert_into_scene(object);
00580 
00581                 // If the object emits light, insert it into scene light list.
00582                 if( object->GetSurfaceShader()->GetEDF() &&
00583                     !object->GetSurfaceShader()->GetRadiantExitance().IsBlack())
00584                 {
00585                     m_scene->InsertLight(object);
00586                 }
00587             }
00588         }
00589     }
00590     catch(const ParameterMap::InvalidKeyException &e) {
00591         throw ParseErrorException("Missing or invalid parameter: '" + e.m_key + "'.");
00592     }
00593     catch(const SurfaceShaderRepository::InvalidKeyException &e) {
00594         throw ParseErrorException("Surface shader does not exist: '" + e.m_key + "'.");
00595     }
00596     catch(const ObjectRepository::InvalidKeyException &e) {
00597         throw ParseErrorException("Object does not exist: '" + e.m_key + "'.");
00598     }
00599 }
00600 
00601 Color3 SceneBuilder::radiant_exitance_builder(const DOMNode *node) const {
00602     const DOMElement *element = static_cast<const DOMElement *>(node);
00603     const string value = StrX(element->getAttribute(XStr("value")));
00604 
00605     return parse_color3(value);
00606 }
00607 
00608 const ITexture *SceneBuilder::reflectance_builder(const DOMNode *node) const {
00609     DOMNodeList *childs = node->getChildNodes();
00610 
00611     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00612         DOMNode *child = childs->item(i);
00613 
00614         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00615             continue;
00616 
00617         const string name = StrX(child->getNodeName());
00618 
00619         if(name == "ConstantTexture")
00620             return constant_texture_builder(child);
00621         else if(name == "ImageTexture")
00622             return image_texture_builder(child);
00623     }
00624 
00625     return 0;   // keep the compiler happy
00626 }
00627 
00628 Matrix4 SceneBuilder::rotation_builder(const DOMNode *node) const {
00629     const DOMElement *element = static_cast<const DOMElement *>(node);
00630     const string angle = StrX(element->getAttribute(XStr("angle")));
00631     const string axis = StrX(element->getAttribute(XStr("axis")));
00632 
00633     return Matrix4::Rotation(Quaternion::Rotation(
00634         dtor(StringUtils::FromString<Real>(angle)),
00635         parse_vector3(axis)));
00636 }
00637 
00638 Matrix4 SceneBuilder::scale_builder(const DOMNode *node) const {
00639     const DOMElement *element = static_cast<const DOMElement *>(node);
00640     const string value = StrX(element->getAttribute(XStr("value")));
00641 
00642     return Matrix4::Scale(parse_vector3(value));
00643 }
00644 
00645 void SceneBuilder::surface_shader_builder(const DOMNode *node) {
00646     const DOMElement *element = static_cast<const DOMElement *>(node);
00647     const string shader_name = StrX(element->getAttribute(XStr("name")));
00648     const string shader_base = StrX(element->getAttribute(XStr("base")));
00649 
00650     assert(shader_name != "");
00651 
00652     const IEDF *edf;
00653     Color3 radiant_exitance;
00654     const IBDF *bdf;
00655     const ITexture *reflectance;
00656 
00657     if(shader_base == "") {
00658         // Use default values.
00659         edf = 0;
00660         radiant_exitance = Color3(0.0);
00661         bdf = new LambertianBRDF();
00662         reflectance = new ConstantTexture(Color3(0.5));
00663     } else {
00664         // Use base shader values.
00665         //!\todo Implement forward definition of objects and shaders.
00666         const BasicSurfaceShader *surface_shader;
00667         try {
00668             surface_shader = static_cast<const BasicSurfaceShader *>(m_surface_shaders.Find(shader_base));
00669         }
00670         catch(SurfaceShaderRepository::InvalidKeyException) {
00671             throw ParseErrorException("Undefined object: '" + shader_base + "'.");
00672         }
00673 
00674         edf = clone(surface_shader->GetEDF());
00675         radiant_exitance = surface_shader->GetRadiantExitance();
00676         bdf = clone(surface_shader->GetBDF());
00677         reflectance = clone(surface_shader->GetReflectance());
00678     }
00679 
00680     const DOMNodeList *childs = node->getChildNodes();
00681     Dictionary dictionary;
00682 
00683     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00684         const DOMNode *child = childs->item(i);
00685 
00686         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00687             continue;
00688 
00689         const string name = StrX(child->getNodeName());
00690 
00691         if(dictionary.Contains(name))
00692             throw MultipleDefinitionException(name);
00693         else dictionary.Insert(name);
00694 
00695         if(name == "EDF") {
00696             delete edf;
00697             edf = edf_builder(child);
00698         } else if(name == "RadiantExitance") {
00699             radiant_exitance = radiant_exitance_builder(child);
00700         } else if(name == "BDF") {
00701             delete bdf;
00702             bdf = bdf_builder(child);
00703         } else if(name == "Reflectance") {
00704             delete reflectance;
00705             reflectance = reflectance_builder(child);
00706         }
00707     }
00708 
00709     const ISurfaceShader *surface_shader = new BasicSurfaceShader(
00710         edf,
00711         radiant_exitance,
00712         bdf,
00713         reflectance);
00714 
00715     try {
00716         m_surface_shaders.Insert(shader_name, surface_shader);
00717     }
00718     catch(const SurfaceShaderRepository::DuplicateKeyException &e) {
00719         throw ParseErrorException("Duplicate surface shader name: '" + e.m_key + "'.");
00720     }
00721 }
00722 
00723 Matrix4 SceneBuilder::transform_builder(const DOMNode *node) const {
00724     Matrix4 transform = Matrix4::Identity();
00725 
00726     DOMNodeList *childs = node->getChildNodes();
00727 
00728     for(XMLSize_t i = 0; i < childs->getLength(); ++i) {
00729         DOMNode *child = childs->item(i);
00730 
00731         if(child->getNodeType() != DOMNode::ELEMENT_NODE)
00732             continue;
00733 
00734         const string name = StrX(child->getNodeName());
00735 
00736         if(name == "Matrix4")
00737             transform = matrix_builder(child) * transform;
00738         else if(name == "Scale")
00739             transform = scale_builder(child) * transform;
00740         else if(name == "Rotation")
00741             transform = rotation_builder(child) * transform;
00742         else if(name == "Translation")
00743             transform = translation_builder(child) * transform;
00744     }
00745 
00746     return transform;
00747 }
00748 
00749 Matrix4 SceneBuilder::translation_builder(const DOMNode *node) const {
00750     const DOMElement *element = static_cast<const DOMElement *>(node);
00751     const string value = StrX(element->getAttribute(XStr("value")));
00752 
00753     return Matrix4::Translation(parse_vector3(value));
00754 }
00755 
00756 void SceneBuilder::insert_into_repository(const string &key, const IObject *object) {
00757     // If the object is named, insert it into object repository.
00758     if(key != "") {
00759         try {
00760             m_objects.Insert(key, object);
00761         }
00762         catch(const ObjectRepository::DuplicateKeyException &e) {
00763             throw ParseErrorException("Duplicate object name: '" + e.m_key + "'.");
00764         }
00765     }
00766 }
00767 
00768 void SceneBuilder::insert_into_scene(IBoundedObject *object) {
00769     if(m_octree)
00770         m_octree->Insert(object);
00771     else m_root->Insert(object);
00772 }
00773 
00774 void SceneBuilder::insert_into_scene(Plane *plane) {
00775     m_root->Insert(plane);
00776 }
00777 
00778 PinholeCamera *SceneBuilder::pinholecamera_builder(const Matrix4 &transform,
00779                                                    const ParameterMap &params) const
00780 {
00781     const Real default_aspect_ratio =
00782         static_cast<Real>(m_framebuffer->GetWidth()) / m_framebuffer->GetHeight();
00783 
00784     return new PinholeCamera(
00785         transform,
00786         dtor(params.GetOptionalValue<Real>("hfov", DEFAULT_CAMERA_HFOV)),
00787         params.GetOptionalValue<Real>("aspectratio", default_aspect_ratio));
00788 }
00789 
00790 ThinLensCamera *SceneBuilder::thinlenscamera_builder(const Matrix4 &transform,
00791                                                      const ParameterMap &params) const
00792 {
00793     const Real default_aspect_ratio =
00794         static_cast<Real>(m_framebuffer->GetWidth()) / m_framebuffer->GetHeight();
00795 
00796     const Real hfov = dtor(params.GetOptionalValue<Real>("hfov", DEFAULT_CAMERA_HFOV));
00797     const Real aspect_ratio = params.GetOptionalValue<Real>("aspectratio", default_aspect_ratio);
00798     const Real fstop = params.GetValue<Real>("fstop");
00799     const Real focal_length = params.GetValue<Real>("focallength");
00800     Real focal_distance;
00801     bool af_enabled = false;
00802     Point2 af_target;
00803 
00804     try {
00805         // Try to get back the autofocus target point.
00806         const vector<Real> v = parse_sequence<Real>(params.GetValue<string>("autofocus"));
00807 
00808         if(v.size() != 2)
00809             throw ParseErrorException("Invalid NDC point format.");
00810 
00811         af_enabled = true;
00812         af_target.m_x = v[0];
00813         af_target.m_y = v[1];
00814     }
00815     catch(ParameterMap::InvalidKeyException) {
00816         // No autofocus target: autofocus is disabled.
00817 
00818         // Try to get back the focal distance.
00819         try {
00820             focal_distance = params.GetValue<Real>("focaldistance");
00821         }
00822         catch(ParameterMap::InvalidKeyException) {
00823             throw ParseErrorException("Either 'autofocus' or 'focaldistance' parameters must be specified.");
00824         }
00825     }
00826 
00827     if(af_enabled) {
00828         return new ThinLensCamera(
00829             transform,
00830             hfov,
00831             aspect_ratio,
00832             fstop,
00833             focal_length,
00834             af_target);
00835     } else {
00836         return new ThinLensCamera(
00837             transform,
00838             hfov,
00839             aspect_ratio,
00840             fstop,
00841             focal_length,
00842             focal_distance);
00843     }
00844 }
00845 
00846 PointLight *SceneBuilder::pointlight_builder(const Matrix4 &transform,
00847                                              const ParameterMap &params) const
00848 {
00849     return new PointLight(
00850         transform,
00851         parse_color3(params.GetValue<string>("power")),
00852         params.GetOptionalValue<bool>("castshadow", true));
00853 }
00854 
00855 Cube *SceneBuilder::cube_builder(const Matrix4 &transform,
00856                                  IObject::IntersectionMask intersection_mask,
00857                                  const ParameterMap &params) const
00858 {
00859     return new Cube(
00860         transform,
00861         m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
00862         intersection_mask);
00863 }
00864 
00865 MeshBuilder::MeshVector SceneBuilder::mesh_builder(const Matrix4 &transform,
00866                                                    IObject::IntersectionMask intersection_mask,
00867                                                    const ParameterMap &params) const
00868 {
00869     const string filename = m_path + params.GetValue<string>("href");
00870 
00871     m_progmon->Reset("     * Loading '" + StringUtils::GetFilename(filename) + "'");
00872 
00873     const ISurfaceShader *surface_shader;
00874     try {
00875         const string surface_shader_name = params.GetValue<string>("surfaceshader");
00876         surface_shader = m_surface_shaders.Find(surface_shader_name);
00877     }
00878     catch(ParameterMap::InvalidKeyException) {
00879         surface_shader = 0;
00880     }
00881 
00882     MeshBuilder builder(transform, surface_shader, intersection_mask);
00883 
00884     const bool rebuild_normals = params.GetOptionalValue<bool>("rebuildnormals", false);
00885     const bool optimize_mesh = params.GetOptionalValue<bool>("optimizemesh", false);
00886 
00887     MeshModifier *mesh_modifier = 0;
00888 
00889     if(rebuild_normals || optimize_mesh)
00890         mesh_modifier = new MeshModifier(builder);
00891 
00892     if(rebuild_normals) {
00893         // Get back normal vertex normals smoothing settings.
00894         try {
00895             mesh_modifier->ComputeSmoothedVertexNormals(
00896                 dtor(params.GetValue<Real>("smoothingthresholdangle")));
00897         }
00898         catch(ParameterMap::InvalidKeyException) {
00899             throw ParseErrorException(
00900                 "'smoothingthresholdangle' parameter must be specified in order to enable "
00901                 "computation of smoothed vertex normals."
00902             );
00903         }
00904     }
00905 
00906     if(optimize_mesh) {
00907         // Get back mesh optimization settings.
00908         try {
00909             mesh_modifier->OptimizeMesh(
00910                 params.GetValue<Real>("vertexweldingthreshold"),
00911                 dtor(params.GetValue<Real>("normalweldingthreshold"))
00912             );
00913         }
00914         catch(ParameterMap::InvalidKeyException) {
00915             throw ParseErrorException(
00916                 "'vertexweldingthreshold' and 'normalweldingthreshold' parameters must be specified "
00917                 "in order to enable mesh optimization."
00918             );
00919         }
00920     }
00921 
00922 //  const int option_mask = IMeshLoader::DEFAULT_CONFIGURATION_BIT;
00923     const int option_mask = IMeshLoader::STOP_ON_MISSING_FILE_BIT;
00924 
00925     try {
00926         if(mesh_modifier)
00927             SmartLoader().Load(filename, *mesh_modifier, option_mask, m_progmon);
00928         else SmartLoader().Load(filename, builder, option_mask, m_progmon);
00929     }
00930 
00931     // Catch exceptions thrown by ASELoader class.
00932     catch(const ASELoader::ParsingException &e) {
00933         throw ParseErrorException("Parse error on line " + StringUtils::ToString(e.m_line) + ".");
00934     }
00935     catch(const ASELoader::ExtendedLoadingException &e) {
00936         throw ParseErrorException("Unknown load error on line " + StringUtils::ToString(e.m_line) + ".");
00937     }
00938 
00939     // Catch exceptions thrown by OBJLoader class.
00940     catch(const OBJLoader::ParsingException &e) {
00941         throw ParseErrorException("Parse error on line " + StringUtils::ToString(e.m_line) + ".");
00942     }
00943     catch(const OBJLoader::InvalidFaceException &e) {
00944         throw ParseErrorException("Invalid face on line " + StringUtils::ToString(e.m_line) + ".");
00945     }
00946     catch(const OBJLoader::TriangulationException &e) {
00947         throw ParseErrorException("Triangulation error on line " + StringUtils::ToString(e.m_line) + ".");
00948     }
00949     catch(const OBJLoader::ExtendedLoadingException &e) {
00950         throw ParseErrorException("Unknown load error on line " + StringUtils::ToString(e.m_line) + ".");
00951     }
00952 
00953     // Catch exceptions thrown by SmartLoader class.
00954     catch(SmartLoader::UnknownFileFormatException) {
00955         throw ParseErrorException("This file format is not supported.");
00956     }
00957 
00958     // Catch exceptions thrown by TRILoader class.
00959     catch(const TRILoader::ReadingException &e) {
00960         throw ParseErrorException("Read error at offset " + StringUtils::ToString(e.m_offset) + ".");
00961     }
00962     catch(const TRILoader::ExtendedLoadingException &e) {
00963         throw ParseErrorException("Unknown load error at offset " + StringUtils::ToString(e.m_offset) + ".");
00964     }
00965 
00966     // Catch common exceptions.
00967     catch(const IMeshLoader::FileNotFoundException &e) {
00968         throw ParseErrorException("File '" + e.m_filename + "' not found.");
00969     }
00970     catch(IMeshLoader::LoadingException) {
00971         throw ParseErrorException("Unknown load error.");
00972     }
00973     catch(...) {
00974         throw ParseErrorException("Unknown error.");
00975     }
00976 
00977     delete mesh_modifier;
00978 
00979     MeshBuilder::MeshVector meshes = builder.GetMeshes();
00980 
00981     //!\todo Print the number of meshes added to the scene.
00982 
00983     bool include = true, exclude = true;
00984     string param_value;
00985 
00986     try {
00987         param_value = params.GetValue<string>("include");
00988     }
00989     catch(ParameterMap::InvalidKeyException) {
00990         include = false;
00991     }
00992 
00993     try {
00994         param_value = params.GetValue<string>("exclude");
00995     }
00996     catch(ParameterMap::InvalidKeyException) {
00997         exclude = false;
00998     }
00999 
01000     if(!include && !exclude)
01001         return meshes;
01002 
01003     if(include && exclude)
01004         throw ParseErrorException("'include' and 'exclude' parameters are mutually exclusive.");
01005 
01006     const string param_name = include ? "include" : "exclude";
01007 
01008     // Convert the parameter value (which is a string) to a vector of int.
01009     vector<int> indices = parse_sequence<int>(param_value);
01010 
01011     if(indices.size() == 0) {
01012         if(include)
01013             return MeshBuilder::MeshVector();
01014         else return meshes;
01015     }
01016 
01017     // Sort the vector and remove duplicate indices.
01018     sort(indices.begin(), indices.end());
01019     const vector<int>::iterator new_indices_end =
01020         unique(indices.begin(), indices.end());
01021 
01022     // Make sure all indices are valid.
01023     const int index_vec[2] = { *indices.begin(), *(new_indices_end - 1) };
01024     for(int i = 0; i < 2; ++i) {
01025         const int index = index_vec[i];
01026         if(index < 0 || index >= meshes.size()) {
01027             throw ParseErrorException("Invalid index in '" + param_name + "' parameter: " +
01028                 StringUtils::ToString(index));
01029         }
01030     }
01031 
01032     MeshBuilder::MeshVector selected_meshes;
01033 
01034     if(include) {
01035         for(vector<int>::const_iterator i = indices.begin(), e = new_indices_end; i != e; ++i)
01036             selected_meshes.push_back(meshes[*i]);
01037     } else {
01038         for(int i = 0; i < meshes.size(); ++i) {
01039             if(!binary_search(indices.begin(), new_indices_end, i))
01040                 selected_meshes.push_back(meshes[i]);
01041         }
01042     }
01043 
01044     return selected_meshes;
01045 }
01046 
01047 Plane *SceneBuilder::plane_builder(const Matrix4 &transform,
01048                                    IObject::IntersectionMask intersection_mask,
01049                                    const ParameterMap &params) const
01050 {
01051     return new Plane(
01052         transform,
01053         m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
01054         intersection_mask);
01055 }
01056 
01057 Ring *SceneBuilder::ring_builder(const Matrix4 &transform,
01058                                  IObject::IntersectionMask intersection_mask,
01059                                  const ParameterMap &params) const
01060 {
01061     return new Ring(
01062         transform,
01063         m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
01064         params.GetValue<Real>("innerradius"),
01065         intersection_mask);
01066 }
01067 
01068 Sphere *SceneBuilder::sphere_builder(const Matrix4 &transform,
01069                                      IObject::IntersectionMask intersection_mask,
01070                                      const ParameterMap &params) const
01071 {
01072     return new Sphere(
01073         transform,
01074         m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
01075         intersection_mask);
01076 }
01077 
01078 Square *SceneBuilder::square_builder(const Matrix4 &transform,
01079                                      IObject::IntersectionMask intersection_mask,
01080                                      const ParameterMap &params) const
01081 {
01082     return new Square(
01083         transform,
01084         m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
01085         intersection_mask);
01086 }

Generated on Tue May 11 01:31:52 2004 for toxic by doxygen 1.3.6