/******************************************************************/ /* This file is part of the homework assignments for CSCI-427/527 */ /* at The College of William & Mary and authored by Pieter Peers. */ /* No part of this file, whether altered or in original form, can */ /* be distributed or used outside the context of CSCI-427/527 */ /* without consent of either the College of William & Mary or */ /* Pieter Peers. */ /******************************************************************/ #include #include "sceneIO_xml.h" #include "sceneIO_core.h" #include "sceneIO_texture.h" #include "sceneIO_material.h" #include "bumpMap.h" #include "normalMap.h" #include "compoundShader.h" #include "reflectanceParameter.h" #include "phongReflectanceShader.h" #include "diffuseReflectanceShader.h" ////////////////////////////////////////////////////////////// static colorReflectanceParameter importColorReflectanceParameter(const XMLNode& node, nodeCache& texture_cache, const std::string& rootDir) { // get parameter color value = getColor(node, "value", color(0.0f, 0.0f, 0.0f)); // check for texture std::shared_ptr texture = importTexture(node.firstChild(), texture_cache, rootDir); // create & return parameter, give preference to textured parameters if(texture) return colorReflectanceParameter(texture); else return colorReflectanceParameter(value); // Done. } ////////////////////////////////////////////////////////////// static scalarReflectanceParameter importScalarReflectanceParameter(const XMLNode& node, nodeCache& texture_cache, const std::string& rootDir) { // get parameters float value = getFloat(node, "value", 0.0f); unsigned int channel = getInteger(node, "channel", 0); // check for texture std::shared_ptr texture = importTexture(node.firstChild(), texture_cache, rootDir); // create & return parameter, give preference to textured parameters if(texture) return scalarReflectanceParameter(texture, channel); else return scalarReflectanceParameter(value); // Done. } ////////////////////////////////////////////////////////////// static std::shared_ptr importDiffuse(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(node.name() == "diffuse"); // parameter storage colorReflectanceParameter albedo; // check child nodes for(XMLNode child=node.firstChild(); child.isValid(); child++) { std::string name = child.name(); if(name == "albedo") albedo = importColorReflectanceParameter(child, texture_cache, rootDir); else errorMessage("Unknown parameter in diffuse-node (%s).", name.c_str()); } // Done. return std::shared_ptr(new diffuseReflectanceShader(albedo)); } ////////////////////////////////////////////////////////////// static std::shared_ptr importPhong(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(node.name() == "phong"); // parameter storage colorReflectanceParameter albedo; scalarReflectanceParameter sharpness; // check child nodes for(XMLNode child=node.firstChild(); child.isValid(); child++) { std::string name = child.name(); if(name == "albedo") albedo = importColorReflectanceParameter(child, texture_cache, rootDir); else if(name == "sharpness") sharpness = importScalarReflectanceParameter(child, texture_cache, rootDir); else errorMessage("Unknown parameter in phong-node (%s).", name.c_str()); } // Done. return std::shared_ptr(new phongReflectanceShader(albedo, sharpness)); } ////////////////////////////////////////////////////////////// static std::shared_ptr importCompoundMaterial(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(node.isValid() && node.name() == "material"); // storage for child material nodes std::vector> shader_list; // for each child for(XMLNode child = node.firstChild(); child.isValid(); child++) { // try to import material std::shared_ptr shader = importMaterial(child, shader_cache, texture_cache, rootDir); // add to list if successful. if(shader) shader_list.push_back(shader); else errorMessage("Unknown material-node (%s).", child.name().c_str()); } // Done. return std::shared_ptr(new compoundShader(shader_list)); } ////////////////////////////////////////////////////////////// std::shared_ptr importNormalMap(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(getString(node, "type") == "normalMap"); // parameter storage std::shared_ptr shader; std::shared_ptr map; // process child nodes for(XMLNode child=node.firstChild(); child.isValid(); child++) { // process specific nodes if(child.name() == "texture") map = importTexture(child, texture_cache, rootDir); // process general shader nodes else if(!shader) shader = importMaterial(child, shader_cache, texture_cache, rootDir); else if(!shader) errorMessage("Unknown node in normalMap (%s).", child.name().c_str()); } // check if shader & texture was specified if(!shader) errorMessage("NormalMap requires a shader."); if(!map) errorMessage("NormalMap requires a texture."); // Done. return std::shared_ptr(new normalMap(map, shader)); } ////////////////////////////////////////////////////////////// std::shared_ptr importBumpMap(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(getString(node, "type") == "bumpMap"); // obtain parameters float scale = getFloat(node, "scale", 1.0f); unsigned int channel = getInteger(node, "channel", 0); // parameter storage std::shared_ptr shader; std::shared_ptr map; // process child nodes for(XMLNode child=node.firstChild(); child.isValid(); child++) { // process specific nodes if(child.name() == "texture") map = importTexture(child, texture_cache, rootDir); // process general shader nodes else if(!shader) shader = importMaterial(child, shader_cache, texture_cache, rootDir); else if(!shader) errorMessage("Unknown node in bumpMap (%s).", child.name().c_str()); } // check if shader & texture was specified if(!shader) errorMessage("BumpMap requires a shader."); if(!map) errorMessage("BumpMap requires a texture."); // Done. return std::shared_ptr(new bumpMap(map, scale, channel, shader)); } ////////////////////////////////////////////////////////////// std::shared_ptr importShadingFrameTransformation(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { // sanity check assert(node.name() == "shadingFrameTransformation"); // get type std::string type = getString(node, "type", "none specified"); // specialize based on type std::shared_ptr sft; if(type == "normalMap") sft = importNormalMap(node, shader_cache, texture_cache, rootDir); else if(type == "bumpMap") sft = importBumpMap(node, shader_cache, texture_cache, rootDir); else errorMessage("Unknown shadingFrameTransformation type (%s).", type.c_str()); // Done. return sft; } ////////////////////////////////////////////////////////////// std::shared_ptr importMaterial(const XMLNode& node, nodeCache& shader_cache, nodeCache& texture_cache, const std::string& rootDir) { std::string name = node.name(); // check material type if(name != "material" && name != "shadingFrameTransformation" && name != "diffuse" && name != "phong") return std::shared_ptr(nullptr); // check if reference std::string ref = getString(node, "ref"); std::shared_ptr shader = shader_cache.get(ref); if(shader) return shader; else if(ref != "") errorMessage("Unknown %s name (%s).", name.c_str(), ref.c_str()); // get id std::string id = getString(node, "id"); if(shader_cache.get(id)) errorMessage("%s-id is not unique (%s).", name.c_str(), id.c_str()); // process primitives based on type if(name == "material") shader = importCompoundMaterial(node, shader_cache, texture_cache, rootDir); else if(name == "shadingFrameTransformation") shader = importShadingFrameTransformation(node, shader_cache, texture_cache, rootDir); else if(name == "diffuse") shader = importDiffuse(node, shader_cache, texture_cache, rootDir); else if(name == "phong") shader = importPhong(node, shader_cache, texture_cache, rootDir); else errorMessage("Unknown material-node (%s).", name.c_str()); // update cache if(id != "") shader_cache.add(id, shader); // Done. return shader; }