summaryrefslogtreecommitdiff
path: root/hw3/src/sceneIO_material.cpp
blob: 018e913d570786b733d3e1a4b87891adbf63947f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/******************************************************************/
/* 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_material.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));
  
  // create & return parameter, give preference to textured parameters
  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);

  // create & return parameter, give preference to textured parameters
  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> 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 != "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 == "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;
}