MiltonJSONSceneLoader.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   MiltonJSONSceneLoader.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Matthew Jacobs (jacobs.mh@gmail.com)
00005    @date   Fall 2008
00006    
00007    @brief
00008       Scene loader for Milton JSON scene format
00009    <!-------------------------------------------------------------------->**/
00010 
00011 #include "MiltonJSONSceneLoader.h"
00012 #include <milton.h>
00013 
00014 #include <QtCore>
00015 #include <boost/any.hpp>
00016 #include <iostream>
00017 #include <fstream>
00018 #include <sstream>
00019 
00020 
00021 #define PARSE_ERROR(errorStr)                                \
00022    do {                                                      \
00023       std::stringstream s_;                                  \
00024       s_ << std::string(__func__) << " (" << __LINE__ <<     \
00025          "): " << std::string((errorStr));                   \
00026       data.error = s_.str();                                 \
00027       return false;                                          \
00028    } while(0)
00029 
00030 #define PARSE_TYPE_ERROR(obj, typeStr, v)                    \
00031    PARSE_ERROR((((std::string(obj) + " must be of type '") + \
00032                 std::string(typeStr) + "', found '") +       \
00033                 std::string((v)->type().name()) + "'"))
00034 
00035 #define PARSE_CHECK_TYPE_ERROR(obj, typeStr, type_, v) \
00036       do {                                             \
00037          if ((v)->type() != typeid(type_))           \
00038             PARSE_TYPE_ERROR(obj, typeStr, v);         \
00039       } while(0)
00040 
00041 #define PARSE_ADD_MAP(map, str, val)                                       \
00042    do {                                                                    \
00043       if ((map).contains((str)))                                           \
00044          PARSE_ERROR("duplicate key '" + std::string((str)) + "' found");  \
00045       (map)[(str)] = (val);                                                \
00046    } while(0)
00047 
00048 #define PARSE_ADD_MAP_OPTIONAL(map, str, val)                              \
00049    do {                                                                    \
00050       if (!(map).contains((str)))                                          \
00051          (map)[(str)] = (val);                                             \
00052    } while(0)
00053 
00054 
00055 bool JSONVisitor::visit(const MiltonJSONSceneLoader *loader, 
00056                         const JSONVariant &v, 
00057                         JSONParseData &data)
00058 {
00059    const std::string &type = (v->empty() ? "void" : v->type().name());
00060    FunctionMapIter iter = functionMap.find(type);
00061    ParseFunction visitor;
00062    
00063    if ((iter == functionMap.end()) || 
00064        (NULL == (visitor = iter->second.function)))
00065       return false;
00066    
00067    return ((loader->*(visitor)) (v, data));
00068 }
00069 
00070 bool JSONVisitor::visit(const MiltonJSONSceneLoader *loader, 
00071                         JSONObject const &obj, JSONParseData &data, 
00072                         ParseResultsMap *results, bool allowRepeats, 
00073                         bool atLeastOne, bool strict)
00074 {
00075    unsigned iterations = 0;
00076    
00077    FOREACH(JSONObjectConstIter, obj, iter) {
00078       const std::string &first    = iter->first;
00079       const JSONVariant &second   = iter->second;
00080       FunctionMapConstIter iter2  = functionMap.find(first);
00081       const JSONVisitorValue &val = iter2->second;
00082       const ParseFunction &func   = val.function;
00083       
00084       if (iter2 == functionMap.end()) {
00085          if (!strict)
00086             continue;
00087          
00088          PARSE_ERROR("encountered unknown key '" + first + "'");
00089       }
00090       
00091       if (NULL == func)
00092          continue; // disregard
00093       
00094       data << "<" << first << ">" << endl;
00095       if (!(loader->*func) (second, data))
00096          return false;
00097       
00098       // optionally record results
00099       // (number of times each key was successfully parsed)
00100       if (results && ++((*results)[first]) > 1 && !allowRepeats)
00101          PARSE_ERROR("found multiple definitions of key '" + first + "'");
00102       
00103       ++iterations;
00104    }
00105    
00106    if (results) {
00107       FOREACH(ParseResultsMapConstIter, *results, iter) {
00108          const std::string &key = iter->first;
00109          unsigned noOccurrences = iter->second;
00110          
00111          if (noOccurrences <= 0 && functionMap[key].required)
00112             PARSE_ERROR("missing required key '" + key + "'");
00113       }
00114    }
00115    
00116    return (!atLeastOne || iterations > 0);
00117 }
00118 
00119 bool MiltonJSONSceneLoader::parse(const std::string &fileName, 
00120                                   ParseData &outData)
00121 {
00122    outData.reset();
00123    outData.source = fileName;
00124    
00125    outData << "parsing file '" << fileName << "'" << endl;
00126    std::ifstream inputStream(fileName.c_str());
00127    
00128    if (!inputStream) {
00129       outData.error = "unable to find/read file '" + fileName + "'";
00130       return false;
00131    }
00132    
00133    // TODO: optimize this sheise
00134    std::string file;
00135    char buf[256];
00136    
00137    while(!inputStream.getline(buf, 255).eof())
00138       file += buf;
00139    
00140    bool retVal = _parse(file, outData);
00141    
00142    if (retVal)
00143       outData << "done parsing file '" << fileName << "'" << endl;
00144    else 
00145       outData << "error parsing file '" << fileName << "'" << endl;
00146    
00147    return retVal;
00148 }
00149 
00150 bool MiltonJSONSceneLoader::_parse(const std::string &input, 
00151                                    ParseData &outData) const
00152 {
00153    const JSONVariant &root = json::parse(input.begin(), input.end());
00154     
00155    if (root->type() != typeid(JSONObject)) {
00156       outData.error = "error parsing file (ill-formed JSON)";
00157       return false;
00158    }
00159    
00160    JSONParseData data(outData);
00161    bool retVal = false;
00162    
00163    try {
00164       retVal = _parse_root(root, data);
00165    } catch(boost::bad_any_cast &e) {
00166       //data << "caught exception during parsing: " << std::string(e.what()) << endl;
00167       data.error = std::string("internal error: ") + std::string(e.what());
00168    }
00169    
00170    outData = data;
00171    return retVal;
00172 }
00173 
00174 bool MiltonJSONSceneLoader::_parse_root(const JSONVariant &v, 
00175                                         JSONParseData &data) const
00176 {
00177    PARSE_CHECK_TYPE_ERROR("root", "object", JSONObject, v);
00178    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00179    
00180    ParseResultsMap results;
00181    JSONVisitor     visitor;
00182    
00183    data.reset();
00184    visitor["scenefile"] = 
00185       JSONVisitorValue(&MiltonJSONSceneLoader::_parse_scenefile, true);
00186    
00187    if (!visitor.visit(this, obj, data, &results))
00188       return false;
00189    
00190    return true;
00191 }
00192 
00193 bool MiltonJSONSceneLoader::_parse_scenefile(const JSONVariant &v, 
00194                                              JSONParseData &data) const
00195 {
00196    PARSE_CHECK_TYPE_ERROR("scenefile", "object", JSONObject, v);
00197    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00198    
00199    ParseResultsMap results;
00200    JSONVisitor     visitor;
00201    visitor["renderer"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_renderer);
00202    visitor["camera"]   = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_camera);
00203    visitor["output"]   = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_output);
00204    visitor["scene"]    = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_scene, true);
00205    visitor["version"]  = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_version);
00206    
00207    if (!visitor.visit(this, obj, data, &results))
00208       return false;
00209 
00210    return _finalizeData(data);
00211 }
00212    
00213 // initialize defaults for the camera, output, and renderer if they weren't 
00214 // specified and ensure all references are in place between them
00215 bool MiltonJSONSceneLoader::_finalizeData(JSONParseData &data) const {
00216    // traverse, flatten, and verify integrity of scenegraph
00217    if (!data.sceneGraph.flatten(data))
00218       return false;
00219    
00220    if (ResourceManager::getValue<bool>("forcePreview", false))
00221       safeDelete(data.renderer);
00222    
00223    // initialize default renderer if none was specified
00224    if (NULL == data.renderer) {
00225       if (ResourceManager::getValue<bool>("enableGui", true)) {
00226          ResourceManager::log.info << "defaulting to OpenGLRenderer" << endl;
00227          data.renderer = new OpenGLRenderer();
00228       } else {
00229          ResourceManager::log.info << "defaulting to RayCaster" << endl;
00230          data.renderer = new RayCaster();
00231          (*data.renderer)["ambient"] = SpectralRadianceSet::fill(0.1);
00232       }
00233    }
00234    
00235    // initialize output dimensions
00236    unsigned width = 480, height = 480;
00237    bool found = false;
00238    PropertyMap &outputProperties = data.outputProperties;
00239    
00240    if (data.output) {
00241       const Viewport &v = data.output->getViewport();
00242       
00243       width  = v.getWidth();
00244       height = v.getHeight();
00245       found  = true;
00246       
00247       outputProperties = *data.output;
00248    }
00249    
00250    if (data.outputProperties.contains("size")) {
00251       const Vector<2, unsigned> &size = 
00252          data.outputProperties.getValue<Vector<2, unsigned> >("size");
00253       
00254       bool oldWidth = width, oldHeight = height;
00255       width  = size[0];
00256       height = size[1];
00257       
00258       if (found && (oldWidth != width || oldHeight != height))
00259          PARSE_ERROR("conflicting declarations of output size");
00260       
00261       found  = true;
00262    }
00263    
00264    if (data.outputProperties.contains("dimensions")) {
00265       const Vector<2, unsigned> &size = 
00266          data.outputProperties.getValue<Vector<2, unsigned> >("dimensions");
00267       
00268       bool oldWidth = width, oldHeight = height;
00269       width  = size[0];
00270       height = size[1];
00271       
00272       if (found && (oldWidth != width || oldHeight != height))
00273          PARSE_ERROR("conflicting declarations of output.size and output.dimensions");
00274       
00275       found  = true;
00276    }
00277    
00278    if (data.outputProperties.contains("width")) {
00279       bool old = width;
00280       width = data.outputProperties.getValue<unsigned>("width");
00281       
00282       if (found && old != width)
00283          PARSE_ERROR("conflicting definitions for output width");
00284    }
00285    
00286    if (data.outputProperties.contains("height")) {
00287       bool old = height;
00288       height = data.outputProperties.getValue<unsigned>("height");
00289       
00290       if (found && old != width)
00291          PARSE_ERROR("conflicting definitions for output height");
00292    }
00293    
00294    data.outputProperties["width"]  = width;
00295    data.outputProperties["height"] = height;
00296    
00297    // ensure camera is valid
00298    if (NULL == data.camera)
00299       data.camera = new PinholeCamera();
00300    
00301    PointSampleRenderer *r = NULL;
00302    try {
00303       r = dynamic_cast<PointSampleRenderer*>(data.renderer);
00304    } catch(std::bad_cast&) { }
00305    
00306    // if we have PointSampleRenderer, initialize its RenderOutput field
00307    if (r)
00308       r->setOutput(data.output);
00309    
00310    Scene *scene = new Scene(data.materials, data.primitives);
00311    scene->setBackground(data.background ? 
00312                         data.background->getEmitter() : 
00313                         NULL);
00314    
00315    data.renderer->setScene (scene);
00316    data.renderer->setCamera(data.camera);
00317    
00318    // initialize camera (may be reinitialized later, but it's not a big deal)
00319    data.camera->init(scene);
00320    
00321    return true;
00322 }
00323 
00324 bool MiltonJSONSceneLoader::_parse_scene(const JSONVariant &v, 
00325                                          JSONParseData &data) const
00326 {
00327    PARSE_CHECK_TYPE_ERROR("scene", "object", JSONObject, v);
00328    
00329    return _parse_shapeSet(v, data);
00330    /*JSONVisitor visitor;
00331    _add_node(visitor);
00332    
00333    // push root scene node
00334    data.sceneGraph.beginNode(new SceneNodeShape(new ShapeSet(true)));
00335    
00336    // recur and visit children
00337    if (!visitor.visit(this, obj, data))
00338       return false;
00339    
00340    return true;*/
00341 }
00342 
00343 bool MiltonJSONSceneLoader::_parse_material(const JSONVariant &v, 
00344                                             JSONParseData &data) const
00345 {
00346    // handle null materials
00347    if (v->empty()) {
00348       data.sceneGraph.beginNode(new SceneNodeMaterial(new Material()));
00349       data << "null" << endl;
00350       data.sceneGraph.endNode();
00351       return true;
00352    }
00353    
00354    PARSE_CHECK_TYPE_ERROR("material", "object", JSONObject, v);
00355    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00356    
00357    JSONVisitor visitor;
00358    _add_node(visitor);
00359    
00360    visitor["bsdf"]    = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_bsdf);
00361    visitor["emitter"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_emitter);
00362    visitor["medium"]  = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_medium);
00363    
00364    Material *material = new Material();
00365    
00366    KeyValueIDMap req;
00367    
00368    req["bumpMap"]       = "string";
00369    req["bumpIntensity"] = "real_t";
00370    req["filter"]        = "string";
00371    req["repeatU"]       = "real_t";
00372    req["repeatV"]       = "real_t";
00373    
00374    // parse required and optional parameters
00375    if (!_parse_properties(req, obj, *material, data))
00376       return false;
00377    
00378    data.sceneGraph.beginNode(new SceneNodeMaterial(material));
00379    
00380    if (!visitor.visit(this, obj, data, NULL, false, false, false))
00381       return false;
00382    
00383    material->init();
00384    
00385    data.sceneGraph.endNode();
00386    return true;
00387 }
00388 
00389 bool MiltonJSONSceneLoader::_parse_transform(const JSONVariant &v, 
00390                                              JSONParseData &data) const
00391 {
00392    PARSE_CHECK_TYPE_ERROR("transform", "object", JSONObject, v);
00393    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00394    
00395    JSONVisitor visitor;
00396    _add_node(visitor);
00397    
00398    visitor["arbitraryTransform"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_arbitraryTransform);
00399    visitor["translate"]          = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_translate);
00400    visitor["rotate"]             = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_rotate);
00401    visitor["scale"]              = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_scale);
00402    
00403    data.sceneGraph.beginNode(new SceneNodeTransform());
00404    
00405    if (!visitor.visit(this, obj, data))
00406       return false;
00407    
00408    data.sceneGraph.endNode();
00409    return true;
00410 }
00411 
00412 bool MiltonJSONSceneLoader::_parse_shape(const JSONVariant &v, 
00413                                          JSONParseData &data) const
00414 {
00415    PARSE_CHECK_TYPE_ERROR("shape", "object", JSONObject, v);
00416    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00417    JSONObjectConstIter instanceIter = obj.find("instance");
00418    JSONObjectConstIter typeIter     = obj.find("type");
00419    std::string type = "";
00420    
00421    SceneNode *node = NULL;
00422    PropertyMap properties;
00423    KeyValueIDMap req;
00424    req["name"] = "string";
00425    
00426    if (instanceIter != obj.end()) {
00427       PARSE_CHECK_TYPE_ERROR("shape.instance", "string", 
00428                              JSONString, instanceIter->second);
00429       const std::string &instancee = 
00430          boost::any_cast<JSONString>(*(instanceIter->second));
00431       data << "instance '" << instancee << "'" << endl;
00432       type = "instance";
00433       
00434       if (!_parse_properties(req, obj, properties, data))
00435          return false;
00436       
00437       node = new SceneNodeInstance(instancee, SCENE_NODE_SHAPE);
00438    } else {
00439       if (typeIter == obj.end())
00440          PARSE_ERROR("unable to infer shape type");
00441       
00442       PARSE_CHECK_TYPE_ERROR("shape.type", "string", 
00443                              JSONString, typeIter->second);
00444       type = boost::any_cast<JSONString>(*(typeIter->second));
00445       data << type << endl;
00446       
00447       Shape *shape = NULL;
00448       
00449       if (type == "plane") {
00450          req["vertices"] = "vector12";
00451       } else if (type == "point") {
00452          shape = new PointShape();
00453       } else if (type == "cube") {
00454          shape = new Cube();
00455       } else if (type == "cone") {
00456          shape = new Cone();
00457       } else if (type == "mesh") {
00458          req["path"] = "string";
00459       } else if (type == "cylinder") {
00460          shape = new Cylinder();
00461       } else if (type == "sphere") {
00462          shape = new Sphere();
00463          
00464          req["position"] = "point3";
00465          req["radius"]   = "real_t";
00466       } else if (type == "triangle") {
00467          req["vertices"] = "vector9";
00468          req["normals"]  = "vector9"; // per vertex normals
00469          req["normal"]   = "vector3"; // constant over face of triangle
00470          req["uvs"]      = "vector6";
00471       } else if (type == "blob") {
00472          return _parse_blob(v, data);
00473       } else if (type == "shapeSet") {
00474          return _parse_shapeSet(v, data);
00475       } else if (type == "dynamic") {
00476          if (!(shape = _parse_dynamic_plugin<Shape, MILTON_PLUGIN_TYPE_SHAPE>(obj, data)))
00477             PARSE_ERROR("dynamic shape plugin: " + data.error);
00478       } else {
00479          PARSE_ERROR("invalid shape type");
00480       }
00481       
00482       // valid variant found; now parse required and optional parameters
00483       if (!_parse_properties(req, obj, properties, data))
00484          return false;
00485       
00486       if (type == "mesh") {
00487          if (!properties.contains("path"))
00488             PARSE_ERROR("missing required key 'path' in 'mesh' (path to mesh data file)");
00489          
00490          const std::string &path = properties.getValue<const std::string>("path");
00491          data << "loading mesh '" << path << "'" << endl;
00492          Mesh *mesh;
00493          
00494          if (NULL == (mesh = MeshLoader::load(path)))
00495             PARSE_ERROR(std::string("mesh '") + path + std::string("' failed to load"));
00496          
00497          mesh->inherit(properties);
00498          shape = mesh;
00499       } else if (type == "triangle") {
00500          // defaults
00501          real_t vertices[9] = {
00502             0, 0, 0,   // A
00503             0, 0, 0.5, // B
00504             0.5, 0, 0, // C
00505          };
00506          
00507          real_t normals[9] = {
00508             0, 1, 0, 
00509             0, 1, 0, 
00510             0, 1, 0, 
00511          };
00512          
00513          real_t uvs[6] = {
00514             0, 0, 
00515             1, 0, 
00516             0, 1, 
00517          };
00518          
00519          if (properties.contains("vertices")) {
00520             real_t *d = properties.getValue<real_t*>("vertices");
00521             memcpy(vertices, d, sizeof(real_t) * 9);
00522             safeDeleteArray(d);
00523          }
00524          
00525          if (properties.contains("normals")) {
00526             real_t *d = properties.getValue<real_t*>("normals");
00527             memcpy(normals, d, sizeof(real_t) * 9);
00528             safeDeleteArray(d);
00529          }
00530          
00531          if (properties.contains("uvs")) {
00532             real_t *d = properties.getValue<real_t*>("uvs");
00533             memcpy(uvs, d, sizeof(real_t) * 6);
00534             safeDeleteArray(d);
00535          }
00536          
00537          if (properties.contains("normal")) {
00538             const Vector3 &normal = properties.getValue<Vector3>("normal");
00539             for(unsigned i = 3; i--;)
00540                memcpy(normals + i * 3, normal.data, sizeof(Vector3));
00541          }
00542          
00543          Triangle *triangle = new Triangle(
00544             Vertex(vertices), Vertex(vertices + 3), Vertex(vertices + 6), 
00545             Normal(vertices), Normal(normals  + 3), Normal(normals  + 6), 
00546             UV(uvs[0], uvs[1]), UV(uvs[2], uvs[3]), UV(uvs[4], uvs[5]));
00547          
00548          shape = triangle;
00549       } else if (type == "sphere") {
00550          Matrix4x4 trans = Matrix4x4::identity();
00551          
00552          if (properties.contains("position")) {
00553             const Point3 &position = properties.getValue<Point3>("position");
00554             
00555             trans *= getTransMat(Vector3(position.data));
00556          }
00557          
00558          if (properties.contains("radius")) {
00559             const real_t radius = properties.getValue<real_t>("radius") * 2.0;
00560             
00561             trans *= getScaleMat(Vector3(radius, radius, radius));
00562          }
00563          
00564          (dynamic_cast<Sphere*>(shape))->setTransToWorld(trans);
00565       } else if (type == "plane") {
00566          if (properties.contains("vertices")) {
00567             real_t *d = properties.getValue<real_t*>("vertices");
00568             
00569             Vector3 v1(d), v2(d + 3), v3(d + 6), v4(d + 9);
00570             safeDeleteArray(d);
00571             
00572             data.sceneGraph.beginNode(new SceneNodeShape(new Triangle(v1, v2, v3, 
00573                                                                       UV(0, 0), 
00574                                                                       UV(0, 1), 
00575                                                                       UV(1, 1))));
00576             data.sceneGraph.endNode();
00577             
00578             shape = new Triangle(v1, v3, v4, UV(0, 0), UV(1, 1), UV(1, 0));
00579          } else {
00580             shape = new Plane();
00581          }
00582       }
00583       
00584       if (NULL == shape)
00585          PARSE_ERROR(type + std::string(" failed to load"));
00586       
00587       ASSERT(shape);
00588       node = new SceneNodeShape(shape);
00589    }
00590    
00591    // record 'named' nodes which may be instanced
00592    if (properties.contains("name")) {
00593       const std::string &name = properties.getValue<std::string>("name");
00594       
00595       if (data.instancedNodes.find(name) != data.instancedNodes.end()) {
00596          const std::string &s = 
00597             std::string("error: duplicate definitions for named node '") + 
00598             name + "'";
00599          PARSE_ERROR(s);
00600       }
00601       
00602       data.instancedNodes[name] = node;
00603    }
00604    
00605    JSONVisitor visitor;
00606    visitor["material"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_material);
00607    
00608    data.sceneGraph.beginNode(node);
00609    
00610    if (type == "mesh") {
00611       JSONObjectConstIter spatialAccelIter = obj.find("spatialAccel");
00612       
00613       if (spatialAccelIter != obj.end()) {
00614          if (!_parse_spatialAccel(spatialAccelIter->second, data))
00615             return false;
00616       }
00617    }
00618    
00619    if (!visitor.visit(this, obj, data, NULL, false, false, false))
00620       return false;
00621    
00622    data.sceneGraph.endNode();
00623    return true;
00624 }
00625 
00626 bool MiltonJSONSceneLoader::_parse_version(const JSONVariant &v, 
00627                                            JSONParseData &data) const
00628 {
00629    return _parse_real_t(v, data.version);
00630 }
00631 
00632 bool MiltonJSONSceneLoader::_parse_renderer(const JSONVariant &v, 
00633                                             JSONParseData &data) const
00634 {
00635    PARSE_CHECK_TYPE_ERROR("renderer", "object", JSONObject, v);
00636    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00637    JSONObjectConstIter typeIter = obj.find("type");
00638    
00639    if (typeIter == obj.end())
00640       PARSE_ERROR("unable to infer renderer type");
00641    
00642    if (data.renderer)
00643       PARSE_ERROR("multiple renderer definitions");
00644    
00645    PARSE_CHECK_TYPE_ERROR("renderer.type", "string", JSONString, 
00646                           typeIter->second);
00647    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
00648    data << type << endl;
00649    
00650    data.source += std::string(" (renderer: ") + type + std::string(")");
00651    
00652    KeyValueIDMap req;
00653    
00654    req["noDirectSamples"] = "uint";
00655    req["noRenderThreads"] = "uint";
00656    req["noSuperSamples"]  = "uint";
00657    req["directSampleGenerator"] = "string";
00658    req["generator"]       = "string";
00659    
00660    if (type == "preview" || type == "OpenGL") {
00661       data.renderer = new OpenGLRenderer();
00662    } else if (type == "rayCaster") {
00663       data.renderer = new RayCaster();
00664       
00665       req["ambient"]  = "spectrum";
00666    } else if (type == "rayTracer") {
00667       data.renderer = new WhittedRayTracer();
00668       
00669       req["maxDepth"] = "uint";
00670       req["ambient"]  = "spectrum";
00671    } else if (type == "pathTracer") {
00672       data.renderer = new PathTracer();
00673    } else if (type == "bidirectionalPathTracer" || type == "bidirPathTracer") {
00674       data.renderer = new BidirectionalPathTracer();
00675    } /*else if (type == "photonMapper") {
00676       data.renderer = new PhotonMapper();
00677       
00678       req["diffuseNoGatherPhotons"] = "uint";
00679       req["causticNoGatherPhotons"] = "uint";
00680       req["diffuseGatherRadius"]    = "real_t";
00681       req["causticGatherRadius"]    = "real_t";
00682       req["diffuseNoPhotons"]       = "uint";
00683       req["causticNoPhotons"]       = "uint";
00684    }*/ else if (type == "mlt" || type == "MLT") {
00685       NYI();
00686    } else if (type == "dynamic") {
00687       if (!(data.renderer = _parse_dynamic_plugin<Renderer, MILTON_PLUGIN_TYPE_RENDERER>(obj, data)))
00688          PARSE_ERROR("dynamic renderer plugin: " + data.error);
00689    } else {
00690       PARSE_ERROR("invalid renderer type");
00691    }
00692    
00693    ASSERT(data.renderer);
00694    
00695    // valid variant found; now parse required and optional parameters
00696    if (!_parse_properties(req, obj, *data.renderer, data))
00697       return false;
00698    
00699    return true;
00700 }
00701 
00702 bool MiltonJSONSceneLoader::_parse_output(const JSONVariant &v, 
00703                                           JSONParseData &data) const
00704 {
00705    PARSE_CHECK_TYPE_ERROR("output", "object", JSONObject, v);
00706    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00707    JSONObjectConstIter typeIter = obj.find("type");
00708    
00709    if (data.output)
00710       PARSE_ERROR("multiple output definitions");
00711    
00712    PropertyMap &properties = data.outputProperties;
00713    KeyValueIDMap req;
00714    
00715    req["width"]  = "uint";
00716    req["height"] = "uint";
00717    req["size"]   = "uivec2"; // TODO
00718    req["dimensions"] = req["size"];
00719    
00720    if (typeIter != obj.end()) {
00721       PARSE_CHECK_TYPE_ERROR("output.type", "string", JSONString, 
00722                              typeIter->second);
00723       const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
00724       data << type << endl;
00725       
00726       if (type == "naive") {
00727          data.output = new NaiveRenderOutput();
00728       } else if (type == "default") {
00729          data.output = new DefaultRenderOutput();
00730       } else if (type == "reconstruction") {
00731          data.output = new ReconstructionRenderOutput();
00732          
00733          req["filter"] = "string";
00734       } else if (type == "dynamic") {
00735          if (!(data.output = _parse_dynamic_plugin<RenderOutput, MILTON_PLUGIN_TYPE_OUTPUT>(obj, data)))
00736             PARSE_ERROR("dynamic output plugin: " + data.error);
00737       } else {
00738          PARSE_ERROR("invalid output type");
00739       }
00740       
00741       ASSERT(data.output);
00742       properties = *data.output;
00743    }
00744    
00745    // valid variant found; now parse required and optional parameters
00746    if (!_parse_properties(req, obj, properties, data))
00747       return false;
00748    
00749    if (data.output)
00750       data.output->init();
00751    
00752    return true;
00753 }
00754 
00755 bool MiltonJSONSceneLoader::_parse_camera(const JSONVariant &v, 
00756                                           JSONParseData &data) const
00757 {
00758    PARSE_CHECK_TYPE_ERROR("camera", "object", JSONObject, v);
00759    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00760    JSONObjectConstIter typeIter = obj.find("type");
00761    
00762    if (typeIter == obj.end())
00763       PARSE_ERROR("unable to infer camera type");
00764    
00765    PARSE_CHECK_TYPE_ERROR("camera.type", "string", 
00766                           JSONString, typeIter->second);
00767    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
00768    data << type << endl;
00769    
00770    KeyValueIDMap req;
00771    
00772    if (data.camera)
00773       PARSE_ERROR("multiple camera definitions");
00774    
00775    if (type == "pinhole" || type == "thinlens") {
00776       req["eye"]   = "point3";
00777       req["look"]  = "vector3";
00778       req["focus"] = "point3";
00779       req["up"]    = "vector3";
00780       req["heightAngle"] = "real_t";
00781       req["aspectRatio"] = "real_t";
00782       req["near"]  = "real_t";
00783       req["far"]   = "real_t";
00784       
00785       if (type == "thinlens") {
00786          req["aperture"]      = "real_t";
00787          req["fstop"]         = "real_t";
00788          req["focalDistance"] = "real_t";
00789          req["focalPoint"]    = "vector2";
00790          
00791          data.camera = new ThinLensCamera();
00792       } else {
00793          data.camera = new PinholeCamera();
00794       }
00795    } else if (type == "dynamic") {
00796       if (!(data.camera = _parse_dynamic_plugin<Camera, MILTON_PLUGIN_TYPE_CAMERA>(obj, data)))
00797          PARSE_ERROR("dynamic camera plugin: " + data.error);
00798    } else {
00799       PARSE_ERROR("invalid camera type");
00800    }
00801    
00802    ASSERT(data.camera);
00803    
00804    // valid variant found; now parse required and optional parameters
00805    if (!_parse_properties(req, obj, *data.camera, data))
00806       return false;
00807    
00808    //data.camera->init();
00809    // gets initialized later in _finalizeData and/or in Renderer::init
00810    
00811    return true;
00812 }
00813 
00814 bool MiltonJSONSceneLoader::_parse_bsdf(const JSONVariant &v, 
00815                                         JSONParseData &data) const
00816 {
00817    PARSE_CHECK_TYPE_ERROR("bsdf", "object", JSONObject, v);
00818    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00819    JSONObjectConstIter typeIter = obj.find("type");
00820    
00821    if (typeIter == obj.end())
00822       PARSE_ERROR("unable to infer bsdf type");
00823    
00824    PARSE_CHECK_TYPE_ERROR("bsdf.type", "string", JSONString, 
00825                           typeIter->second);
00826    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
00827    data << type << endl;
00828    
00829    SceneNodeMaterial *parent = 
00830       dynamic_cast<SceneNodeMaterial*>(data.sceneGraph.top());
00831    ASSERT(parent);
00832    Material *material = parent->material;
00833    ASSERT(material);
00834    
00835    if (material->contains("bsdf"))
00836       PARSE_ERROR("multiple bsdf definitions");
00837    
00838    KeyValueIDMap req;
00839    
00840    if (type == "diffuse") {
00841       material->insert("bsdf", type);
00842       
00843       req["kd"] = "clampedSpectrum";
00844    } else if (type == "specular") {
00845       material->insert("bsdf", std::string("dielectric"));
00846       
00847       req["ks"] = "clampedSpectrum";
00848    } else if (type == "transmissive") {
00849       material->insert("bsdf", std::string("dielectric"));
00850       
00851       req["ks"] = "clampedSpectrum";
00852    } else if (type == "dielectric") {
00853       material->insert("bsdf", type);
00854       
00855       req["ks"]           = "clampedSpectrum";
00856       req["transparency"] = "clampedSpectrum";
00857    } else if (type == "absorbent") {
00858       material->insert("bsdf", type);
00859    } else if (type == "modifiedPhong" || type == "phong") {
00860       material->insert("bsdf", type);
00861       
00862       req["kd"] = "clampedSpectrum";
00863       req["ks"] = "clampedSpectrum";
00864       req["n"]  = "spectrum";
00865    } else if (type == "dynamic") {
00866       
00867       NYI(); // TODO
00868       
00869    } else {
00870       PARSE_ERROR("invalid bsdf type");
00871    }
00872    
00873    // valid variant found; now parse required and optional parameters
00874    if (!_parse_properties(req, obj, *material, data))
00875       return false;
00876    
00877    if (type == "specular")
00878       material->insert("transparency", 0.0);
00879    else if (type == "transmissive")
00880       material->insert("transparency", 1.0);
00881    
00882    return true;
00883 }
00884 bool MiltonJSONSceneLoader::_parse_emitter(const JSONVariant &v, 
00885                                            JSONParseData &data) const
00886 {
00887    return _parse_emitter_helper(v, data, false);
00888 }
00889 
00890 bool MiltonJSONSceneLoader::_parse_emitter_helper(const JSONVariant &v, 
00891                                                   JSONParseData &data, 
00892                                                   bool background) const
00893 {
00894    PARSE_CHECK_TYPE_ERROR("emitter", "object", JSONObject, v);
00895    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00896    JSONObjectConstIter typeIter = obj.find("type");
00897    
00898    if (typeIter == obj.end())
00899       PARSE_ERROR("unable to infer emitter type");
00900    
00901    PARSE_CHECK_TYPE_ERROR("emitter.type", "string", JSONString, 
00902                           typeIter->second);
00903    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
00904    data << type << endl;
00905    
00906    Material *material = NULL;
00907    
00908    if (background) {
00909       material = data.background;
00910    } else {
00911       SceneNodeMaterial *parent = 
00912          dynamic_cast<SceneNodeMaterial*>(data.sceneGraph.top());
00913       ASSERT(parent);
00914       material = parent->material;
00915    }
00916    
00917    ASSERT(material);
00918    
00919    if (material->contains("emitter"))
00920       PARSE_ERROR("multiple emitter definitions");
00921    
00922    KeyValueIDMap req;
00923    
00924    if (type == "null") {
00925       material->insert("emitter", type);
00926    } else if (type == "dynamic") {
00927       
00928       NYI(); // TODO
00929       
00930    } else {
00931       req["power"]           = "spectrum";
00932       req["glDiffuseColor"]  = "color3";
00933       req["glSpecularColor"] = "color3";
00934       req["glAttenuation"]   = "vector3";
00935       
00936       if (type == "omni") {
00937          material->insert("emitter", type);
00938       } else if (type == "oriented") {
00939          material->insert("emitter", type);
00940       } else if (type == "environment")  {
00941          if (background) {
00942             material->insert("emitter", type);
00943             
00944             req["coords"] = "string";
00945             req["path"]   = "string";
00946          } else {
00947             PARSE_ERROR("environment map emitters may only be placed in the "
00948                         "scene's \"background.emitter\" element");
00949          }
00950       } else {
00951          PARSE_ERROR("invalid emitter type");
00952       }
00953    }
00954    
00955    // valid variant found; now parse required and optional parameters
00956    if (!_parse_properties(req, obj, *material, data))
00957       return false;
00958    
00959    if (type == "environment" && !material->contains("path")) {
00960       PARSE_ERROR("environment map must contain a 'path' child element "
00961                   "specifying an absolute or relative path to an environment "
00962                   "texture");
00963    }
00964    
00965    return true;
00966 }
00967 
00968 bool MiltonJSONSceneLoader::_parse_medium(const JSONVariant &v, 
00969                                           JSONParseData &data) const
00970 {
00971    PARSE_CHECK_TYPE_ERROR("medium", "object", JSONObject, v);
00972    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
00973    JSONObjectConstIter typeIter = obj.find("type");
00974    std::string type = "homogenous"; // default
00975    
00976    if (typeIter != obj.end()) {
00977       PARSE_CHECK_TYPE_ERROR("medium.type", "string", JSONString, 
00978                              typeIter->second);
00979       type = boost::any_cast<JSONString>(*(typeIter->second));
00980    }
00981    data << type << endl;
00982    
00983    SceneNodeMaterial *parent = 
00984       dynamic_cast<SceneNodeMaterial*>(data.sceneGraph.top());
00985    ASSERT(parent);
00986    Material *material = parent->material;
00987    ASSERT(material);
00988    
00989    if (material->contains("medium"))
00990       PARSE_ERROR("multiple medium definitions");
00991    
00992    KeyValueIDMap req;
00993    req["ior"] = "spectrum";
00994    
00995    if (type == "homogenous") {
00996       material->insert("medium", type);
00997    } else if (type == "dynamic") {
00998       
00999       NYI(); // TODO
01000       
01001    } else {
01002       PARSE_ERROR("invalid medium type");
01003    }
01004    
01005    // valid variant found; now parse required and optional parameters
01006    if (!_parse_properties(req, obj, *material, data))
01007       return false;
01008    
01009    return true;
01010 }
01011 
01012 bool MiltonJSONSceneLoader::_parse_arbitraryTransform(const JSONVariant &v, 
01013                                                       JSONParseData &data) const
01014 {
01015    SceneNodeTransform *parent = 
01016       dynamic_cast<SceneNodeTransform*>(data.sceneGraph.top());
01017    
01018    ASSERT(parent);
01019    real_t matrix[16];
01020    
01021    if (!_parse_real_t_array(v, matrix, 16, data))
01022       PARSE_ERROR("arbitraryTransform expects 16 doubles in row-major order");
01023    
01024    parent->transform *= Matrix4x4(matrix);
01025    return true;
01026 }
01027 
01028 bool MiltonJSONSceneLoader::_parse_translate(const JSONVariant &v, 
01029                                              JSONParseData &data) const
01030 {
01031    SceneNodeTransform *parent = 
01032       dynamic_cast<SceneNodeTransform*>(data.sceneGraph.top());
01033    
01034    ASSERT(parent);
01035    real_t d[3];
01036    
01037    if (!_parse_real_t_array(v, d, 3, data))
01038       PARSE_ERROR("translate transformation expects 3 doubles");
01039    
01040    parent->translation *= getTransMat(Vector3(d));
01041    return true;
01042 }
01043 
01044 bool MiltonJSONSceneLoader::_parse_rotate(const JSONVariant &v, 
01045                                           JSONParseData &data) const
01046 {
01047    SceneNodeTransform *parent = 
01048       dynamic_cast<SceneNodeTransform*>(data.sceneGraph.top());
01049    
01050    ASSERT(parent);
01051    real_t d[7];
01052    
01053    if (!_parse_real_t_array(v, d, 7, data)) {
01054       // TODO: attempt to try alternative subobject w/ 
01055       // 'point', 'axis' and 'angle'
01056       
01057       PARSE_ERROR("rotate expects 7 doubles: point specifying origin of rotation; vector specifying axis of rotation, and angle in degrees to rotate about the axis; \n[ px, py, pz, vx, vy, vz, degrees ]");
01058    }
01059    
01060    parent->rotation *= getRotMat(Point3(d[0], d[1], d[2], 1), 
01061                                  Vector3(d + 3).getNormalized(), DEGREES_TO_RADIANS(d[6]));
01062    return true;
01063 }
01064 
01065 bool MiltonJSONSceneLoader::_parse_scale(const JSONVariant &v, 
01066                                          JSONParseData &data) const
01067 {
01068    SceneNodeTransform *parent = 
01069       dynamic_cast<SceneNodeTransform*>(data.sceneGraph.top());
01070    
01071    ASSERT(parent);
01072    real_t d[3];
01073    
01074    if (!_parse_real_t_array(v, d, 3, data))
01075       PARSE_ERROR("scale expects 3 doubles");
01076    
01077    parent->scale *= getScaleMat(Vector3(d));
01078    return true;
01079 }
01080 
01081 bool MiltonJSONSceneLoader::_parse_properties(const KeyValueIDMap &constraints,
01082                                               JSONObject const &obj, 
01083                                               PropertyMap &outMap, 
01084                                               JSONParseData &data) const
01085 {
01086    std::vector<bool> satisfied(constraints.size(), false);
01087    
01088    // parse constrained parameters
01089    FOREACH(KeyValueIDMapConstIter, constraints, iter) {
01090       const std::string &key = iter->first;
01091       // exp is a text description of what is expected in the value of obj
01092       const std::string &exp = iter->second;
01093       
01094       JSONObjectConstIter objIter = obj.find(key);
01095       
01096       if (objIter == obj.end()) { // ensure key exists
01097          //data << "missing optional key '" << std::string(key) << "'" << endl;
01098          continue;
01099          //PARSE_ERROR("missing required key '" + std::string(key) + "'");
01100       }
01101       
01102       const JSONVariant &v = objIter->second;
01103       
01104       if(v->empty()) {
01105          if (exp != "null")
01106             PARSE_TYPE_ERROR(key, exp, v);
01107          
01108          PARSE_ADD_MAP(outMap, key, boost::any());
01109       } else if(v->type() == typeid(bool)) {
01110          if (exp != "bool")
01111             PARSE_TYPE_ERROR(key, exp, v);
01112          
01113          PARSE_ADD_MAP(outMap, key, boost::any_cast<bool>(*v));
01114       } else if(v->type() == typeid(int)) {
01115          int val = boost::any_cast<int>(*v);
01116          
01117          if (exp == "int") {
01118             PARSE_ADD_MAP(outMap, key, val);
01119          } else if (exp == "real_t") {
01120             PARSE_ADD_MAP(outMap, key, static_cast<real_t>(val));
01121          } else if (exp == "clampedSpectrum") {
01122             const real_t val2 = static_cast<real_t>(val);
01123             
01124             if (!_is_valid_clampedSpectralSampleSet(val2))
01125                PARSE_ERROR("clampedSpectrum must have value within [0, 1]");
01126             
01127             PARSE_ADD_MAP(outMap, key, SpectralSampleSet::fill(val2));
01128          } else if (exp == "spectrum") {
01129             const real_t val2 = static_cast<real_t>(val);
01130             
01131             PARSE_ADD_MAP(outMap, key, SpectralRadianceSet::fill(val2));
01132          } else if (exp == "uint") {
01133             PARSE_ADD_MAP(outMap, key, static_cast<unsigned>(val));
01134          } else {
01135             PARSE_TYPE_ERROR(key, exp, v);
01136          }
01137       } else if(v->type() == typeid(double)) {
01138          const real_t val = static_cast<real_t>(boost::any_cast<double>(*v));
01139          
01140          if (exp == "real_t") {
01141             PARSE_ADD_MAP(outMap, key, val);
01142          } else if (exp == "int" || exp == "uint") {
01143             const int val2 = floor(val);
01144             if (val2 != val)
01145                PARSE_ERROR("expected integer; found real_t");
01146             
01147             if (exp == "int")
01148                PARSE_ADD_MAP(outMap, key, val2);
01149             else 
01150                PARSE_ADD_MAP(outMap, key, static_cast<unsigned>(val));
01151          } else if (exp == "clampedSpectrum") {
01152             if (!_is_valid_clampedSpectralSampleSet(val))
01153                PARSE_ERROR("clampedSpectrum must have value within [0, 1]");
01154             
01155             PARSE_ADD_MAP(outMap, key, SpectralSampleSet::fill(val));
01156          } else if (exp == "spectrum") {
01157             PARSE_ADD_MAP(outMap, key, SpectralRadianceSet::fill(val));
01158          } else {
01159             PARSE_TYPE_ERROR(key, exp, v);
01160          }
01161       } else if(v->type() == typeid(std::string)) {
01162          if (exp != "string" && exp != "clampedSpectrum")
01163             PARSE_TYPE_ERROR(key, exp, v);
01164          
01165          PARSE_ADD_MAP(outMap, key, boost::any_cast<JSONString>(*v));
01166       } else if(v->type() == typeid(JSONArray)) {
01167          JSONArray const &a = boost::any_cast<JSONArray>(*v);
01168          unsigned length = a.size();
01169          
01170          // TODO: allow spectra to have arbitrary length!!
01171          if (exp == "point3" || exp == "vector3" || exp == "color3" || 
01172              exp == "spectrum" || exp == "clampedSpectrum")
01173          {
01174             if (length != 3)
01175                PARSE_ERROR("'" + key + "' expects an array of length 3");
01176             
01177             real_t d[3];
01178             for(int i = 0; i < 3; ++i) {
01179                if (!_parse_real_t(a[i], d[i])) {
01180                   PARSE_TYPE_ERROR(key, "real_t", a[i]);
01181                }
01182             }
01183             
01184             if (exp == "point3") {
01185                PARSE_ADD_MAP(outMap, key, Point3 (d[0], d[1], d[2]));
01186             } else if (exp == "vector3") {
01187                PARSE_ADD_MAP(outMap, key, Vector3(d[0], d[1], d[2]));
01188             } else if (exp == "spectrum") {
01189                PARSE_ADD_MAP(outMap, key, SpectralRadianceSet(d[0], d[1], d[2]));
01190             } else if (exp == "clampedSpectrum") {
01191                for(unsigned i = 0; i < 3; ++i) {
01192                   if (!_is_valid_clampedSpectralSampleSet(d[i]))
01193                      PARSE_ERROR("clampedSpectrum expects values within [0, 1]");
01194                }
01195                
01196                PARSE_ADD_MAP(outMap, key, SpectralSampleSet(d[0], d[1], d[2]));
01197             } else if (exp == "color3") {
01198                // ensure color components are within [0, 1]
01199                for(int i = 0; i < 3; ++i) {
01200                   if (d[i] < 0 || d[i] > 1) {
01201                      PARSE_ERROR("'" + key + 
01202                         "' expects a color3 with components in [0, 1]");
01203                   }
01204                }
01205                
01206                PARSE_ADD_MAP(outMap, key, SpectralRadianceSet(RgbaHDR(d[0], d[1], d[2])));
01207             } else {
01208                ASSERT(0 && "PANIC");
01209             }
01210          } else if (exp.find("vector") == 0) {
01211             ASSERT(exp.length() > strlen("vector"));
01212             
01213             unsigned n = atoi(exp.c_str() + 6);
01214             
01215             if (n != length) {
01216                ostringstream s;
01217                s << "'" << key << "' expects an array of length " << n;
01218                PARSE_ERROR(s.str());
01219             }
01220             
01221             real_t *d = new real_t[n];
01222             
01223             for(unsigned i = 0; i < n; ++i) {
01224                if (!_parse_real_t(a[i], d[i]))
01225                   PARSE_TYPE_ERROR(key, "real_t", a[i]);
01226             }
01227             
01228             // caller will safeDeleteArray 'd'
01229             PARSE_ADD_MAP(outMap, key, d);
01230          } else {
01231             PARSE_TYPE_ERROR(key, exp, v);
01232          }
01233       } else if(v->type() == typeid(JSONObject)) {
01234          //JSONObject const &o = boost::any_cast<JSONObject>(*v);
01235          
01236          ASSERT(exp != "object"); // TODO: currently unhandled
01237          PARSE_TYPE_ERROR(key, exp, v);
01238          
01239       } else {
01240          // shouldn't ever reach here
01241          PARSE_ERROR("PANIC: Found unexpected JSON type '" + 
01242                      std::string(typeid(*v).name()));
01243       }
01244    }
01245    
01246    // parse optional parameters
01247    FOREACH(JSONObjectConstIter, obj, iter) {
01248       const std::string &key = iter->first;
01249       const JSONVariant &v   = iter->second;
01250       
01251       KeyValueIDMapConstIter constraintIter = constraints.find(key);
01252       
01253       if (constraintIter != constraints.end()) { // ensure key exists
01254          // already saw this key in the first FOREACH (it had a type constraint)
01255          continue;
01256       }
01257       
01258       if(v->empty()) {
01259          PARSE_ADD_MAP_OPTIONAL(outMap, key, boost::any());
01260       } else if(v->type() == typeid(bool)) {
01261          PARSE_ADD_MAP_OPTIONAL(outMap, key, boost::any_cast<bool>(*v));
01262       } else if(v->type() == typeid(int)) {
01263          PARSE_ADD_MAP_OPTIONAL(outMap, key, boost::any_cast<int>(*v));
01264       } else if(v->type() == typeid(double)) {
01265          PARSE_ADD_MAP_OPTIONAL(outMap, key, 
01266                                 static_cast<real_t>(boost::any_cast<real_t>(*v)));
01267       } else if(v->type() == typeid(std::string)) {
01268          PARSE_ADD_MAP_OPTIONAL(outMap, key, boost::any_cast<JSONString>(*v));
01269       } else if(v->type() == typeid(JSONArray)) {
01270          JSONArray const &a = boost::any_cast<JSONArray>(*v);
01271          unsigned length = a.size();
01272          
01273          if (length != 3) {
01274             cout << "ignoring attribute '" << key << "' of irregular length" << endl;
01275             continue;
01276          }
01277          
01278          real_t d[3];
01279          for(int i = 0; i < 3; ++i) {
01280             if (!_parse_real_t(a[i], d[i])) {
01281                continue;
01282             }
01283          }
01284          
01285          PARSE_ADD_MAP_OPTIONAL(outMap, key, Vector3(d[0], d[1], d[2]));
01286       } else if(v->type() == typeid(JSONObject)) {
01287          //JSONObject const &o = boost::any_cast<JSONObject>(*v);
01288          
01289          //PARSE_TYPE_ERROR(key, std::string("optional parameter"), v);
01290          continue;
01291       } else {
01292          // shouldn't ever reach here
01293          //PARSE_ERROR("PANIC: Found unexpected JSON type '" + 
01294          //            std::string(objVal));
01295          continue;
01296       }
01297    }
01298    
01299    return true;
01300 }
01301 
01302 #if 0
01303 bool MiltonJSONSceneLoader::_parse_filter(const JSONVariant &v, 
01304                                           KernelFilter *outFilter, 
01305                                           JSONParseData &data) const
01306 {
01307    PARSE_CHECK_TYPE_ERROR("filter", "object", JSONObject, v);
01308    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01309    JSONObjectConstIter typeIter = obj.find("type");
01310    
01311    if (typeIter == obj.end())
01312       PARSE_ERROR("unable to infer filter type");
01313    
01314    if (NULL == data.output)
01315       PARSE_ERROR("'filter' element must fall within a parent 'output' element");
01316    
01317    PARSE_CHECK_TYPE_ERROR("filter.type", "string", JSONString, 
01318                           typeIter->second);
01319    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
01320    data << type << endl;
01321    
01322    KernelFilter *filter = NULL;
01323    KeyValueIDMap req;
01324    
01325    req["support"] = "uint";
01326    
01327    if (type == "box") {
01328       filter = new BoxFilter();
01329    } else if (type == "triangle") {
01330       filter = new TriangleFilter();
01331    } else if (type == "gaussian") {
01332       filter = new GaussianFilter();
01333       
01334       req["sigma"] = "real_t";
01335    } else if (type == "mitchell") {
01336       filter = new MitchellFilter();
01337       
01338       req["B"] = "real_t";
01339       req["C"] = "real_t";
01340    } else if (type == "lanczosSinc") {
01341       filter = new LanczosSincFilter();
01342       
01343       req["tau"] = "real_t";
01344    } else if (type == "dynamic") {
01345       
01346       NYI();
01347       
01348    } else {
01349       PARSE_ERROR("invalid filter type");
01350    }
01351    
01352    ASSERT(filter);
01353    
01354    // valid variant found; now parse required and optional parameters
01355    if (!_parse_properties(req, obj, *filter, data))
01356       return false;
01357    
01358    filter->init();
01359    outFilter = filter;
01360    
01361    return true;
01362 }
01363 #endif
01364 
01365 void MiltonJSONSceneLoader::_add_node(JSONVisitor &outVisitor) const {
01366    outVisitor["material"]  = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_material);
01367    outVisitor["transform"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_transform);
01368    
01369    _add_shapes(outVisitor);
01370 }
01371 
01372 void MiltonJSONSceneLoader::_add_shapes(JSONVisitor &outVisitor) const {
01373    // all supported shapes
01374    // TODO: if we call _parse_shape, lose info about what type of shape it 
01375    // was!! how to fix cleanly..?
01376    outVisitor["blob"]     = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_blob);
01377    outVisitor["cube"]     = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_cube);
01378    outVisitor["cone"]     = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_cone);
01379    outVisitor["cylinder"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_cylinder);
01380    outVisitor["mesh"]     = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_mesh);
01381    outVisitor["plane"]    = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_plane);
01382    outVisitor["point"]    = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_point);
01383    outVisitor["shape"]    = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_shape);
01384    outVisitor["sphere"]   = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_sphere);
01385    outVisitor["shapeSet"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_shapeSet);
01386    outVisitor["triangle"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_triangle);
01387    
01388    // TODO
01389    //outVisitor["dynamic"]  = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_shape);
01390 }
01391 
01392 #define DECLARE_VARIANT(prim, shape)                                    \
01393    bool MiltonJSONSceneLoader::_parse_##prim(const JSONVariant &v,      \
01394                                              JSONParseData &data) const \
01395 {                                                                       \
01396    PARSE_CHECK_TYPE_ERROR(#prim, "object", JSONObject, v);              \
01397    JSONObject obj(boost::any_cast<JSONObject>(*v));                     \
01398    obj.insert(std::make_pair(JSONString("type"),                        \
01399                              JSONVariant(                               \
01400                                 new boost::any(std::string(#prim)))));  \
01401                                                                         \
01402    return _parse_##shape(JSONVariant(new boost::any(obj)), data);       \
01403 }
01404 
01405 #define DECLARE_PRIMITIVE(prim) DECLARE_VARIANT(prim, shape)
01406 
01407 DECLARE_PRIMITIVE(cube);
01408 DECLARE_PRIMITIVE(cone);
01409 DECLARE_PRIMITIVE(cylinder);
01410 DECLARE_PRIMITIVE(mesh);
01411 DECLARE_PRIMITIVE(plane);
01412 DECLARE_PRIMITIVE(point);
01413 DECLARE_PRIMITIVE(sphere);
01414 DECLARE_PRIMITIVE(triangle);
01415 
01416 bool MiltonJSONSceneLoader::_parse_shapeSet(const JSONVariant &v, 
01417                                             JSONParseData &data) const
01418 {
01419    PARSE_CHECK_TYPE_ERROR("shapeSet", "object", JSONObject, v);
01420    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01421    
01422    JSONVisitor visitor;
01423    _add_node(visitor);
01424    
01425    bool root = (NULL == data.primitives);
01426    
01427    if (root)
01428       visitor["background"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_background);
01429    
01430    visitor["spatialAccel"]  = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_spatialAccel);
01431    
01432    ShapeSet *shapeSet = new ShapeSet(true);
01433    if (root)
01434       data.primitives = shapeSet;
01435    
01436    data.sceneGraph.beginNode(new SceneNodeShape(shapeSet));
01437    
01438    if (!_parse_properties(KeyValueIDMap(), obj, *shapeSet, data))
01439       return false;
01440    
01441    if (!visitor.visit(this, obj, data, NULL, false, false, false))
01442       return false;
01443    
01444    if (!root)
01445       data.sceneGraph.endNode();
01446    
01447    return true;
01448 }
01449 
01450 bool MiltonJSONSceneLoader::_parse_blob(const JSONVariant &v, 
01451                                         JSONParseData &data) const
01452 {
01453    PARSE_CHECK_TYPE_ERROR("blob", "object", JSONObject, v);
01454    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01455    
01456    JSONVisitor visitor;
01457    _add_node(visitor);
01458    
01459    Blob *blob = new Blob();
01460    KeyValueIDMap req;
01461    
01462    req["threshold"] = "real_t";
01463    
01464    visitor["metaObjects"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_metaObjects);
01465    visitor["threshold"] = JSONVisitorValue(&MiltonJSONSceneLoader::_parse_dummy);
01466    
01467    data.sceneGraph.beginNode(new SceneNodeShape(blob));
01468    
01469    if (!_parse_properties(req, obj, *blob, data))
01470       return false;
01471    
01472    if (!visitor.visit(this, obj, data, NULL, false, false, false))
01473       return false;
01474    
01475    data.sceneGraph.endNode();
01476    
01477    return true;
01478 }
01479 
01480 bool MiltonJSONSceneLoader::_parse_metaObjects(const JSONVariant &v, 
01481                                                JSONParseData &data) const
01482 {
01483    PARSE_CHECK_TYPE_ERROR("metaObjects", "array", JSONArray, v);
01484    JSONArray const &array = boost::any_cast<JSONArray>(*v);
01485    
01486    FOREACH(JSONArrayConstIter, array, iter) {
01487       JSONVariant const &curV = *iter;
01488       
01489       PARSE_CHECK_TYPE_ERROR("meta", "object", JSONObject, curV);
01490       JSONObject const &obj = boost::any_cast<JSONObject>(*curV);
01491       
01492       if (obj.find("type") != obj.end()) {
01493          if (!_parse_meta(curV, data))
01494             return false;
01495       } else if (obj.find("ball") != obj.end()) {
01496          if (!_parse_ball(curV, data))
01497             return false;
01498       }
01499    }
01500    
01501    return true;
01502 }
01503 
01504 bool MiltonJSONSceneLoader::_parse_meta(const JSONVariant &v, 
01505                                         JSONParseData &data) const
01506 {
01507    PARSE_CHECK_TYPE_ERROR("meta", "object", JSONObject, v);
01508    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01509    JSONObjectConstIter typeIter = obj.find("type");
01510    
01511    if (typeIter == obj.end())
01512       PARSE_ERROR("unable to infer meta object type");
01513    
01514    PARSE_CHECK_TYPE_ERROR("meta.type", "string", 
01515                           JSONString, typeIter->second);
01516    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
01517    data << type << endl;
01518    
01519    MetaObject *meta = NULL;
01520    KeyValueIDMap req;
01521    
01522    req["negative"] = "bool";
01523    req["strength"] = "real_t";
01524    
01525    if (type == "ball") {
01526       meta = new MetaBall();
01527       
01528       req["position"] = "vector3";
01529       req["radius"]   = "real_t";
01530    } else if (type == "dynamic") {
01531       if (!(meta = _parse_dynamic_plugin<MetaObject, MILTON_PLUGIN_TYPE_METAOBJECT>(obj, data)))
01532          PARSE_ERROR("dynamic meta-object plugin: " + data.error);
01533    } else {
01534       PARSE_ERROR("invalid meta type");
01535    }
01536    
01537    ASSERT(meta);
01538    
01539    // valid variant found; now parse required and optional parameters
01540    if (!_parse_properties(req, obj, *meta, data))
01541       return false;
01542    
01543    // get parent blob object
01544    SceneNodeShape *parent = 
01545       dynamic_cast<SceneNodeShape*>(data.sceneGraph.top());
01546    ASSERT(parent);
01547    Shape *shape = parent->shape;
01548    ASSERT(shape);
01549    Blob *blob = dynamic_cast<Blob*>(shape);
01550    ASSERT(blob);
01551    
01552    blob->push_back(meta);
01553    
01554    return true;
01555 }
01556 
01557 
01558 #define DECLARE_META(prim) DECLARE_VARIANT(prim, meta)
01559 
01560 DECLARE_META(ball);
01561 
01562 bool MiltonJSONSceneLoader::_parse_spatialAccel(const JSONVariant &v, 
01563                                                 JSONParseData &data) const
01564 {
01565    PARSE_CHECK_TYPE_ERROR("spatialAccel", "object", JSONObject, v);
01566    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01567    JSONObjectConstIter typeIter = obj.find("type");
01568    
01569    if (typeIter == obj.end())
01570       PARSE_ERROR("unable to infer spatialAccel type");
01571    
01572    PARSE_CHECK_TYPE_ERROR("spatialAccel.type", "string", JSONString, 
01573                           typeIter->second);
01574    const std::string &type = boost::any_cast<JSONString>(*(typeIter->second));
01575    data << type << endl;
01576    
01577    SceneNodeShape *parent = 
01578       dynamic_cast<SceneNodeShape*>(data.sceneGraph.top());
01579    ASSERT(parent);
01580    Shape *shape = parent->shape;
01581    ASSERT(shape);
01582    PropertyMap *properties = dynamic_cast<PropertyMap*>(shape);
01583    ASSERT(properties);
01584    
01585    if (properties->contains("spatialAccel"))
01586       PARSE_ERROR("multiple spatialAccel definitions");
01587    
01588    KeyValueIDMap req;
01589    
01590    if (type == "naive") {
01591       properties->insert("spatialAccel", type);
01592    } else if (type == "kdTree") {
01593       properties->insert("spatialAccel", type);
01594       
01595       req["kdSplitPlaneType"] = "string";
01596       req["kdSplitAxisType"]  = "string";
01597       req["kdMinPrimitives"]  = "uint";
01598       req["kdMaxDepth"]       = "uint";
01599       req["kdNoThreads"]      = "uint";
01600       req["kdPostCompress"]   = "bool";
01601       req["kdCostTraversal"]  = "real_t";
01602       req["kdCostIntersect"]  = "real_t";
01603       req["kdEmptyBias"]      = "real_t";
01604    } else if (type == "dynamic") {
01605       
01606       NYI(); // TODO
01607       
01608    } else {
01609       PARSE_ERROR("invalid spatialAccel type");
01610    }
01611    
01612    // valid variant found; now parse required and optional parameters
01613    return _parse_properties(req, obj, *properties, data);
01614 }
01615 
01616 bool MiltonJSONSceneLoader::_parse_background(const JSONVariant &v, 
01617                                               JSONParseData &data) const
01618 {
01619    PARSE_CHECK_TYPE_ERROR("background", "object", JSONObject, v);
01620    JSONObject const &obj = boost::any_cast<JSONObject>(*v);
01621    
01622    if (data.background != NULL)
01623       PARSE_ERROR("scene may contain at most one background element");
01624    
01625    if (obj.size() == 0)
01626       return true; // use default background
01627    
01628    JSONObjectConstIter emitterIter = obj.find("emitter");
01629    
01630    if (obj.size() > 1 || emitterIter == obj.end())
01631       PARSE_ERROR("background element must have exactly one child emitter element");
01632    
01633    data.background = new Material();
01634    
01635    if (_parse_emitter_helper(emitterIter->second, data, true)) {
01636       ASSERT(data.background);
01637       data.background->init();
01638       
01639       return true;
01640    }
01641    
01642    return false;
01643 }
01644 
01645 bool MiltonJSONSceneLoader::_parse_dummy(const JSONVariant &v, 
01646                                          JSONParseData &data) const
01647 {
01648    return true;
01649 }
01650 
01651 bool MiltonJSONSceneLoader::_parse_real_t(const JSONVariant &v, 
01652                                           real_t &outVal) const
01653 {
01654    const std::type_info &type = v->type();
01655    
01656    if (type == typeid(int))
01657       outVal = boost::any_cast<int>(*v);
01658    else if (type == typeid(double))
01659       outVal = static_cast<real_t>(boost::any_cast<double>(*v));
01660    else if (type == typeid(float))
01661       outVal = static_cast<real_t>(boost::any_cast<float>(*v));
01662    else
01663       return false;
01664    
01665    return true;
01666 }
01667 
01668 bool MiltonJSONSceneLoader::_parse_real_t_array(const JSONVariant &v, 
01669                                                 real_t *outArray, 
01670                                                 unsigned expectedLength, 
01671                                                 JSONParseData &data) const
01672 {
01673    ASSERT(outArray);
01674    ASSERT(expectedLength > 0);
01675    
01676    PARSE_CHECK_TYPE_ERROR("initializer", "array", JSONArray, v);
01677    JSONArray const &array = boost::any_cast<JSONArray>(*v);
01678    unsigned length = array.size();
01679    
01680    if (length != expectedLength)
01681       PARSE_ERROR("(incorrect length)");
01682    
01683    for(unsigned i = 0; i < length; ++i) {
01684       if (!_parse_real_t(array[i], outArray[i])) {
01685          PARSE_ERROR("(incorrect type)");
01686       }
01687    }
01688    
01689    return true;
01690 }
01691 
01692 template<typename T, unsigned E>
01693 T *MiltonJSONSceneLoader::_parse_dynamic_plugin(JSONObject const &obj, 
01694                                                 JSONParseData &data) const
01695 {
01696    JSONObjectConstIter pathIter = obj.find("path");
01697    PARSE_CHECK_TYPE_ERROR("dynamic.path", "string", JSONString, 
01698                           pathIter->second);
01699    const std::string &path = boost::any_cast<JSONString>(*(pathIter->second));
01700    data << path << endl;
01701    
01702    SharedLibraryManager *manager = ResourceManager::manager;
01703    SharedLibrary *library = manager->load(path);
01704    
01705    if (NULL == library)
01706       PARSE_ERROR(path + std::string(": plugin failed to load: ") + manager->getLastError());
01707    
01708    void *plugin_type_symbol   = library->getSymbol("plugin_type");
01709    void *plugin_new_symbol    = library->getSymbol("plugin_new");
01710    //void *plugin_delete_symbol = library->getSymbol("plugin_delete");
01711    
01712    if (NULL == plugin_type_symbol)
01713       PARSE_ERROR(path + std::string(": invalid plugin; could not find plugin_type symbol ") + manager->getLastError());
01714    
01715    if (NULL == plugin_new_symbol)
01716       PARSE_ERROR(path + std::string(": invalid plugin; could not find plugin_new symbol ") + manager->getLastError());
01717    
01718    plugin_type_func_t plugin_type_func = (plugin_type_func_t) plugin_type_symbol;
01719    MILTON_PLUGIN_TYPE actualtype       = plugin_type_func();
01720    
01721    if (actualtype != E) {
01722       ostringstream s;
01723       s << path << ": dynamic plugin expected type '" << E << "' but found type '" 
01724         << actualtype << "' -- " <<  manager->getLastError();
01725       
01726       PARSE_ERROR(s.str());
01727    }
01728    
01729    plugin_new_func_t plugin_new_func = (plugin_new_func_t) plugin_new_symbol;
01730    void *plugin = plugin_new_func();
01731    
01732    if (plugin == NULL)
01733       PARSE_ERROR(path + std::string(": invalid plugin; plugin_new returned NULL; ") + manager->getLastError());
01734    
01735    return (T *)plugin;
01736 }
01737 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6