// ======================================================================== // // Copyright 2009-2013 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // // you may not use this file except in compliance with the License. // // You may obtain a copy of the License at // // // // http://www.apache.org/licenses/LICENSE-2.0 // // // // Unless required by applicable law or agreed to in writing, software // // distributed under the License is distributed on an "AS IS" BASIS, // // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // // limitations under the License. // // ======================================================================== // #include "xml_loader.h" #include "xml_parser.h" #include "scene.h" #include "math/affinespace.h" #include "math/vec2.h" #include "math/vec3.h" #include "math/vec4.h" #include namespace embree { struct Variant { ALIGNED_CLASS public: /*! Determines which kind of value is stored in the variant. */ enum Type { EMPTY, /*!< variant is empty */ BOOL1, /*!< variant stores bool value */ BOOL2, /*!< variant stores bool2 value */ BOOL3, /*!< variant stores bool3 value */ BOOL4, /*!< variant stores bool4 value */ INT1, /*!< variant stores int value */ INT2, /*!< variant stores int2 value */ INT3, /*!< variant stores int3 value */ INT4, /*!< variant stores int4 value */ FLOAT1, /*!< variant stores float value */ FLOAT2, /*!< variant stores float2 value */ FLOAT3, /*!< variant stores float3 value */ FLOAT4, /*!< variant stores float4 value */ STRING, /*!< variant stores string value */ }; /*! Constructs an empty variant object. */ Variant ( ) : type(EMPTY) { } /*! Constructs a variant object holding a bool value. */ Variant (bool b0 ) : type(BOOL1) { b[0] = b0; } /*! Constructs a variant object holding a bool2 value. */ Variant (bool b0, bool b1 ) : type(BOOL2) { b[0] = b0; b[1] = b1; } /*! Constructs a variant object holding a bool3 value. */ Variant (bool b0, bool b1, bool b2 ) : type(BOOL3) { b[0] = b0; b[1] = b1; b[2] = b2; } /*! Constructs a variant object holding a bool4 value. */ Variant (bool b0, bool b1, bool b2, bool b3) : type(BOOL4) { b[0] = b0; b[1] = b1; b[2] = b2; b[3] = b3; } /*! Constructs a variant object holding an int value. */ Variant (int i0) : type(INT1) { i[0] = i0; } /*! Constructs a variant object holding an int2 value. */ Variant (Vec2i v) : type(INT2) { i[0] = v.x; i[1] = v.y; } /*! Constructs a variant object holding an int3 value. */ Variant (Vec3i v) : type(INT3) { i[0] = v.x; i[1] = v.y; i[2] = v.z; } /*! Constructs a variant object holding an int4 value. */ Variant (Vec4i v) : type(INT4) { i[0] = v.x; i[1] = v.y; i[2] = v.z; i[3] = v.w; } /*! Constructs a variant object holding a float value. */ Variant (float f0) : type(FLOAT1) { f[0] = f0; } /*! Constructs a variant object holding a float2 value. */ Variant (Vec2f v) : type(FLOAT2) { f[0] = v.x; f[1] = v.y; } /*! Constructs a variant object holding a float3 value. */ Variant (Vec3f v) : type(FLOAT3) { f[0] = v.x; f[1] = v.y; f[2] = v.z; } /*! Constructs a variant object holding a float4 value. */ Variant (Vec4f v) : type(FLOAT4) { f[0] = v.x; f[1] = v.y; f[2] = v.z; f[3] = v.w; } /*! Constructs a variant object holding a string value. */ Variant (const char* str) : type(STRING), str(str) {} /*! Constructs a variant object holding a string value. */ Variant (const std::string& str) : type(STRING), str(str) {} /*! Extracts a boolean from the variant type. */ bool getBool () const { return b[0]; } /*! Extracts an integer from the variant type. */ int getInt () const { return i[0]; } /*! Extracts a float from the variant type. */ float getFloat() const { return f[0]; } /*! Extracts a Vec2f from the variant type. */ Vec2f getVec2f() const { return Vec2f(f[0],f[1]); } /*! Extracts a Vec3f from the variant type. */ Vec3f getVec3f() const { return Vec3f(f[0],f[1],f[2]); } /*! Extracts a Vec3fa from the variant type. */ Vec3f getVec3fa() const { return Vec3fa(f[0],f[1],f[2]); } /*! Extracts a string from the variant type. */ std::string getString() const { return str; } operator bool() const { return type != EMPTY; } public: Type type; //!< Type of the data contained in the variant. union { bool b[4]; //!< Storage for single bool,bool2,bool3, and bool4 values. int i[4]; //!< Storage for single int,int2,int3, and int4 values. float f[12]; //!< Storage for single float,float2,float3, float4, and AffineSpace3f values. }; std::string str; //!< Storage for string values. }; /*! Parameter container. Implements parameter container as a mapping * from a string to variant values. This container is used to pass * parameters for constructing objects from the API to the * constructors of that objects. All the extraction functions * return a default values in case the parameter is not found. */ class Parms { public: /*! clears the parameter container */ void clear() { m.clear(); } /*! Extracts a named boolean out of the container. */ bool getBool(const char* name, bool def = false) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::BOOL1) return def; return (*i).second.getBool(); } /*! Extracts a named integer out of the container. */ int getInt(const char* name, int def = zero) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::INT1) return def; return (*i).second.getInt(); } /*! Extracts a named float out of the container. */ float getFloat(const char* name, float def = zero) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::FLOAT1) return def; return (*i).second.getFloat(); } /*! Extracts a named Vec2f out of the container. */ Vec2f getVec2f(const char* name, const Vec2f& def = zero) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::FLOAT2) return def; return (*i).second.getVec2f(); } /*! Extracts a named Vec3f out of the container. */ Vec3f getVec3f(const char* name, const Vec3f& def = zero) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; return (*i).second.getVec3f(); } /*! Extracts a named Vec3f out of the container. */ Vec3fa getVec3fa(const char* name, const Vec3fa& def = zero) const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; return (*i).second.getVec3fa(); } /*! Extracts a named string out of the container. */ std::string getString(const char* name, std::string def = "") const { std::map::const_iterator i = m.find(name); if (i == m.end() || (*i).second.type != Variant::STRING) return def; return (*i).second.getString(); } /*! Adds a new named element to the container. */ void add(const std::string& name, Variant data) { m[name] = data; } private: /*! Implementation of the container as an STL map. */ std::map m; }; class XMLLoader { public: XMLLoader(const FileName& fileName, const AffineSpace3f& space, OBJScene& scene); ~XMLLoader(); public: void loadPointLight(const Ref& xml, const AffineSpace3f& space); void loadSpotLight(const Ref& xml, const AffineSpace3f& space); void loadDirectionalLight(const Ref& xml, const AffineSpace3f& space); void loadDistantLight(const Ref& xml, const AffineSpace3f& space); void loadAmbientLight(const Ref& xml, const AffineSpace3f& space); void loadTriangleLight(const Ref& xml, const AffineSpace3f& space); void loadHDRILight(const Ref& xml, const AffineSpace3f& space); Parms loadMaterialParms(const Ref& parms); int loadMaterial(const Ref& xml, std::string* name = NULL); void loadTriangleMesh(const Ref& xml, const AffineSpace3f& space); void loadSubdivMesh(const Ref& xml, const AffineSpace3f& space); void loadSphere(const Ref& xml, const AffineSpace3f& space); void loadDisk(const Ref& xml, const AffineSpace3f& space); void loadQuadLight(const Ref& xml, const AffineSpace3f& space); void loadScene(const Ref& xml, const AffineSpace3f& space); void loadTransformNode(const Ref& xml, const AffineSpace3f& space); void loadGroupNode(const Ref& xml, const AffineSpace3f& space); private: template T load(const Ref& xml) { return T(zero); } template T load(const Ref& xml, const T& opt) { return T(zero); } char* loadBinary(const Ref& xml, size_t eltSize, size_t& size); std::vector loadFloatArray(const Ref& xml); std::vector loadVec2fArray(const Ref& xml); std::vector loadVec3fArray(const Ref& xml); std::vector loadIntArray(const Ref& xml); std::vector loadVec2iArray(const Ref& xml); std::vector loadVec3iArray(const Ref& xml); private: FileName path; //!< path to XML file FILE* binFile; //!< .bin file for reading binary data FileName binFileName; //!< name of the .bin file private: std::map materialMap; //!< named materials std::map, int> materialCache; //!< map for detecting repeated materials public: OBJScene& scene; }; ////////////////////////////////////////////////////////////////////////////// //// Loading standard types from an XML node ////////////////////////////////////////////////////////////////////////////// template<> std::string XMLLoader::load(const Ref& xml) { if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong string body"); return xml->body[0].String(); } template<> bool XMLLoader::load(const Ref& xml, const bool& opt) { if (xml == null) return opt; if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong bool body"); return xml->body[0].Int() != 0; } template<> int XMLLoader::load(const Ref& xml) { if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int body"); return xml->body[0].Int(); } template<> Vec2i XMLLoader::load(const Ref& xml) { if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int2 body"); return Vec2i(xml->body[0].Int(),xml->body[1].Int()); } template<> Vec3i XMLLoader::load(const Ref& xml) { if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int3 body"); return Vec3i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int()); } template<> Vec4i XMLLoader::load(const Ref& xml) { if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int4 body"); return Vec4i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int(),xml->body[3].Int()); } template<> float XMLLoader::load(const Ref& xml) { if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); return xml->body[0].Float(); } template<> float XMLLoader::load(const Ref& xml, const float& opt) { if (xml == null) return opt; if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); return xml->body[0].Float(); } template<> Vec2f XMLLoader::load(const Ref& xml) { if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float2 body"); return Vec2f(xml->body[0].Float(),xml->body[1].Float()); } template<> Vec3f XMLLoader::load(const Ref& xml) { if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); return Vec3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); } template<> Vec3fa XMLLoader::load(const Ref& xml, const Vec3fa& opt) { if (xml == null) return opt; if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); } template<> Vec4f XMLLoader::load(const Ref& xml) { if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float4 body"); return Vec4f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float(),xml->body[3].Float()); } template<> AffineSpace3f XMLLoader::load(const Ref& xml) { if (xml->parm("translate") != "") { float x,y,z; sscanf(xml->parm("translate").c_str(),"%f %f %f",&x,&y,&z); return AffineSpace3f::translate(Vec3f(x,y,z)); } else if (xml->parm("scale") != "") { float x,y,z; sscanf(xml->parm("scale").c_str(),"%f %f %f",&x,&y,&z); return AffineSpace3f::scale(Vec3f(x,y,z)); } else if (xml->parm("rotate_x") != "") { float degrees; sscanf(xml->parm("rotate_x").c_str(),"%f",°rees); return AffineSpace3f::rotate(Vec3f(1,0,0),deg2rad(degrees)); } else if (xml->parm("rotate_y") != "") { float degrees; sscanf(xml->parm("rotate_y").c_str(),"%f",°rees); return AffineSpace3f::rotate(Vec3f(0,1,0),deg2rad(degrees)); } else if (xml->parm("rotate_z") != "") { float degrees; sscanf(xml->parm("rotate_z").c_str(),"%f",°rees); return AffineSpace3f::rotate(Vec3f(0,0,1),deg2rad(degrees)); } else if (xml->parm("rotate") != "" && xml->parm("axis") != "") { float degrees; sscanf(xml->parm("rotate").c_str(),"%f",°rees); float x,y,z; sscanf(xml->parm("axis").c_str(),"%f %f %f",&x,&y,&z); return AffineSpace3f::rotate(Vec3f(x,y,z),deg2rad(degrees)); } else { if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body"); return AffineSpace3f(LinearSpace3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[ 2].Float(), xml->body[4].Float(),xml->body[5].Float(),xml->body[ 6].Float(), xml->body[8].Float(),xml->body[9].Float(),xml->body[10].Float()), Vec3f(xml->body[3].Float(),xml->body[7].Float(),xml->body[11].Float())); } } char* XMLLoader::loadBinary(const Ref& xml, size_t eltSize, size_t& size) { if (!binFile) THROW_RUNTIME_ERROR("cannot open file "+binFileName.str()+" for reading"); size_t ofs = atol(xml->parm("ofs").c_str()); fseek(binFile,long(ofs),SEEK_SET); size = atol(xml->parm("size").c_str()); char* data = (char*) alignedMalloc(size*eltSize); if (size != fread(data, eltSize, size, binFile)) THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); return data; } std::vector XMLLoader::loadFloatArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; float* data = NULL; if (xml->parm("ofs") != "") { data = (float*)loadBinary(xml,sizeof(float),size); } else { size_t elts = xml->body.size(); size = elts; data = (float*) alignedMalloc(size*sizeof(float)); for (size_t i=0; ibody[i].Float(); } std::vector res; for (size_t i=0; i XMLLoader::loadVec2fArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; Vec2f* data = NULL; if (xml->parm("ofs") != "") { data = (Vec2f*)loadBinary(xml,2*sizeof(float),size); } else { size_t elts = xml->body.size(); if (elts % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); size = elts/2; data = (Vec2f*) alignedMalloc(size*sizeof(Vec2f)); for (size_t i=0; ibody[2*i+0].Float(),xml->body[2*i+1].Float()); } std::vector res; for (size_t i=0; i XMLLoader::loadVec3fArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; Vec3f* data = NULL; if (xml->parm("ofs") != "") { data = (Vec3f*) loadBinary(xml,3*sizeof(float),size); } else { size_t elts = xml->body.size(); if (elts % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); size = elts/3; data = (Vec3f*) alignedMalloc(size*sizeof(Vec3f)); for (size_t i=0; ibody[3*i+0].Float(),xml->body[3*i+1].Float(),xml->body[3*i+2].Float()); } std::vector res; for (size_t i=0; i XMLLoader::loadIntArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; int* data = NULL; if (xml->parm("ofs") != "") { data = (int*)loadBinary(xml,sizeof(int),size); } else { size_t elts = xml->body.size(); size = elts; data = (int*) alignedMalloc(size*sizeof(int)); for (size_t i=0; ibody[i].Int(); } std::vector res; for (size_t i=0; i XMLLoader::loadVec2iArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; Vec2i* data = NULL; if (xml->parm("ofs") != "") { data = (Vec2i*) loadBinary(xml,2*sizeof(int),size); } else { size_t elts = xml->body.size(); if (elts % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); size = elts/2; data = (Vec2i*) alignedMalloc(size*sizeof(Vec2i)); for (size_t i=0; ibody[2*i+0].Int(),xml->body[2*i+1].Int()); } std::vector res; for (size_t i=0; i XMLLoader::loadVec3iArray(const Ref& xml) { /*! do not fail of array does not exist */ if (!xml) { return std::vector(); } size_t size = 0; Vec3i* data = NULL; if (xml->parm("ofs") != "") { data = (Vec3i*) loadBinary(xml,3*sizeof(int),size); } else { size_t elts = xml->body.size(); if (elts % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); size = elts/3; data = (Vec3i*) alignedMalloc(size*sizeof(Vec3i)); for (size_t i=0; ibody[3*i+0].Int(),xml->body[3*i+1].Int(),xml->body[3*i+2].Int()); } std::vector res; for (size_t i=0; i& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa I = load(xml->child("I")); Vec3fa P = space.p; scene.pointLights.push_back(OBJScene::PointLight(P,I)); } void XMLLoader::loadSpotLight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa I = load(xml->child("I")); Vec3fa P = space.p; Vec3fa D = space.l.vz; float angleMin = load(xml->child("angleMin")); float angleMax = load(xml->child("angleMax")); } void XMLLoader::loadDirectionalLight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa E = load(xml->child("E")); Vec3fa D = space.l.vz; scene.directionalLights.push_back(OBJScene::DirectionalLight(D,E)); } void XMLLoader::loadDistantLight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa L = load(xml->child("L")); Vec3fa D = space.l.vz; float halfAngle = load(xml->child("halfAngle")); scene.distantLights.push_back(OBJScene::DistantLight(D,L,halfAngle)); } void XMLLoader::loadAmbientLight(const Ref& xml, const AffineSpace3f& space_in) { Vec3fa L = load(xml->child("L")); scene.ambientLights.push_back(OBJScene::AmbientLight(L)); } void XMLLoader::loadTriangleLight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa L = load(xml->child("L")); Vec3fa v0 = xfmPoint(space, Vec3fa(1, 0, 0)); Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); Vec3fa v2 = xfmPoint(space, Vec3fa(0, 0, 0)); } void XMLLoader::loadQuadLight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa L = load(xml->child("L")); Vec3fa v0 = xfmPoint(space, Vec3fa(0, 0, 0)); Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); Vec3fa v2 = xfmPoint(space, Vec3fa(1, 1, 0)); Vec3fa v3 = xfmPoint(space, Vec3fa(1, 0, 0)); } void XMLLoader::loadHDRILight(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->child("AffineSpace")); Vec3fa L = load(xml->child("L")); //image = rtLoadImage(path + load(xml->child("image")))); } Parms XMLLoader::loadMaterialParms(const Ref& parms) { Parms material; for (size_t i=0; ichildren.size(); i++) { Ref entry = parms->children[i]; std::string name = entry->parm("name"); if (entry->name == "int" ) { material.add(name,load (entry)); } else if (entry->name == "int2" ) { material.add(name, load(entry)); } else if (entry->name == "int3" ) { material.add(name, load(entry)); } else if (entry->name == "int4" ) { material.add(name, load(entry)); } else if (entry->name == "float" ) { material.add(name, load(entry)); } else if (entry->name == "float2" ) { material.add(name, load(entry)); } else if (entry->name == "float3" ) { material.add(name, load(entry)); } else if (entry->name == "float4" ) { material.add(name, load(entry)); } else if (entry->name == "texture") { material.add(name, (path + load(entry)).str()); } else THROW_RUNTIME_ERROR(entry->loc.str()+": invalid type: "+entry->name); } return material; } int XMLLoader::loadMaterial(const Ref& xml, std::string* name) { if (xml->parm("id") != "") { if (name) *name = xml->parm("id"); return materialMap[xml->parm("id")]; } Ref parameters = xml->child("parameters"); if (materialCache.find(parameters) != materialCache.end()) { return materialCache[parameters]; } std::string type = load(xml->child("code")).c_str(); Parms parms = loadMaterialParms(parameters); OBJScene::Material material; if (type == "Matte") { const Vec3fa reflectance = parms.getVec3fa("reflectance",one); new (&material) OBJScene::MatteMaterial(reflectance); } else if (type == "Mirror") { const Vec3fa reflectance = parms.getVec3fa("reflectance",one); new (&material) OBJScene::MirrorMaterial(reflectance); } else if (type == "OBJ") { //map_d = parms.getTexture("map_d"); const float d = parms.getFloat("d", 1.0f); //map_Kd = parms.getTexture("map_Kd"); const Vec3fa Kd = parms.getVec3fa("Kd", one); //map_Ks = parms.getTexture("map_Ks"); const Vec3fa Ks = parms.getVec3fa("Ks", zero); //map_Ns = parms.getTexture("map_Ns"); const float Ns = parms.getFloat("Ns", 10.0f); //map_Bump = parms.getTexture("map_Bump"); new (&material) OBJScene::OBJMaterial(d,Kd,Ks,Ns); } else if (type == "ThinDielectric" || type == "ThinGlass") { const Vec3fa transmission = parms.getVec3fa("transmission",one); const float eta = parms.getFloat("eta",1.4f); const float thickness = parms.getFloat("thickness",0.1f); new (&material) OBJScene::ThinDielectricMaterial(transmission,eta,thickness); } else if (type == "Plastic") { const Vec3fa pigmentColor = parms.getVec3fa("pigmentColor",one); const float eta = parms.getFloat("eta",1.4f); const float roughness = parms.getFloat("roughness",0.01f); new (&material) OBJScene::MetallicPaintMaterial(pigmentColor,pigmentColor,roughness,eta); } else if (type == "Metal") { const Vec3fa reflectance = parms.getVec3fa("reflectance",one); const Vec3fa eta = parms.getVec3fa("eta",Vec3fa(1.4f)); const Vec3fa k = parms.getVec3fa("k",Vec3fa(0.0f)); const float roughness = parms.getFloat("roughness",0.01f); if (roughness == 0.0f) new (&material) OBJScene::MetalMaterial(reflectance,eta,k); else new (&material) OBJScene::MetalMaterial(reflectance,eta,k,roughness); } else if (type == "Velvet") { const Vec3fa reflectance = parms.getVec3fa("reflectance",one); const float backScattering = parms.getFloat("backScattering",zero); const Vec3fa horizonScatteringColor = parms.getVec3fa("horizonScatteringColor",one); const float horizonScatteringFallOff = parms.getFloat("horizonScatteringFallOff",zero); new (&material) OBJScene::VelvetMaterial(reflectance,backScattering,horizonScatteringColor,horizonScatteringFallOff); } else if (type == "Dielectric") { const Vec3fa transmissionOutside = parms.getVec3fa("transmissionOutside",one); const Vec3fa transmissionInside = parms.getVec3fa("transmission",one); const float etaOutside = parms.getFloat("etaOutside",1.0f); const float etaInside = parms.getFloat("etaInside",1.4f); new (&material) OBJScene::DielectricMaterial(transmissionOutside,transmissionInside,etaOutside,etaInside); } else if (type == "MetallicPaint") { const Vec3fa shadeColor = parms.getVec3fa("shadeColor",one); const Vec3fa glitterColor = parms.getVec3fa("glitterColor",zero); const float glitterSpread = parms.getFloat("glitterSpread",1.0f); const float eta = parms.getFloat("eta",1.4f); new (&material) OBJScene::MetallicPaintMaterial(shadeColor,glitterColor,glitterSpread,eta); } else { std::cout << "Warning: unsupported material " << type << std::endl; new (&material) OBJScene::OBJMaterial(1.0f,0.5f,0.0f,0.0f); } int materialID = scene.materials.size(); scene.materials.push_back(material); materialCache[parameters] = materialID; return materialID; } void XMLLoader::loadSubdivMesh(const Ref& xml, const AffineSpace3f& space) { std::string materialName; int materialID = loadMaterial(xml->child("material"),&materialName); OBJScene::SubdivMesh* mesh = new OBJScene::SubdivMesh; std::vector positions = loadVec3fArray(xml->childOpt("positions")); for (size_t i=0; ipositions.push_back(xfmPoint(space,positions[i])); std::vector normals = loadVec3fArray(xml->childOpt("normals")); for (size_t i=0; inormals.push_back(xfmNormal(space,normals[i])); mesh->texcoords = loadVec2fArray(xml->childOpt("texcoords")); mesh->position_indices = loadIntArray(xml->childOpt("position_indices")); mesh->normal_indices = loadIntArray(xml->childOpt("normal_indices")); mesh->texcoord_indices = loadIntArray(xml->childOpt("texcoord_indices")); mesh->verticesPerFace = loadIntArray(xml->childOpt("faces")); mesh->holes = loadIntArray(xml->childOpt("holes")); mesh->edge_creases = loadVec2iArray(xml->childOpt("edge_creases")); mesh->edge_crease_weights = loadFloatArray(xml->childOpt("edge_crease_weights")); mesh->vertex_creases = loadIntArray(xml->childOpt("vertex_creases")); mesh->vertex_crease_weights = loadFloatArray(xml->childOpt("vertex_crease_weights")); mesh->materialID = materialID; scene.subdiv.push_back(mesh); } void XMLLoader::loadTriangleMesh(const Ref& xml, const AffineSpace3f& space) { std::string materialName; int materialID = loadMaterial(xml->child("material"),&materialName); std::vector positions = loadVec3fArray(xml->childOpt("positions")); std::vector motions = loadVec3fArray(xml->childOpt("motions" )); std::vector normals = loadVec3fArray(xml->childOpt("normals" )); std::vector texcoords = loadVec2fArray(xml->childOpt("texcoords")); std::vector triangles = loadVec3iArray(xml->childOpt("triangles")); OBJScene::Mesh* mesh = new OBJScene::Mesh; for (size_t i=0; iv.push_back(xfmPoint(space,positions[i])); for (size_t i=0; ivn.push_back(xfmVector(space,normals[i])); for (size_t i=0; ivt.push_back(texcoords[i]); for (size_t i=0; itriangles.push_back(OBJScene::Triangle(triangles[i].x,triangles[i].y,triangles[i].z,materialID)); scene.meshes.push_back(mesh); } void XMLLoader::loadSphere(const Ref& xml, const AffineSpace3f& space) { std::cout << "Warning: ignoring sphere" << std::endl; } void XMLLoader::loadDisk(const Ref& xml, const AffineSpace3f& space) { std::cout << "Warning: ignoring disk" << std::endl; } void XMLLoader::loadTransformNode(const Ref& xml, const AffineSpace3f& space_in) { AffineSpace3f space = space_in*load(xml->children[0]); for (size_t i=1; ichildren.size(); i++) loadScene(xml->children[i],space); } void XMLLoader::loadGroupNode(const Ref& xml, const AffineSpace3f& space) { for (size_t i=0; ichildren.size(); i++) loadScene(xml->children[i],space); } ////////////////////////////////////////////////////////////////////////////// //// Loading of scene graph node from XML file ////////////////////////////////////////////////////////////////////////////// void XMLLoader::loadScene(const Ref& xml, const AffineSpace3f& space) { if (xml->name == "assign") { if (xml->parm("type") == "material") materialMap[xml->parm("id")] = loadMaterial(xml->child(0)); //else if (xml->parm("type") == "scene") //sceneMap[xml->parm("id")] = loadScene(xml->child(0)); else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown type: "+xml->parm("type")); } else { if (xml->name == "xml") { loadXML(path + xml->parm("src"),space,scene); } else if (xml->name == "obj") { loadOBJ(path + xml->parm("src"),space,scene); } else if (xml->name == "extern") { FileName fname = path + xml->parm("src"); if (fname.ext() == "xml") loadXML(path + xml->parm("src"),space,scene); else if (fname.ext() == "obj") loadOBJ(path + xml->parm("src"),space,scene); else THROW_RUNTIME_ERROR("unknown file type:" + fname.str()); } //else if (xml->name == "ref") { // prims = sceneMap[xml->parm("id")]; // for (size_t i=0; irtTransformPrimitive(prims[i],copyToArray(transforms.top())); //} else if (xml->name == "PointLight" ) loadPointLight (xml,space); else if (xml->name == "SpotLight" ) loadSpotLight (xml,space); else if (xml->name == "DirectionalLight") loadDirectionalLight(xml,space); else if (xml->name == "DistantLight" ) loadDistantLight (xml,space); else if (xml->name == "AmbientLight" ) loadAmbientLight (xml,space); else if (xml->name == "TriangleLight" ) loadTriangleLight (xml,space); else if (xml->name == "QuadLight" ) loadQuadLight (xml,space); else if (xml->name == "HDRILight" ) loadHDRILight (xml,space); else if (xml->name == "TriangleMesh" ) loadTriangleMesh (xml,space); else if (xml->name == "SubdivisionMesh" ) loadSubdivMesh (xml,space); else if (xml->name == "Sphere" ) loadSphere (xml,space); else if (xml->name == "Disk" ) loadDisk (xml,space); else if (xml->name == "Group" ) loadGroupNode (xml,space); else if (xml->name == "Transform" ) loadTransformNode (xml,space); else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); } } XMLLoader::XMLLoader(const FileName& fileName, const AffineSpace3f& space, OBJScene& scene) : binFile(NULL), scene(scene) { path = fileName.path(); binFileName = fileName.setExt(".bin"); binFile = fopen(binFileName.c_str(),"rb"); Ref xml = parseXML(fileName); if (xml->name != "scene") THROW_RUNTIME_ERROR(xml->loc.str()+": invalid scene tag"); for (size_t i=0; ichildren.size(); i++) { loadScene(xml->children[i],space); } } XMLLoader::~XMLLoader() { if (binFile) fclose(binFile); } /*! read from disk */ void loadXML(const FileName& fileName, const AffineSpace3f& space, OBJScene& scene) { XMLLoader loader(fileName,space,scene); } }