00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "scenebuilder.h"
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
00054 #include "renderer/pinholecamera.h"
00055 #include "renderer/thinlenscamera.h"
00056
00057
00058 #include "renderer/pointlight.h"
00059
00060
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
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
00101
00102
00103 m_root = new Collection(Matrix4::Identity());
00104 m_scene->SetRootObject(m_root);
00105
00106
00107
00108 bool use_octree = true;
00109
00110 if(use_octree) {
00111
00112 m_octree = new Octree(Matrix4::Identity());
00113 m_root->Insert(m_octree);
00114 } else m_octree = 0;
00115
00116
00117
00118 parse_file(filename, home_path);
00119
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
00128 m_root->Finalize(context);
00129
00130
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
00269 XercesDOMParser *parser = new XercesDOMParser();
00270
00271
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
00279 ErrorHandler *error_handler = new DefaultErrorHandler();
00280 parser->setErrorHandler(error_handler);
00281
00282
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
00294 parse_root(parser->getDocument()->getDocumentElement());
00295
00296
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, ¶ms);
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;
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;
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)
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();
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
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
00449 if(name == "Parameter") {
00450 string name, value;
00451 parse_parameter(child, &name, &value);
00452 store_parameter(name, value, ¶ms);
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
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
00478 else if(object_type == "pointlight") {
00479 m_scene->InsertLight(pointlight_builder(transform, params));
00480 }
00481
00482
00483 else {
00484 IObject::IntersectionMask intersection_mask;
00485
00486
00487 if(params.GetOptionalValue<bool>("visible", true))
00488 intersection_mask = IObject::INTERSECT_ALL_RAYS;
00489 else intersection_mask = IObject::INTERSECT_VISIBILITY_RAYS;
00490
00491
00492 if(object_type == "plane") {
00493 Plane *plane = plane_builder(
00494 transform,
00495 intersection_mask,
00496 params
00497 );
00498
00499
00500 insert_into_repository(object_name, plane);
00501
00502
00503 insert_into_scene(plane);
00504 }
00505
00506
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
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
00526 insert_into_scene(mesh);
00527 }
00528
00529 const IObject *front_object = meshes.front();
00530
00531
00532 insert_into_repository(object_name, front_object);
00533
00534
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
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
00576 insert_into_repository(object_name, object);
00577
00578
00579 insert_into_scene(object);
00580
00581
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;
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
00659 edf = 0;
00660 radiant_exitance = Color3(0.0);
00661 bdf = new LambertianBRDF();
00662 reflectance = new ConstantTexture(Color3(0.5));
00663 } else {
00664
00665
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
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 ¶ms) 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 ¶ms) 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
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
00817
00818
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 ¶ms) 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 ¶ms) 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 ¶ms) 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
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
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
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
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
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
00954 catch(SmartLoader::UnknownFileFormatException) {
00955 throw ParseErrorException("This file format is not supported.");
00956 }
00957
00958
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
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
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
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
01018 sort(indices.begin(), indices.end());
01019 const vector<int>::iterator new_indices_end =
01020 unique(indices.begin(), indices.end());
01021
01022
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 ¶ms) 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 ¶ms) 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 ¶ms) 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 ¶ms) const
01081 {
01082 return new Square(
01083 transform,
01084 m_surface_shaders.Find(params.GetValue<string>("surfaceshader")),
01085 intersection_mask);
01086 }