summaryrefslogblamecommitdiff
path: root/hw6/src/sceneIO_material.cpp
blob: 7999eca85f972c771848fa643a356b4a6beb507a (plain) (tree)


















































































































































































































































                                                                                                                                                                                            
/******************************************************************/
/* 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 <cassert>

#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_base>& 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<const texture_base> 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_base>& 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<const texture_base> 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<shader_base> importDiffuse(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& 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<shader_base>(new diffuseReflectanceShader(albedo));
}

//////////////////////////////////////////////////////////////
static std::shared_ptr<shader_base> importPhong(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& 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<shader_base>(new phongReflectanceShader(albedo, sharpness));
}

//////////////////////////////////////////////////////////////
static std::shared_ptr<shader_base> importCompoundMaterial(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir)
{
  // sanity check
  assert(node.isValid() && node.name() == "material");

  // storage for child material nodes
  std::vector<std::shared_ptr<const shader_base>> shader_list;

  // for each child
  for(XMLNode child = node.firstChild(); child.isValid(); child++)
  {
    // try to import material
    std::shared_ptr<shader_base> 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<shader_base>(new compoundShader(shader_list));
}

//////////////////////////////////////////////////////////////
std::shared_ptr<shader_base> importNormalMap(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir)
{
  // sanity check
  assert(getString(node, "type") == "normalMap");

  // parameter storage
  std::shared_ptr<const shader_base> shader;
  std::shared_ptr<const texture_base> 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<shader_base>(new normalMap(map, shader));
}

//////////////////////////////////////////////////////////////
std::shared_ptr<shader_base> importBumpMap(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& 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<const shader_base> shader;
  std::shared_ptr<const texture_base> 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<shader_base>(new bumpMap(map, scale, channel, shader));
}

//////////////////////////////////////////////////////////////
std::shared_ptr<shader_base> importShadingFrameTransformation(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& 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<shader_base> 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<shader_base> importMaterial(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& 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<shader_base>(nullptr);

  // check if reference
  std::string ref = getString(node, "ref");
  std::shared_ptr<shader_base> 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;
}