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
1.5.6