summaryrefslogtreecommitdiff
path: root/hw3
diff options
context:
space:
mode:
author53hornet <53hornet@gmail.com>2019-02-02 23:33:15 -0500
committer53hornet <53hornet@gmail.com>2019-02-02 23:33:15 -0500
commitdb072ad4dc181eca5a1458656b130beb43f475bf (patch)
treea3c03c7f5497cb70503e2486662fa85cfb53415a /hw3
downloadcsci427-master.tar.xz
csci427-master.zip
Diffstat (limited to 'hw3')
-rw-r--r--hw3/.gitignore5
-rw-r--r--hw3/CMakeLists.txt71
-rw-r--r--hw3/bin/HW1.cpp38
-rw-r--r--hw3/bin/HW2.cpp112
-rw-r--r--hw3/bin/HW3.cpp90
-rw-r--r--hw3/bin/helloworld.cpp9
-rw-r--r--hw3/bin/image_compare.cpp90
-rw-r--r--hw3/data/HW3-scene1.xml23
-rw-r--r--hw3/data/HW3-scene2.xml24
-rw-r--r--hw3/data/HW3-scene3.xml18
-rw-r--r--hw3/data/HW3-scene4.xml19
-rw-r--r--hw3/data/HW3-scene5.xml22
-rw-r--r--hw3/data/HW3-scene6.xml22
-rw-r--r--hw3/data/HW3-scene7.xml19
-rw-r--r--hw3/data/HW3-scene8.xml20
-rw-r--r--hw3/data/cube.obj26
-rw-r--r--hw3/data/sphere.obj1834
-rw-r--r--hw3/include/.directory4
-rw-r--r--hw3/include/boundedCompound.h55
-rw-r--r--hw3/include/boundedPrimitive.h67
-rw-r--r--hw3/include/boundedTriangle.h46
-rw-r--r--hw3/include/boundingBox.h77
-rw-r--r--hw3/include/brdf_base.h47
-rw-r--r--hw3/include/camera.h80
-rw-r--r--hw3/include/color.h105
-rw-r--r--hw3/include/compoundShader.h51
-rw-r--r--hw3/include/constants.h16
-rw-r--r--hw3/include/coordinateTransform.h31
-rw-r--r--hw3/include/diffuseBrdf.h59
-rw-r--r--hw3/include/diffuseReflectanceShader.h45
-rw-r--r--hw3/include/directionalLightsource.h55
-rw-r--r--hw3/include/errorMessage.h17
-rw-r--r--hw3/include/image.h89
-rw-r--r--hw3/include/imageIO.h19
-rw-r--r--hw3/include/imageIO.pfm.h18
-rw-r--r--hw3/include/imageIO.ppm.h18
-rw-r--r--hw3/include/importOBJ.h18
-rw-r--r--hw3/include/intersectionPoint.h110
-rw-r--r--hw3/include/intersector_base.h34
-rw-r--r--hw3/include/intersector_factory_base.h29
-rw-r--r--hw3/include/interval.h77
-rw-r--r--hw3/include/lightSample.h75
-rw-r--r--hw3/include/lightsource_base.h51
-rw-r--r--hw3/include/linear_intersector.h62
-rw-r--r--hw3/include/mat3d.h112
-rw-r--r--hw3/include/phongBrdf.h60
-rw-r--r--hw3/include/phongReflectanceShader.h46
-rw-r--r--hw3/include/random_number.h50
-rw-r--r--hw3/include/ray.h69
-rw-r--r--hw3/include/reflectanceParameter.h106
-rw-r--r--hw3/include/reflectanceShader_base.h45
-rw-r--r--hw3/include/scene.h59
-rw-r--r--hw3/include/sceneGraphNode.h45
-rw-r--r--hw3/include/sceneIO.h17
-rw-r--r--hw3/include/sceneIO_basis.h22
-rw-r--r--hw3/include/sceneIO_cache.h52
-rw-r--r--hw3/include/sceneIO_cache.inline.h66
-rw-r--r--hw3/include/sceneIO_core.h24
-rw-r--r--hw3/include/sceneIO_geometry.h23
-rw-r--r--hw3/include/sceneIO_light.h25
-rw-r--r--hw3/include/sceneIO_material.h22
-rw-r--r--hw3/include/sceneIO_xml.h51
-rw-r--r--hw3/include/shaderProperties.h38
-rw-r--r--hw3/include/shader_base.h59
-rw-r--r--hw3/include/shadingFrameTransformation.h57
-rw-r--r--hw3/include/texture_base.h67
-rw-r--r--hw3/include/tinyxml2.h2102
-rw-r--r--hw3/include/transformation3d.h77
-rw-r--r--hw3/include/triangle.h115
-rw-r--r--hw3/include/triangleMesh.h51
-rw-r--r--hw3/include/util.h19
-rw-r--r--hw3/include/vec2d.h117
-rw-r--r--hw3/include/vec3d.h120
-rw-r--r--hw3/src/.directory4
-rw-r--r--hw3/src/boundedCompound.cpp93
-rw-r--r--hw3/src/boundedPrimitive.cpp50
-rw-r--r--hw3/src/boundedTriangle.cpp53
-rw-r--r--hw3/src/boundingBox.cpp185
-rw-r--r--hw3/src/camera.cpp150
-rw-r--r--hw3/src/color.cpp233
-rw-r--r--hw3/src/compoundShader.cpp60
-rw-r--r--hw3/src/coordinateTransform.cpp67
-rw-r--r--hw3/src/diffuseBrdf.cpp88
-rw-r--r--hw3/src/diffuseReflectanceShader.cpp35
-rw-r--r--hw3/src/directionalLightsource.cpp38
-rw-r--r--hw3/src/errorMessage.cpp34
-rw-r--r--hw3/src/image.cpp122
-rw-r--r--hw3/src/imageIO.cpp46
-rw-r--r--hw3/src/imageIO.pfm.cpp87
-rw-r--r--hw3/src/imageIO.ppm.cpp106
-rw-r--r--hw3/src/importOBJ.cpp152
-rw-r--r--hw3/src/intersectionPoint.cpp309
-rw-r--r--hw3/src/interval.cpp154
-rw-r--r--hw3/src/lightSample.cpp121
-rw-r--r--hw3/src/linear_intersector.cpp49
-rw-r--r--hw3/src/mat3d.cpp260
-rw-r--r--hw3/src/phongBrdf.cpp99
-rw-r--r--hw3/src/phongReflectanceShader.cpp36
-rw-r--r--hw3/src/ray.cpp83
-rw-r--r--hw3/src/reflectanceParameter.cpp140
-rw-r--r--hw3/src/reflectanceShader_base.cpp39
-rw-r--r--hw3/src/scene.cpp42
-rw-r--r--hw3/src/sceneGraphNode.cpp39
-rw-r--r--hw3/src/sceneIO.cpp87
-rw-r--r--hw3/src/sceneIO_basis.cpp51
-rw-r--r--hw3/src/sceneIO_core.cpp99
-rw-r--r--hw3/src/sceneIO_geometry.cpp153
-rw-r--r--hw3/src/sceneIO_light.cpp51
-rw-r--r--hw3/src/sceneIO_material.cpp147
-rw-r--r--hw3/src/sceneIO_xml.cpp109
-rw-r--r--hw3/src/shaderProperties.cpp59
-rw-r--r--hw3/src/tinyxml2.cpp2466
-rw-r--r--hw3/src/transformation3d.cpp174
-rw-r--r--hw3/src/triangle.cpp465
-rw-r--r--hw3/src/triangleMesh.cpp57
-rw-r--r--hw3/src/util.cpp45
-rw-r--r--hw3/src/vec2d.cpp258
-rw-r--r--hw3/src/vec3d.cpp287
118 files changed, 14995 insertions, 0 deletions
diff --git a/hw3/.gitignore b/hw3/.gitignore
new file mode 100644
index 0000000..f64613c
--- /dev/null
+++ b/hw3/.gitignore
@@ -0,0 +1,5 @@
+Debug
+Release
+Reference
+*.ppm
+
diff --git a/hw3/CMakeLists.txt b/hw3/CMakeLists.txt
new file mode 100644
index 0000000..984cdf2
--- /dev/null
+++ b/hw3/CMakeLists.txt
@@ -0,0 +1,71 @@
+##################
+# Initialization #
+##################
+# Project name is not mandatory, but you should use it
+project(CSCI427)
+
+# States that CMake required version must be >= 2.6
+cmake_minimum_required(VERSION 2.6)
+
+#####################
+# Setup Environment #
+#####################
+# set to include custom modules
+set(CMAKE_MODULE_PATH $ENV{CMAKE_MODULE_PATH} ${CSCI427_SOURCE_DIR}/cmake)
+
+# set build type if specified by environment
+if((NOT CMAKE_BUILD_TYPE) AND (NOT $ENV{CMAKE_BUILD_TYPE} STREQUAL ""))
+ set(CMAKE_BUILD_TYPE $ENV{CMAKE_BUILD_TYPE})
+endif()
+
+# Set include directories
+include_directories(${CSCI427_SOURCE_DIR}/include)
+
+# Get CPP files
+file(GLOB SRC ${CSCI427_SOURCE_DIR}/src/*cpp)
+
+# Get executable files
+file(GLOB EXECLIST ${CSCI427_SOURCE_DIR}/bin/*cpp)
+
+
+###############
+# C++ Options #
+###############
+# Enable C++11
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+# determine build type based on directory name. Do not allow for in source building
+#
+if(${CSCI427_SOURCE_DIR} STREQUAL ${CSCI427_BINARY_DIR})
+ message(FATAL_ERROR " *** In-source building not allowed. Please create a subdir 'Release' or 'Debug', and run cmake from within this directory 'cmake ..' ***")
+else()
+ get_filename_component(TYPE ${CSCI427_BINARY_DIR} NAME)
+ string(TOUPPER "${TYPE}" TYPE)
+ if(${TYPE} STREQUAL "RELEASE")
+ set(CMAKE_BUILD_TYPE Release)
+ else()
+ set(CMAKE_BUILD_TYPE Debug)
+ endif()
+ message("-- Build type set to: ${TYPE}")
+endif()
+
+#######################
+# Set Compile Targets #
+#######################
+# src libraries
+if(NOT SRC STREQUAL "")
+ set(LIBNAME "427_core")
+ add_library(${LIBNAME} ${SRC})
+endif()
+
+# executables
+foreach(EXEC ${EXECLIST})
+ get_filename_component(EXECNAME ${EXEC} NAME_WE)
+ add_executable(${EXECNAME} ${EXEC})
+
+ if(NOT SRC STREQUAL "")
+ target_link_libraries(${EXECNAME} LINK_PUBLIC ${LIBNAME})
+ endif()
+
+ message("-- Adding executable: ${EXECNAME}")
+endforeach(EXEC)
diff --git a/hw3/bin/HW1.cpp b/hw3/bin/HW1.cpp
new file mode 100644
index 0000000..8e66297
--- /dev/null
+++ b/hw3/bin/HW1.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include "vec3d.h"
+
+int main(int argc, char** argv)
+{
+ std::cout << "CSCI-427/527 Homework 1: Vectors" << std::endl;
+
+ vec3d a(1.0f, 0.0f, -1.0f);
+ vec3d b(-1.0f, 1.0f, 1.0f);
+
+ std::cout << "a = " << a << std::endl;
+ std::cout << "b = " << b << std::endl;
+
+ std::cout << "a+b = " << a+b << std::endl;
+ std::cout << "a-b = " << a-b << std::endl;
+ std::cout << "a*b = " << a*b << std::endl;
+ std::cout << "a/b = " << a/b << std::endl;
+ std::cout << "a*2 = " << a*2.0f << std::endl;
+ std::cout << "b/2 = " << b/2.0f << std::endl;
+
+ std::cout << "a.dot(b) = " << a.dot(b) << std::endl;
+ std::cout << "b.dot(a) = " << b.dot(a) << std::endl;
+ std::cout << "a.squared_length() = " << a.squared_length() << std::endl;
+ std::cout << "b.length() = " << b.length() << std::endl;
+ std::cout << "a.distance(b) = " << a.distance(b) << std::endl;
+ std::cout << "a.cross(b) = " << a.cross(b) << std::endl;
+ std::cout << "b.cross(a) = " << b.cross(a) << std::endl;
+ std::cout << "normalize(a) = " << normalize(a) << std::endl;
+ std::cout << "abs(a) = " << abs(a) << std::endl;
+ std::cout << "b.normalize() = " << b.normalize() << std::endl;
+ std::cout << "b.abs() = " << b.abs() << std::endl;
+
+ std::cout << "a = " << a << std::endl;
+ std::cout << "b = " << b << std::endl;
+
+ // Done.
+ return 0;
+}
diff --git a/hw3/bin/HW2.cpp b/hw3/bin/HW2.cpp
new file mode 100644
index 0000000..70be45b
--- /dev/null
+++ b/hw3/bin/HW2.cpp
@@ -0,0 +1,112 @@
+#include <iostream>
+
+#include "image.h"
+#include "camera.h"
+#include "imageIO.h"
+#include "triangle.h"
+
+image generateImage(const camera& cam, const triangle& tri)
+{
+ float t;
+ vec3d barycentricCoord;
+ image result(cam.width(), cam.height());
+
+ // for each pixel
+ for(image::size_type y=0; y < result.height(); y++)
+ for(image::size_type x=0; x < result.width(); x++)
+ {
+ // generate view ray
+ ray r = cam(x,y);
+
+ // intersect triangle
+ bool hit = tri.intersect(r, barycentricCoord, t);
+
+ // draw pixel
+ if(hit)
+ result(x,y) = color(barycentricCoord.x, barycentricCoord.y, barycentricCoord.z);
+ else
+ result(x,y) = color(0.0f, 0.0f, 0.0f);
+ }
+
+ // Done.
+ return result;
+}
+
+int main(int argc, char** argv)
+{
+ // setup camera
+ camera cam( vec3d(0.0f, 0.0f, 0.0f),
+ vec3d(0.0f, 0.0f, -1.0f),
+ vec3d(0.0f, 1.0f, 0.0f),
+ 60.0f,
+ 512, 512 );
+
+ // Image 1
+ std::cout << "Generating image 1." << std::endl;
+
+ triangle t1( vec3d(1.0f, -1.0f, -2.0f),
+ vec3d(0.0f, 1.0f, -2.0f),
+ vec3d(-1.0f, -1.0f, -2.0f) );
+
+ image result1 = generateImage(cam, t1);
+ exportImage("hw2-result1.ppm", result1);
+
+
+ // Image 2
+ std::cout << "Generating image 2." << std::endl;
+
+ triangle t2( vec3d(1.0f, -1.0f, 2.0f),
+ vec3d(0.0f, 1.0f, 2.0f),
+ vec3d(-1.0f, -1.0f, 2.0f) );
+
+ image result2 = generateImage(cam, t2);
+ exportImage("hw2-result2.ppm", result2);
+
+
+ // Image 3
+ std::cout << "Generating image 3." << std::endl;
+
+ triangle t3( vec3d(-1.0f, -1.0f, -2.0f),
+ vec3d(1.0f, -1.0f, -2.0f),
+ vec3d(0.0f, 1.0f, -2.0f) );
+
+ image result3 = generateImage(cam, t3);
+ exportImage("hw2-result3.ppm", result3);
+
+
+ // Image 4
+ std::cout << "Generating image 4." << std::endl;
+
+ triangle t4( vec3d(-1.0f, -1.0f, 2.0f),
+ vec3d(0.0f, 1.0f, 2.0f),
+ vec3d(1.0f, -1.0f, 2.0f) );
+
+ image result4 = generateImage(cam, t4);
+ exportImage("hw2-result4.ppm", result4);
+
+
+ // Image 5
+ std::cout << "Generating image 5." << std::endl;
+
+ triangle t5( vec3d(-1.0f, -1.0f, -1.0f),
+ vec3d(1.0f, -1.0f, -1.0f),
+ vec3d(1.0f, 1.0f, -1.0f) );
+
+ image result5 = generateImage(cam, t5);
+ exportImage("hw2-result5.ppm", result5);
+
+
+ // Image 6
+ std::cout << "Generating image 6." << std::endl;
+
+ triangle t6( vec3d(-1.0f, 2.0f, -1.0f),
+ vec3d(0.0f, 2.0f, 1.0f),
+ vec3d(1.0f, 2.0f, -1.0f) );
+
+ image result6 = generateImage(cam, t6);
+ exportImage("hw2-result6.ppm", result6);
+
+
+ // Done.
+ return 0;
+}
diff --git a/hw3/bin/HW3.cpp b/hw3/bin/HW3.cpp
new file mode 100644
index 0000000..4dbb9e6
--- /dev/null
+++ b/hw3/bin/HW3.cpp
@@ -0,0 +1,90 @@
+#include <string>
+#include <chrono>
+#include <iostream>
+
+#include "util.h"
+#include "image.h"
+#include "scene.h"
+#include "imageIO.h"
+#include "sceneIO.h"
+
+image generateImage(const scene& s)
+{
+ image result(s.getCamera().width(), s.getCamera().height());
+
+ // for every pixel
+ for(image::size_type y=0; y < result.height(); y++)
+ for(image::size_type x=0; x < result.width(); x++)
+
+ // For debugging -- render a single delinquent pixel.
+ // for (image::size_type y=41; y < 42; y++)
+ // for (image::size_type x=126; x < 127; x++)
+ {
+ // generate view ray
+ ray r = s.getCamera()(x,y);
+
+ // intersect scene
+ intersectionPoint ip = s.intersect(r);
+
+ // shade pixel
+ if(ip.isHit())
+ {
+ // for each light source
+ for(unsigned int l=0; l < s.numberOfLightsources(); l++)
+ {
+ // connect to light source
+ lightSample ls = s.getLightsource(l).intensityAt(ip.position());
+
+ // shade
+ result(x,y) += ip.shade(ls);
+ }
+ }
+ else result(x,y) = color(0.0f, 0.0f, 0.0f);
+ }
+
+
+ // Done.
+ return result;
+}
+
+
+
+int main(int argc, char** argv)
+{
+ // parse command line
+ if(argc < 2)
+ {
+ std::cout << "Usage: " << argv[0] << " <scene.xml> [scene2.xml ...]" << std::endl;
+ return -1;
+ }
+
+ // for each filename, import scene and render
+ unsigned int pos=1;
+ while(pos < argc)
+ {
+ // get filename
+ std::string filename = argv[pos++];
+
+ // import
+ std::cerr << " * Reading " << filename << std::endl;
+ scene s;
+ importScene(filename, s);
+
+ // render
+ std::cerr << " * Rendering... ";
+ auto startTime = std::chrono::system_clock::now();
+
+ image result = generateImage(s);
+
+ auto endTime = std::chrono::system_clock::now();
+ std::chrono::duration<float> duration = endTime - startTime;
+ std::cerr << duration.count() << " seconds." << std::endl;
+
+ // save image
+ std::cerr << " * Writing result." << std::endl;
+ exportImage(getFilename(filename) + ".ppm", result);
+ }
+
+ // Done.
+ return 0;
+}
diff --git a/hw3/bin/helloworld.cpp b/hw3/bin/helloworld.cpp
new file mode 100644
index 0000000..4911d87
--- /dev/null
+++ b/hw3/bin/helloworld.cpp
@@ -0,0 +1,9 @@
+#include <iostream>
+#include <cassert>
+
+int main(int argc, char** argv)
+{
+ ///////////////////////////
+ std::cout << "Hello World." << std::endl;
+ return(0);
+}
diff --git a/hw3/bin/image_compare.cpp b/hw3/bin/image_compare.cpp
new file mode 100644
index 0000000..4f1a798
--- /dev/null
+++ b/hw3/bin/image_compare.cpp
@@ -0,0 +1,90 @@
+#include <string>
+#include <iostream>
+
+#include "util.h"
+#include "image.h"
+#include "imageIO.h"
+#include "constants.h"
+#include "errorMessage.h"
+
+int main(int argc, char** argv)
+{
+ // parse command line
+ if(argc != 3)
+ {
+ std::cout << "Usage: " << argv[0] << " <image A> <image B>" << std::endl;
+ return -1;
+ }
+
+ std::string nameA(argv[1]);
+ std::string nameB(argv[2]);
+
+ // get image extensions
+ std::string extA = getExtension(nameA);
+ std::string extB = getExtension(nameB);
+
+ // check if both images have the same extension
+ if(extA != extB) errorMessage(" => different image types (PPM vs PFM).");
+
+ // load images
+ image imgA, imgB;
+ importImage(nameA, imgA);
+ importImage(nameB, imgB);
+
+ // check if both have the same dimension
+ if(imgA.width() != imgB.width() || imgA.height() != imgB.height())
+ errorMessage(" => different images sizes (%dx%d) vs (%dx%d).", imgA.width(), imgA.height(), imgB.width(), imgB.height());
+
+ // compute the difference image
+ image diff(imgA.width(), imgA.height());
+ color avgDiff, maxDiff;
+ unsigned long diffCount = 0;
+
+ for(image::size_type y=0; y < diff.height(); y++)
+ for(image::size_type x=0; x < diff.width(); x++)
+ {
+ // per pixel difference
+ color diffColor = imgA(x,y) - imgB(x,y);
+ diff(x,y) = (extA == "ppm") ? abs(diffColor) : diffColor;
+
+ // if different => update average and max (abs value)
+ diffColor.abs();
+ if(diffColor.r > EPSILON || diffColor.g > EPSILON || diffColor.b > EPSILON)
+ {
+ diffCount++;
+ avgDiff += diffColor;
+ maxDiff = color(std::max(maxDiff.r, diffColor.r), std::max(maxDiff.g, diffColor.g), std::max(maxDiff.b, diffColor.b));
+ }
+ }
+
+ // output results if different
+ if(extA == "ppm" && diffCount != 0)
+ {
+ avgDiff /= diffCount;
+ std::cout << " => There are " << diffCount << " pixels that differ." << std::endl;
+ std::cout << " Average difference: " << avgDiff << " [base 256: " << (avgDiff * 256.0f) << "]" << std::endl;
+ std::cout << " Maximum difference: " << maxDiff << " [base 256: " << (maxDiff * 256.0f) << "]" << std::endl;
+
+ // write out difference image
+ exportImage("diff.ppm", diff);
+ }
+
+ else if(extA == "pfm" && diffCount != 0)
+ {
+ avgDiff /= diffCount;
+ std::cout << " => There are " << diffCount << " pixels that differ." << std::endl;
+ std::cout << " Average difference: " << avgDiff << std::endl;
+ std::cout << " Maximum difference: " << maxDiff << std::endl;
+
+ // write out difference image
+ exportImage("diff.pfm", diff);
+ }
+
+ // if equal, let the user know
+ else {
+ std::cout << " => Both images are equal.\r\n";
+ }
+
+ // Done.
+ return 0;
+}
diff --git a/hw3/data/HW3-scene1.xml b/hw3/data/HW3-scene1.xml
new file mode 100644
index 0000000..ee1a846
--- /dev/null
+++ b/hw3/data/HW3-scene1.xml
@@ -0,0 +1,23 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" />
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="0.0 0.0 1.0"/>
+ </diffuse>
+ </material>
+
+ <triangleMesh id="triangle">
+ <material ref="mat"/>
+ <triangle>
+ <vertex v="+1.0 -1.0 -2.0"/>
+ <vertex v="+0.0 +1.0 -2.0"/>
+ <vertex v="-1.0 -1.0 -2.0"/>
+ </triangle>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 1.0 -1.0" power="1.0 1.0 1.0"/>
+
+
+</scene> \ No newline at end of file
diff --git a/hw3/data/HW3-scene2.xml b/hw3/data/HW3-scene2.xml
new file mode 100644
index 0000000..be71e94
--- /dev/null
+++ b/hw3/data/HW3-scene2.xml
@@ -0,0 +1,24 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" />
+
+ <material id="mat">
+ <phong>
+ <albedo value="1.0 0.0 0.0"/>
+ <sharpness value="32.0"/>
+ </phong>
+ </material>
+
+ <triangleMesh id="triangle">
+ <material ref="mat"/>
+ <triangle>
+ <vertex v="+1.0 -1.0 -2.0"/>
+ <vertex v="+0.0 +1.0 -2.0"/>
+ <vertex v="-1.0 -1.0 -2.0"/>
+ </triangle>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 0.2 -1.0" power="1.0 1.0 1.0"/>
+
+
+</scene>
diff --git a/hw3/data/HW3-scene3.xml b/hw3/data/HW3-scene3.xml
new file mode 100644
index 0000000..efa843b
--- /dev/null
+++ b/hw3/data/HW3-scene3.xml
@@ -0,0 +1,18 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="0.0 0.0 1.0"/>
+ </diffuse>
+ </material>
+
+ <triangleMesh id="sphere" filename="sphere.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 -1.0 0.0" power="1.0 1.0 1.0"/>
+
+
+</scene> \ No newline at end of file
diff --git a/hw3/data/HW3-scene4.xml b/hw3/data/HW3-scene4.xml
new file mode 100644
index 0000000..ed765f8
--- /dev/null
+++ b/hw3/data/HW3-scene4.xml
@@ -0,0 +1,19 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <phong>
+ <albedo value="1.0 1.0 1.0"/>
+ <sharpness value="25.0"/>
+ </phong>
+ </material>
+
+ <triangleMesh id="sphere" filename="sphere.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 -1.0 0.0" power="1.0 1.0 1.0"/>
+
+
+</scene>
diff --git a/hw3/data/HW3-scene5.xml b/hw3/data/HW3-scene5.xml
new file mode 100644
index 0000000..fa6d4d6
--- /dev/null
+++ b/hw3/data/HW3-scene5.xml
@@ -0,0 +1,22 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="1.0 0.0 0.0"/>
+ </diffuse>
+ <phong>
+ <albedo value="1.0 1.0 1.0"/>
+ <sharpness value="32.0"/>
+ </phong>
+ </material>
+
+ <triangleMesh id="sphere" filename="sphere.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 -1.0 -0.5" power="1.0 1.0 1.0"/>
+
+
+</scene> \ No newline at end of file
diff --git a/hw3/data/HW3-scene6.xml b/hw3/data/HW3-scene6.xml
new file mode 100644
index 0000000..c3df17a
--- /dev/null
+++ b/hw3/data/HW3-scene6.xml
@@ -0,0 +1,22 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="0.0 1.0 0.0"/>
+ </diffuse>
+ <phong>
+ <albedo value="1.0 1.0 1.0"/>
+ <sharpness value="64.0"/>
+ </phong>
+ </material>
+
+ <triangleMesh id="sphere" filename="sphere.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 0.0 1.0" power="1.0 1.0 1.0"/>
+
+
+</scene>
diff --git a/hw3/data/HW3-scene7.xml b/hw3/data/HW3-scene7.xml
new file mode 100644
index 0000000..4183e81
--- /dev/null
+++ b/hw3/data/HW3-scene7.xml
@@ -0,0 +1,19 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="0.0 0.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="1.0 1.0 1.0"/>
+ </diffuse>
+ </material>
+
+ <triangleMesh id="sphere" filename="sphere.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="0.0 -1.0 0.0" power="1.0 0.0 0.0"/>
+ <light type="directional" direction="0.0 1.0 0.0" power="0.0 0.0 1.0"/>
+
+
+</scene> \ No newline at end of file
diff --git a/hw3/data/HW3-scene8.xml b/hw3/data/HW3-scene8.xml
new file mode 100644
index 0000000..52c3ad8
--- /dev/null
+++ b/hw3/data/HW3-scene8.xml
@@ -0,0 +1,20 @@
+<scene>
+
+ <camera eye="0.0 0.0 0.0" up="0.0 1.0 0.0" view="-1.0 -1.0 -1.0" fov="30.0" width="256" height="256" auto="true"/>
+
+ <material id="mat">
+ <diffuse>
+ <albedo value="1.0 1.0 1.0"/>
+ </diffuse>
+ </material>
+
+ <triangleMesh id="cube" filename="cube.obj">
+ <material ref="mat"/>
+ </triangleMesh>
+
+ <light type="directional" direction="-1.0 0.0 0.0" power="1.0 0.0 0.0"/>
+ <light type="directional" direction="0.0 -1.0 0.0" power="0.0 1.0 0.0"/>
+ <light type="directional" direction="0.0 0.0 -1.0" power="0.0 0.0 1.0"/>
+
+
+</scene> \ No newline at end of file
diff --git a/hw3/data/cube.obj b/hw3/data/cube.obj
new file mode 100644
index 0000000..89afe94
--- /dev/null
+++ b/hw3/data/cube.obj
@@ -0,0 +1,26 @@
+v 0.0 0.0 0.0
+v 0.0 0.0 1.0
+v 0.0 1.0 0.0
+v 0.0 1.0 1.0
+v 1.0 0.0 0.0
+v 1.0 0.0 1.0
+v 1.0 1.0 0.0
+v 1.0 1.0 1.0
+vn 0.0 0.0 1.0
+vn 0.0 0.0 -1.0
+vn 0.0 1.0 0.0
+vn 0.0 -1.0 0.0
+vn 1.0 0.0 0.0
+vn -1.0 0.0 0.0
+f 1//2 7//2 5//2
+f 1//2 3//2 7//2
+f 1//6 4//6 3//6
+f 1//6 2//6 4//6
+f 3//3 8//3 7//3
+f 3//3 4//3 8//3
+f 5//5 7//5 8//5
+f 5//5 8//5 6//5
+f 1//4 5//4 6//4
+f 1//4 6//4 2//4
+f 2//1 6//1 8//1
+f 2//1 8//1 4//1
diff --git a/hw3/data/sphere.obj b/hw3/data/sphere.obj
new file mode 100644
index 0000000..5dd7bde
--- /dev/null
+++ b/hw3/data/sphere.obj
@@ -0,0 +1,1834 @@
+mtllib sphere.mtl
+v -1 0 1.40385e-007
+v -0.983024 -0.156077 0.0964607
+v -0.983024 0.156077 -0.0964604
+v -0.978148 -0.185961 -0.0929805
+v -0.978148 0 0.207911
+v -0.978148 0 -0.207911
+v -0.978148 0.185961 0.0929807
+v -0.939205 -0.343331 0.00428931
+v -0.939205 -0.157379 0.305166
+v -0.939205 0.157379 -0.305166
+v -0.939205 0.343331 -0.00428905
+v -0.934172 -0.187593 -0.303531
+v -0.934172 0.187593 0.303531
+v -0.93267 -0.306855 0.189647
+v -0.93267 0.306855 -0.189647
+v -0.913545 -0.363797 -0.181898
+v -0.913545 0 0.406737
+v -0.913545 0 -0.406737
+v -0.913545 0.363797 0.181899
+v -0.866018 -0.490334 0.0979075
+v -0.866018 -0.306855 0.394783
+v -0.866018 0.306855 -0.394782
+v -0.866018 0.490334 -0.0979072
+v -0.851981 -0.516806 -0.0839041
+v -0.851981 -0.156077 0.499769
+v -0.851981 0.156077 -0.499768
+v -0.851981 0.516806 0.0839044
+v -0.850651 -0.447214 0.276393
+v -0.850651 0.447214 -0.276393
+v -0.845991 -0.363797 -0.389809
+v -0.845991 -0.185961 -0.499718
+v -0.845991 0.185961 0.499718
+v -0.845991 0.363797 0.38981
+v -0.809017 -0.525731 -0.262865
+v -0.809017 0 0.587785
+v -0.809017 0 -0.587785
+v -0.809017 0.525731 0.262866
+v -0.762354 -0.644208 0.0617517
+v -0.762354 -0.343331 0.548581
+v -0.762354 0.343331 -0.548581
+v -0.762354 0.644208 -0.0617515
+v -0.758172 -0.60373 0.246345
+v -0.758172 -0.490334 0.429824
+v -0.758172 0.490334 -0.429824
+v -0.758172 0.60373 -0.246345
+v -0.757312 -0.343331 -0.555521
+v -0.757311 0.343331 0.555521
+v -0.738585 -0.516806 -0.432902
+v -0.738585 -0.156077 -0.655845
+v -0.738585 0.156077 0.655845
+v -0.738585 0.516806 0.432902
+v -0.736686 -0.664689 -0.124433
+v -0.736686 0.185961 -0.650164
+v -0.736685 -0.185961 0.650164
+v -0.736685 0.664689 0.124433
+v -0.669131 -0.664689 -0.332344
+v -0.669131 0 0.743144
+v -0.669131 0 -0.743144
+v -0.669131 0.664689 0.332344
+v -0.653054 -0.644208 0.398142
+v -0.653054 0.644208 -0.398142
+v -0.643075 -0.490334 -0.588241
+v -0.643075 -0.306855 -0.701637
+v -0.643075 0.306855 0.701637
+v -0.643075 0.490334 0.588241
+v -0.639949 -0.739749 0.207932
+v -0.639949 -0.516806 0.568662
+v -0.639949 0.516806 -0.568662
+v -0.639949 0.739749 -0.207932
+v -0.632156 -0.774597 0.0194389
+v -0.632156 -0.363797 0.684127
+v -0.632156 0.363797 -0.684127
+v -0.632156 0.774597 -0.0194387
+v -0.580461 -0.644208 -0.498058
+v -0.580461 -0.157379 -0.798935
+v -0.58046 0.157379 0.798935
+v -0.58046 0.644208 0.498058
+v -0.57735 -0.794654 -0.187592
+v -0.57735 -0.187593 0.794655
+v -0.57735 0.187593 -0.794654
+v -0.57735 0.794654 0.187593
+v -0.525731 -0.447214 -0.723607
+v -0.525731 0.447214 0.723607
+v -0.522851 -0.774597 0.355846
+v -0.522851 -0.664689 0.533682
+v -0.522851 0.664689 -0.533681
+v -0.522851 0.774597 -0.355846
+v -0.5 -0.850651 0.16246
+v -0.5 -0.525731 0.688191
+v -0.5 0.525731 -0.688191
+v -0.5 0.850651 -0.16246
+v -0.499999 -0.774597 -0.387298
+v -0.499999 0 0.866026
+v -0.499999 0 -0.866026
+v -0.499999 0.774597 0.387299
+v -0.468576 -0.60373 -0.644939
+v -0.468576 -0.306855 -0.828418
+v -0.468576 0.306855 0.828418
+v -0.468576 0.60373 0.644939
+v -0.455297 -0.889527 -0.0380263
+v -0.455297 -0.363797 0.812623
+v -0.455297 0.363797 -0.812623
+v -0.455297 0.889527 0.0380264
+v -0.395511 -0.739749 -0.544373
+v -0.395511 -0.156077 -0.905103
+v -0.39551 0.156077 0.905103
+v -0.39551 0.739749 0.544373
+v -0.390694 -0.889527 -0.236853
+v -0.390694 -0.185961 0.901541
+v -0.390694 0.185961 -0.901541
+v -0.390694 0.889527 0.236853
+v -0.36073 -0.490334 -0.793377
+v -0.36073 0.490334 0.793377
+v -0.356822 -0.794654 0.491123
+v -0.356822 0.794655 -0.491123
+v -0.345991 -0.889527 0.298381
+v -0.345991 -0.664689 0.662178
+v -0.345991 0.664689 -0.662178
+v -0.345991 0.889527 -0.298381
+v -0.343074 -0.93267 0.111472
+v -0.343074 -0.516806 0.784354
+v -0.343074 0.516806 -0.784354
+v -0.343074 0.93267 -0.111472
+v -0.309017 -0.850651 -0.425325
+v -0.309017 0 0.951057
+v -0.309017 0 -0.951056
+v -0.309017 0.850651 0.425325
+v -0.29431 -0.644208 -0.705959
+v -0.29431 -0.343331 -0.891911
+v -0.294309 0.343331 0.891911
+v -0.294309 0.644208 0.705959
+v -0.286151 -0.953663 -0.092976
+v -0.286151 -0.343331 0.894562
+v -0.286151 0.343331 -0.894562
+v -0.286151 0.953663 0.0929761
+v -0.213835 -0.774597 -0.595209
+v -0.213835 -0.185961 -0.959006
+v -0.213834 0.185961 0.959006
+v -0.213834 0.774597 0.595209
+v -0.212032 -0.93267 -0.291836
+v -0.212032 0.156077 -0.964719
+v -0.212032 0.93267 0.291836
+v -0.212031 -0.156077 0.964719
+v -0.183479 -0.516806 -0.83621
+v -0.183479 0.516806 0.83621
+v -0.17686 -0.889527 0.421262
+v -0.17686 -0.774597 0.607223
+v -0.17686 0.774597 -0.607223
+v -0.17686 0.889527 -0.421262
+v -0.176851 -0.953663 0.243415
+v -0.176851 -0.644208 0.744124
+v -0.176851 0.644208 -0.744124
+v -0.176851 0.953663 -0.243415
+v -0.174499 -0.983024 0.0566981
+v -0.174499 -0.490334 0.853887
+v -0.174499 0.490334 -0.853887
+v -0.174499 0.983024 -0.0566981
+v -0.109305 -0.664689 -0.739082
+v -0.109305 -0.363797 -0.925043
+v -0.109305 0.363797 0.925043
+v -0.109305 0.664689 0.739082
+v -0.107846 -0.983024 -0.148438
+v -0.107846 -0.306855 0.945626
+v -0.107846 0.306855 -0.945626
+v -0.107846 0.983024 0.148438
+v -0.104529 -0.889527 -0.444764
+v -0.104529 0 0.994522
+v -0.104529 0 -0.994522
+v -0.104529 0.889527 0.444764
+v -7.96122e-008 -0.525731 -0.850651
+v -5.98336e-008 -0.187593 -0.982247
+v -5.68148e-008 -0.794655 -0.607062
+v -3.18213e-008 0.157379 -0.987538
+v -2.8159e-008 -0.953663 -0.300877
+v 0 -1 -0
+v 0 0.447214 -0.894427
+v 0 0.60373 -0.797189
+v 0 0.739749 -0.672883
+v 0 0.850651 -0.525731
+v 0 0.93267 -0.36073
+v 0 0.983024 -0.183479
+v 0 1 -0
+v 1.71718e-008 -0.983024 0.183479
+v 2.8159e-008 0.953663 0.300877
+v 3.37606e-008 -0.93267 0.36073
+v 4.92031e-008 -0.850651 0.525731
+v 5.68148e-008 0.794654 0.607062
+v 6.29749e-008 -0.739749 0.672883
+v 7.46087e-008 -0.60373 0.797189
+v 7.96122e-008 0.525731 0.850651
+v 8.37093e-008 -0.447214 0.894427
+v 9.19283e-008 0.187593 0.982247
+v 9.24235e-008 -0.157379 0.987538
+v 0.104529 -0.889527 -0.444764
+v 0.104529 0 0.994522
+v 0.104529 0 -0.994522
+v 0.104529 0.889527 0.444764
+v 0.107846 -0.983024 -0.148438
+v 0.107846 -0.306855 0.945626
+v 0.107846 0.306855 -0.945626
+v 0.107846 0.983024 0.148438
+v 0.109305 -0.664689 -0.739082
+v 0.109305 -0.363797 -0.925043
+v 0.109305 0.363797 0.925043
+v 0.109305 0.664689 0.739082
+v 0.174499 -0.983024 0.0566981
+v 0.174499 -0.490334 0.853887
+v 0.174499 0.490334 -0.853887
+v 0.174499 0.983024 -0.0566981
+v 0.176851 -0.953663 0.243415
+v 0.176851 -0.644208 0.744124
+v 0.176851 0.644208 -0.744124
+v 0.176851 0.953663 -0.243415
+v 0.17686 -0.889527 0.421262
+v 0.17686 -0.774597 0.607223
+v 0.17686 0.774597 -0.607223
+v 0.17686 0.889527 -0.421262
+v 0.183479 -0.516806 -0.83621
+v 0.183479 0.516806 0.83621
+v 0.212032 -0.93267 -0.291836
+v 0.212032 -0.156077 0.964719
+v 0.212032 0.156077 -0.964719
+v 0.212032 0.93267 0.291836
+v 0.213834 -0.774597 -0.595209
+v 0.213834 -0.185961 -0.959006
+v 0.213834 0.774597 0.595209
+v 0.213835 0.185961 0.959006
+v 0.286151 -0.953663 -0.0929761
+v 0.286151 -0.343331 0.894562
+v 0.286151 0.343331 -0.894562
+v 0.286151 0.953663 0.0929761
+v 0.294309 -0.644208 -0.705959
+v 0.294309 -0.343331 -0.891911
+v 0.29431 0.343331 0.891911
+v 0.29431 0.644208 0.705959
+v 0.309017 -0.850651 -0.425325
+v 0.309017 0 0.951056
+v 0.309017 0 -0.951057
+v 0.309017 0.850651 0.425325
+v 0.343074 -0.93267 0.111472
+v 0.343074 -0.516806 0.784354
+v 0.343074 0.516806 -0.784354
+v 0.343074 0.93267 -0.111472
+v 0.345991 -0.889527 0.298381
+v 0.345991 -0.664689 0.662178
+v 0.345991 0.664689 -0.662178
+v 0.345991 0.889527 -0.298381
+v 0.356822 -0.794654 0.491123
+v 0.356822 0.794654 -0.491123
+v 0.36073 -0.490334 -0.793377
+v 0.36073 0.490334 0.793377
+v 0.390694 -0.889527 -0.236853
+v 0.390694 -0.185961 0.901541
+v 0.390694 0.185961 -0.901541
+v 0.390694 0.889527 0.236853
+v 0.39551 -0.739749 -0.544373
+v 0.39551 -0.156077 -0.905103
+v 0.39551 0.739749 0.544373
+v 0.395511 0.156077 0.905103
+v 0.455297 -0.889527 -0.0380264
+v 0.455297 -0.363797 0.812623
+v 0.455297 0.363797 -0.812623
+v 0.455297 0.889527 0.0380263
+v 0.468576 -0.60373 -0.644939
+v 0.468576 -0.306855 -0.828418
+v 0.468576 0.306855 0.828418
+v 0.468576 0.60373 0.644939
+v 0.499999 -0.774597 -0.387298
+v 0.499999 0 0.866026
+v 0.499999 0 -0.866026
+v 0.499999 0.774597 0.387298
+v 0.5 -0.850651 0.16246
+v 0.5 -0.525731 0.688191
+v 0.5 0.525731 -0.688191
+v 0.5 0.850651 -0.16246
+v 0.522851 -0.774597 0.355846
+v 0.522851 -0.664689 0.533681
+v 0.522851 0.664689 -0.533682
+v 0.522851 0.774597 -0.355846
+v 0.525731 -0.447214 -0.723607
+v 0.525731 0.447214 0.723607
+v 0.57735 -0.794654 -0.187592
+v 0.57735 -0.187593 0.794654
+v 0.57735 0.187593 -0.794654
+v 0.57735 0.794654 0.187592
+v 0.58046 -0.644208 -0.498058
+v 0.58046 -0.157379 -0.798935
+v 0.58046 0.644208 0.498058
+v 0.580461 0.157379 0.798935
+v 0.632156 -0.774597 0.0194388
+v 0.632156 -0.363797 0.684127
+v 0.632156 0.363797 -0.684127
+v 0.632156 0.774597 -0.0194389
+v 0.639949 -0.739749 0.207932
+v 0.639949 -0.516806 0.568662
+v 0.639949 0.516806 -0.568662
+v 0.639949 0.739749 -0.207932
+v 0.643075 -0.490334 -0.588241
+v 0.643075 -0.306855 -0.701637
+v 0.643075 0.306855 0.701637
+v 0.643075 0.490334 0.588241
+v 0.653054 -0.644208 0.398142
+v 0.653054 0.644208 -0.398142
+v 0.669131 -0.664689 -0.332344
+v 0.669131 0 0.743144
+v 0.669131 0 -0.743144
+v 0.669131 0.664689 0.332344
+v 0.736685 -0.664689 -0.124433
+v 0.736686 -0.185961 0.650164
+v 0.736686 0.185961 -0.650164
+v 0.736686 0.664689 0.124433
+v 0.738585 -0.516806 -0.432902
+v 0.738585 -0.156077 -0.655845
+v 0.738585 0.156077 0.655845
+v 0.738585 0.516806 0.432902
+v 0.757311 -0.343331 -0.555521
+v 0.757312 0.343331 0.555521
+v 0.758172 -0.60373 0.246345
+v 0.758172 -0.490334 0.429824
+v 0.758172 0.490334 -0.429824
+v 0.758172 0.60373 -0.246345
+v 0.762354 -0.644208 0.0617515
+v 0.762354 -0.343331 0.548581
+v 0.762354 0.343331 -0.548581
+v 0.762354 0.644208 -0.0617516
+v 0.809017 -0.525731 -0.262866
+v 0.809017 0 0.587785
+v 0.809017 0 -0.587785
+v 0.809017 0.525731 0.262865
+v 0.845991 -0.363797 -0.389809
+v 0.845991 -0.185961 -0.499718
+v 0.845991 0.185961 0.499718
+v 0.845991 0.363797 0.389809
+v 0.850651 -0.447214 0.276393
+v 0.850651 0.447214 -0.276393
+v 0.851981 -0.516806 -0.0839043
+v 0.851981 -0.156077 0.499768
+v 0.851981 0.156077 -0.499769
+v 0.851981 0.516806 0.0839042
+v 0.866018 -0.490334 0.0979073
+v 0.866018 -0.306855 0.394782
+v 0.866018 0.306855 -0.394782
+v 0.866018 0.490334 -0.0979074
+v 0.913545 -0.363797 -0.181898
+v 0.913545 0 0.406737
+v 0.913545 0 -0.406737
+v 0.913545 0.363797 0.181898
+v 0.93267 -0.306855 0.189647
+v 0.93267 0.306855 -0.189647
+v 0.934172 -0.187593 -0.303531
+v 0.934172 0.187593 0.303531
+v 0.939205 -0.343331 0.00428914
+v 0.939205 -0.157379 0.305166
+v 0.939205 0.157379 -0.305166
+v 0.939205 0.343331 -0.00428922
+v 0.978148 -0.185961 -0.0929806
+v 0.978148 0 0.207911
+v 0.978148 0 -0.207911
+v 0.978148 0.185961 0.0929806
+v 0.983024 -0.156077 0.0964605
+v 0.983024 0.156077 -0.0964606
+v 1 0 -4.67949e-008
+vt -0.05 0.0972793
+vt -0.05 0.941264
+vt -0.0156234 0.327121
+vt -0.0150836 0.44046
+vt -0.0132618 0.151034
+vt -0.0128636 0.722813
+vt -0.00489247 0.782047
+vt -0.000726819 0.611555
+vt 2.2343e-008 0.5
+vt 0.000726849 0.388445
+vt 0.0048925 0.217953
+vt 0.0128637 0.277187
+vt 0.0132618 0.848966
+vt 0.0150836 0.55954
+vt 0.0155675 0.450115
+vt 0.0156234 0.672879
+vt 0.0179172 0.336875
+vt 0.0266314 0.731436
+vt 0.0312808 0.61852
+vt 0.0319269 0.400723
+vt 0.0333332 0.5
+vt 0.0499999 0.0587359
+vt 0.05 0.352416
+vt 0.05 0.449696
+vt 0.05 0.234944
+vt 0.05 0.293681
+vt 0.05 0.902721
+vt 0.05 0.560069
+vt 0.05 0.176208
+vt 0.0500001 0.676208
+vt 0.0500001 0.792348
+vt 0.0500002 1
+vt 0.0500002 0.117472
+vt 0.0666667 0.5
+vt 0.0680732 0.400723
+vt 0.0687194 0.61852
+vt 0.0733685 0.731436
+vt 0.0820829 0.336875
+vt 0.0843766 0.672879
+vt 0.0844326 0.450115
+vt 0.0849164 0.55954
+vt 0.0867383 0.848966
+vt 0.0871363 0.277187
+vt 0.0951076 0.217953
+vt 0.0992732 0.388445
+vt 0.1 0.5
+vt 0.100727 0.611555
+vt 0.104893 0.782047
+vt 0.112864 0.722813
+vt 0.113262 0.151034
+vt 0.115084 0.44046
+vt 0.115567 0.549885
+vt 0.115623 0.327121
+vt 0.117917 0.663125
+vt 0.126632 0.268564
+vt 0.131281 0.38148
+vt 0.131927 0.599277
+vt 0.133333 0.5
+vt 0.15 0.882528
+vt 0.15 0.70632
+vt 0.15 0.823792
+vt 0.15 0.207652
+vt 0.15 0
+vt 0.15 0.323792
+vt 0.15 0.765056
+vt 0.15 0.550304
+vt 0.15 0.647584
+vt 0.15 0.439931
+vt 0.15 0.0972794
+vt 0.15 0.941264
+vt 0.166667 0.5
+vt 0.168073 0.599277
+vt 0.168719 0.38148
+vt 0.173369 0.268564
+vt 0.182083 0.663125
+vt 0.184377 0.327121
+vt 0.184433 0.549885
+vt 0.184916 0.44046
+vt 0.186738 0.151034
+vt 0.187136 0.722813
+vt 0.195108 0.782047
+vt 0.199273 0.611555
+vt 0.2 0.5
+vt 0.200727 0.388445
+vt 0.204892 0.217953
+vt 0.212864 0.277187
+vt 0.213262 0.848966
+vt 0.215084 0.55954
+vt 0.215568 0.450115
+vt 0.215623 0.672879
+vt 0.217917 0.336875
+vt 0.226632 0.731436
+vt 0.231281 0.61852
+vt 0.231927 0.400723
+vt 0.233333 0.5
+vt 0.25 0.0587359
+vt 0.25 0.117472
+vt 0.25 0.176208
+vt 0.25 0.234944
+vt 0.25 0.293681
+vt 0.25 0.352416
+vt 0.25 0.449696
+vt 0.25 0.560069
+vt 0.25 0.676208
+vt 0.25 0.792348
+vt 0.25 0.902721
+vt 0.25 1
+vt 0.266667 0.5
+vt 0.268073 0.400723
+vt 0.268719 0.61852
+vt 0.273369 0.731436
+vt 0.282083 0.336875
+vt 0.284377 0.672879
+vt 0.284433 0.450115
+vt 0.284916 0.55954
+vt 0.286738 0.848966
+vt 0.287136 0.277187
+vt 0.295108 0.217953
+vt 0.299273 0.388445
+vt 0.3 0.5
+vt 0.300727 0.611555
+vt 0.304892 0.782047
+vt 0.312864 0.722813
+vt 0.313262 0.151034
+vt 0.315084 0.44046
+vt 0.315568 0.549885
+vt 0.315623 0.327121
+vt 0.317917 0.663125
+vt 0.326631 0.268564
+vt 0.331281 0.38148
+vt 0.331927 0.599277
+vt 0.333333 0.5
+vt 0.35 0.941264
+vt 0.35 0.0972794
+vt 0.35 0.647584
+vt 0.35 0.765056
+vt 0.35 0.323792
+vt 0.35 0
+vt 0.35 0.439931
+vt 0.35 0.207652
+vt 0.35 0.70632
+vt 0.35 0.823792
+vt 0.35 0.550304
+vt 0.35 0.882528
+vt 0.366667 0.5
+vt 0.368073 0.599277
+vt 0.368719 0.38148
+vt 0.373369 0.268564
+vt 0.382083 0.663125
+vt 0.384377 0.327121
+vt 0.384433 0.549885
+vt 0.384916 0.44046
+vt 0.386738 0.151034
+vt 0.387136 0.722813
+vt 0.395108 0.782047
+vt 0.399273 0.611555
+vt 0.4 0.5
+vt 0.400727 0.388445
+vt 0.404892 0.217953
+vt 0.412864 0.277187
+vt 0.413262 0.848966
+vt 0.415084 0.55954
+vt 0.415568 0.450115
+vt 0.415623 0.672879
+vt 0.417917 0.336875
+vt 0.426631 0.731436
+vt 0.431281 0.61852
+vt 0.431927 0.400723
+vt 0.433333 0.5
+vt 0.45 0.117472
+vt 0.45 1
+vt 0.45 0.176208
+vt 0.45 0.293681
+vt 0.45 0.560069
+vt 0.45 0.902721
+vt 0.45 0.234944
+vt 0.45 0.449696
+vt 0.45 0.0587359
+vt 0.45 0.352416
+vt 0.45 0.676208
+vt 0.45 0.792348
+vt 0.466667 0.5
+vt 0.468073 0.400723
+vt 0.468719 0.61852
+vt 0.473369 0.731436
+vt 0.482083 0.336875
+vt 0.484377 0.672879
+vt 0.484433 0.450115
+vt 0.484916 0.55954
+vt 0.486738 0.848966
+vt 0.487136 0.277187
+vt 0.495108 0.217953
+vt 0.499273 0.388445
+vt 0.5 0.5
+vt 0.500727 0.611555
+vt 0.504893 0.782047
+vt 0.512864 0.722813
+vt 0.513262 0.151034
+vt 0.515084 0.44046
+vt 0.515567 0.549885
+vt 0.515623 0.327121
+vt 0.517917 0.663125
+vt 0.526631 0.268564
+vt 0.531281 0.38148
+vt 0.531927 0.599277
+vt 0.533333 0.5
+vt 0.55 0.207652
+vt 0.55 0.550304
+vt 0.55 0.647584
+vt 0.55 0.941264
+vt 0.55 0.0972793
+vt 0.55 0.439931
+vt 0.55 0.706319
+vt 0.55 0.765056
+vt 0.55 0.323792
+vt 0.55 0.823792
+vt 0.55 0
+vt 0.55 0.882528
+vt 0.566667 0.5
+vt 0.568073 0.599277
+vt 0.568719 0.38148
+vt 0.573369 0.268564
+vt 0.582083 0.663125
+vt 0.584377 0.327121
+vt 0.584433 0.549885
+vt 0.584916 0.44046
+vt 0.586738 0.151034
+vt 0.587136 0.722813
+vt 0.595108 0.782047
+vt 0.599273 0.611555
+vt 0.6 0.5
+vt 0.600727 0.388445
+vt 0.604892 0.217953
+vt 0.612864 0.277187
+vt 0.613262 0.848966
+vt 0.615084 0.55954
+vt 0.615567 0.450115
+vt 0.615623 0.672879
+vt 0.617917 0.336875
+vt 0.626631 0.731436
+vt 0.631281 0.61852
+vt 0.631927 0.400723
+vt 0.633333 0.5
+vt 0.65 0.117472
+vt 0.65 0.176208
+vt 0.65 0.29368
+vt 0.65 0.792348
+vt 0.65 0.560069
+vt 0.65 0.676208
+vt 0.65 1
+vt 0.65 0.234944
+vt 0.65 0.352416
+vt 0.65 0.449696
+vt 0.65 0.902721
+vt 0.65 0.058736
+vt 0.666667 0.5
+vt 0.668073 0.400723
+vt 0.668719 0.61852
+vt 0.673369 0.731436
+vt 0.682083 0.336875
+vt 0.684377 0.672879
+vt 0.684433 0.450115
+vt 0.684916 0.55954
+vt 0.686738 0.848966
+vt 0.687136 0.277187
+vt 0.695108 0.217953
+vt 0.699273 0.388445
+vt 0.7 0.5
+vt 0.700727 0.611555
+vt 0.704892 0.782047
+vt 0.712864 0.722813
+vt 0.713262 0.151034
+vt 0.715084 0.44046
+vt 0.715567 0.549885
+vt 0.715623 0.327121
+vt 0.717917 0.663125
+vt 0.726632 0.268564
+vt 0.731281 0.38148
+vt 0.731927 0.599277
+vt 0.733333 0.5
+vt 0.75 0
+vt 0.75 0.0972794
+vt 0.75 0.207652
+vt 0.75 0.323792
+vt 0.75 0.439931
+vt 0.75 0.550304
+vt 0.75 0.647584
+vt 0.75 0.706319
+vt 0.75 0.765056
+vt 0.75 0.823792
+vt 0.75 0.882528
+vt 0.75 0.941264
+vt 0.766667 0.5
+vt 0.768073 0.599277
+vt 0.768719 0.38148
+vt 0.773368 0.268564
+vt 0.782083 0.663125
+vt 0.784377 0.327121
+vt 0.784433 0.549885
+vt 0.784917 0.44046
+vt 0.786738 0.151034
+vt 0.787136 0.722813
+vt 0.795108 0.782047
+vt 0.799273 0.611555
+vt 0.8 0.5
+vt 0.800727 0.388445
+vt 0.804893 0.217953
+vt 0.812864 0.277187
+vt 0.813262 0.848966
+vt 0.815084 0.55954
+vt 0.815568 0.450115
+vt 0.815623 0.672879
+vt 0.817917 0.336875
+vt 0.826631 0.731436
+vt 0.831281 0.61852
+vt 0.831927 0.400723
+vt 0.833333 0.5
+vt 0.85 0.058736
+vt 0.85 0.902721
+vt 0.85 0.352416
+vt 0.85 0.560069
+vt 0.85 0.676208
+vt 0.85 1
+vt 0.85 0.176208
+vt 0.85 0.29368
+vt 0.85 0.449696
+vt 0.85 0.792348
+vt 0.85 0.234944
+vt 0.85 0.117472
+vt 0.866667 0.5
+vt 0.868073 0.400723
+vt 0.868719 0.61852
+vt 0.873369 0.731436
+vt 0.882083 0.336875
+vt 0.884377 0.672879
+vt 0.884433 0.450115
+vt 0.884916 0.55954
+vt 0.886738 0.848966
+vt 0.887136 0.277187
+vt 0.895108 0.217953
+vt 0.899273 0.388445
+vt 0.9 0.5
+vt 0.900727 0.611555
+vt 0.904892 0.782047
+vt 0.912864 0.722813
+vt 0.913262 0.151034
+vt 0.915084 0.44046
+vt 0.915568 0.549885
+vt 0.915623 0.327121
+vt 0.917917 0.663125
+vt 0.926631 0.268564
+vt 0.931281 0.38148
+vt 0.931927 0.599277
+vt 0.933333 0.5
+vt 0.95 0
+vt 0.95 0.882528
+vt 0.95 0.823792
+vt 0.95 0.439931
+vt 0.95 0.706319
+vt 0.95 0.765056
+vt 0.95 0.0972793
+vt 0.95 0.550304
+vt 0.95 0.647584
+vt 0.95 0.941264
+vt 0.95 0.207652
+vt 0.95 0.323792
+vt 0.966667 0.5
+vt 0.968073 0.599277
+vt 0.968719 0.38148
+vt 0.973369 0.268564
+vt 0.982083 0.663125
+vt 0.984377 0.327121
+vt 0.984433 0.549885
+vt 0.984916 0.44046
+vt 0.986738 0.151034
+vt 0.987136 0.722813
+vt 0.995108 0.782047
+vt 0.999273 0.611555
+vt 1 0.5
+vt 1.00073 0.388445
+vt 1.00489 0.217953
+vt 1.01286 0.277187
+vt 1.01326 0.848966
+vt 1.01508 0.55954
+vt 1.01562 0.672879
+vt 1.05 0.0587359
+vt 1.05 0.902721
+vn -1 1.00021e-008 4.62596e-008
+vn -0.981591 -0.162468 0.100411
+vn -0.981591 0.162468 -0.100411
+vn -0.978376 -0.180943 -0.100195
+vn -0.978376 0.180943 0.100195
+vn -0.978376 -0.00869708 -0.206649
+vn -0.978376 0.0086971 0.20665
+vn -0.939218 -0.157292 0.30517
+vn -0.939218 -0.343297 0.00421013
+vn -0.939218 0.343297 -0.0042102
+vn -0.939218 0.157293 -0.305171
+vn -0.934172 0.187592 0.303531
+vn -0.934172 -0.187593 -0.303531
+vn -0.929022 -0.314761 0.194533
+vn -0.929022 0.314761 -0.194533
+vn -0.912988 0.360941 0.190194
+vn -0.912988 0.00869702 0.407893
+vn -0.912988 -0.360942 -0.190194
+vn -0.912988 -0.00869627 -0.407893
+vn -0.865939 0.31476 -0.388685
+vn -0.865939 -0.31476 0.388684
+vn -0.865939 -0.488415 0.107705
+vn -0.865939 0.488415 -0.107705
+vn -0.853145 0.162466 -0.49573
+vn -0.853145 -0.516052 -0.0763834
+vn -0.853144 -0.162466 0.495732
+vn -0.853144 0.516053 0.0763836
+vn -0.850652 0.447212 -0.276392
+vn -0.850652 -0.447213 0.276392
+vn -0.850417 -0.180942 -0.494015
+vn -0.850417 -0.360941 -0.382769
+vn -0.850416 0.180942 0.494016
+vn -0.850416 0.360941 0.382772
+vn -0.809018 -0.52573 -0.262865
+vn -0.809017 2.413e-007 -0.587785
+vn -0.809017 0.525732 0.262865
+vn -0.809017 -4.85101e-007 0.587786
+vn -0.763866 0.488416 -0.421851
+vn -0.763866 -0.488417 0.421851
+vn -0.763865 0.595742 -0.248195
+vn -0.763865 -0.595742 0.248195
+vn -0.762317 0.343296 -0.548653
+vn -0.762317 -0.644257 0.0616893
+vn -0.762317 0.644257 -0.0616879
+vn -0.762316 -0.343296 0.548655
+vn -0.757369 -0.343296 -0.555464
+vn -0.757368 0.343296 0.555465
+vn -0.735105 -0.516054 -0.439669
+vn -0.735104 -0.162466 -0.658199
+vn -0.735104 0.162467 0.6582
+vn -0.735104 0.516054 0.439671
+vn -0.73263 -0.667785 -0.131592
+vn -0.73263 0.180943 -0.656135
+vn -0.73263 -0.180942 0.656135
+vn -0.73263 0.667785 0.131592
+vn -0.670058 -0.00869553 0.742258
+vn -0.670058 0.00869665 -0.742258
+vn -0.670057 0.667785 0.324169
+vn -0.670057 -0.667786 -0.324169
+vn -0.652987 -0.644257 0.398171
+vn -0.652987 0.644257 -0.398172
+vn -0.645311 -0.734582 0.209674
+vn -0.645311 0.734582 -0.209674
+vn -0.645311 -0.516052 0.563262
+vn -0.64531 0.516053 -0.563262
+vn -0.637252 0.488417 0.59612
+vn -0.637252 0.31476 0.703446
+vn -0.637251 -0.488416 -0.596121
+vn -0.637251 -0.31476 -0.703447
+vn -0.62683 -0.360942 0.690511
+vn -0.62683 0.77903 -0.0140296
+vn -0.626829 -0.779031 0.0140304
+vn -0.626829 0.360942 -0.690512
+vn -0.580469 -0.157292 -0.798946
+vn -0.580468 0.157292 0.798947
+vn -0.580468 -0.644257 -0.497986
+vn -0.580467 0.644257 0.497987
+vn -0.57735 -0.187593 0.794654
+vn -0.57735 0.794655 0.187592
+vn -0.57735 0.187593 -0.794655
+vn -0.577349 -0.794656 -0.187593
+vn -0.525731 -0.447214 -0.723607
+vn -0.525731 0.447214 0.723607
+vn -0.515363 0.667784 -0.537089
+vn -0.515363 0.77903 -0.35709
+vn -0.515363 -0.667785 0.537089
+vn -0.515362 -0.77903 0.35709
+vn -0.500001 0.52573 -0.688191
+vn -0.5 -0.525729 0.688192
+vn -0.5 0.850651 -0.16246
+vn -0.5 -0.850651 0.16246
+vn -0.49887 -0.00869475 0.866633
+vn -0.49887 0.00869757 -0.866633
+vn -0.498869 -0.77903 -0.379791
+vn -0.498869 0.77903 0.379793
+vn -0.472095 -0.31476 -0.823439
+vn -0.472095 -0.595742 -0.649783
+vn -0.472095 0.314759 0.82344
+vn -0.472095 0.595743 0.649782
+vn -0.463014 0.360941 -0.80953
+vn -0.463014 -0.885484 -0.0391978
+vn -0.463014 0.885484 0.0391977
+vn -0.463013 -0.360942 0.80953
+vn -0.398825 -0.734582 -0.548934
+vn -0.398824 0.162469 0.90252
+vn -0.398824 0.734581 0.548935
+vn -0.398824 -0.162467 -0.902521
+vn -0.397626 -0.885484 -0.240441
+vn -0.397626 0.180943 -0.89953
+vn -0.397625 0.885484 0.240441
+vn -0.397625 -0.180944 0.89953
+vn -0.370023 -0.488416 -0.790274
+vn -0.370022 0.488416 0.790274
+vn -0.356821 0.794655 -0.491122
+vn -0.356821 -0.794656 0.491122
+vn -0.351546 0.667784 -0.656109
+vn -0.351546 -0.885484 0.303865
+vn -0.351546 0.885484 -0.303863
+vn -0.351546 -0.667785 0.656109
+vn -0.336281 -0.935402 0.109265
+vn -0.336281 -0.516052 0.787785
+vn -0.336281 0.516052 -0.787785
+vn -0.336281 0.935402 -0.109265
+vn -0.309017 -0.850651 -0.425325
+vn -0.309017 6.87643e-008 -0.951056
+vn -0.309017 4.8135e-007 0.951057
+vn -0.309017 0.850651 0.425326
+vn -0.29424 -0.644257 -0.705943
+vn -0.294239 0.644258 0.705943
+vn -0.294238 -0.343295 -0.891948
+vn -0.294238 0.343295 0.891949
+vn -0.286232 -0.953636 -0.0930024
+vn -0.286232 0.953636 0.0930024
+vn -0.286231 0.343296 -0.89455
+vn -0.286231 -0.343296 0.89455
+vn -0.207833 -0.935402 -0.286058
+vn -0.207833 0.935402 0.286058
+vn -0.207833 0.162468 -0.964577
+vn -0.207832 -0.162469 0.964577
+vn -0.207046 -0.77903 -0.591814
+vn -0.207046 -0.180943 -0.961453
+vn -0.207045 0.77903 0.591814
+vn -0.207045 0.180944 0.961453
+vn -0.190993 0.516052 0.834992
+vn -0.190992 -0.516052 -0.834992
+vn -0.180359 -0.885484 0.42824
+vn -0.180358 -0.779031 0.600485
+vn -0.180358 0.885484 -0.428239
+vn -0.180357 0.77903 -0.600486
+vn -0.176901 0.953636 -0.243484
+vn -0.176901 -0.953636 0.243484
+vn -0.1769 0.644256 -0.74407
+vn -0.1769 -0.644256 0.74407
+vn -0.165158 -0.984806 0.0536629
+vn -0.165158 0.984806 -0.0536629
+vn -0.165157 0.488415 -0.856839
+vn -0.165157 -0.488415 0.856839
+vn -0.105801 -0.00869593 -0.994349
+vn -0.105801 -0.885484 -0.452464
+vn -0.1058 0.885484 0.452465
+vn -0.1058 0.0086958 0.994349
+vn -0.102073 -0.984806 -0.140492
+vn -0.102073 0.984806 0.140492
+vn -0.102072 -0.31476 0.943667
+vn -0.102071 0.31476 -0.943667
+vn -0.101246 0.360941 0.927077
+vn -0.101246 -0.667784 -0.737437
+vn -0.101245 0.667785 0.737436
+vn -0.101245 -0.360941 -0.927077
+vn -1.38907e-007 0.187592 0.982247
+vn -1.37495e-007 -0.157294 0.987552
+vn -2.50052e-008 -0.52573 -0.850651
+vn -1.24996e-008 -0.953636 -0.300962
+vn -8.74969e-009 0.157294 -0.987552
+vn -1.25026e-009 0.850651 -0.52573
+vn -1.24987e-009 0.984806 -0.173657
+vn -1.24987e-009 0.595741 -0.803177
+vn -1.24987e-009 0.734582 -0.67852
+vn -1.24986e-009 0.935402 -0.353587
+vn 0 -1 1.49983e-008
+vn 0 0.447212 -0.894428
+vn 0 1 -1.34985e-008
+vn 3.74961e-009 -0.984806 0.173657
+vn 1.24987e-008 -0.935402 0.353587
+vn 1.24996e-008 0.953636 0.300962
+vn 2.00227e-008 0.794656 0.60706
+vn 2.12544e-008 -0.850651 0.52573
+vn 2.7497e-008 -0.734582 0.67852
+vn 2.8756e-008 0.52573 0.850651
+vn 3.37465e-008 -0.595741 0.803177
+vn 3.89956e-008 -0.447212 0.894428
+vn 1.45164e-007 -0.187592 -0.982247
+vn 1.45164e-007 -0.794656 -0.60706
+vn 0.101245 0.667785 0.737436
+vn 0.101245 0.360941 0.927077
+vn 0.101246 -0.360941 -0.927077
+vn 0.101246 -0.667784 -0.737437
+vn 0.102071 0.31476 -0.943667
+vn 0.102072 -0.31476 0.943667
+vn 0.102073 -0.984806 -0.140492
+vn 0.102073 0.984806 0.140492
+vn 0.1058 -0.00869608 -0.994349
+vn 0.1058 0.885484 0.452465
+vn 0.105801 -0.885484 -0.452464
+vn 0.105801 0.00869592 0.994349
+vn 0.165157 0.488415 -0.856839
+vn 0.165157 -0.488415 0.856839
+vn 0.165158 0.984806 -0.0536629
+vn 0.165158 -0.984806 0.0536629
+vn 0.1769 -0.644256 0.74407
+vn 0.1769 0.644256 -0.74407
+vn 0.176901 -0.953636 0.243484
+vn 0.176901 0.953636 -0.243484
+vn 0.180358 -0.779031 0.600485
+vn 0.180358 0.779031 -0.600485
+vn 0.180359 0.885484 -0.42824
+vn 0.180359 -0.885484 0.42824
+vn 0.190992 0.516052 0.834992
+vn 0.190993 -0.516052 -0.834992
+vn 0.207045 -0.180944 -0.961453
+vn 0.207045 0.77903 0.591814
+vn 0.207046 0.180943 0.961453
+vn 0.207047 -0.77903 -0.591814
+vn 0.207832 0.162469 -0.964577
+vn 0.207833 -0.162468 0.964577
+vn 0.207833 -0.935402 -0.286058
+vn 0.207833 0.935402 0.286058
+vn 0.286231 -0.343296 0.89455
+vn 0.286231 0.343296 -0.89455
+vn 0.286232 -0.953636 -0.0930024
+vn 0.286232 0.953636 0.0930024
+vn 0.294238 -0.343295 -0.891949
+vn 0.294238 0.343295 0.891948
+vn 0.294239 -0.644258 -0.705943
+vn 0.29424 0.644258 0.705943
+vn 0.309017 -8.52678e-007 -0.951057
+vn 0.309017 -6.87643e-008 0.951056
+vn 0.309017 -0.850651 -0.425326
+vn 0.309017 0.850651 0.425326
+vn 0.336281 -0.935402 0.109265
+vn 0.336281 -0.516052 0.787785
+vn 0.336281 0.516052 -0.787785
+vn 0.336281 0.935402 -0.109265
+vn 0.351546 0.667785 -0.656109
+vn 0.351546 -0.885484 0.303865
+vn 0.351546 0.885484 -0.303865
+vn 0.351546 -0.667785 0.656108
+vn 0.356821 0.794656 -0.491122
+vn 0.356822 -0.794655 0.491122
+vn 0.370022 -0.488416 -0.790274
+vn 0.370023 0.488416 0.790274
+vn 0.397626 -0.180943 0.89953
+vn 0.397626 -0.885484 -0.240442
+vn 0.397626 0.885484 0.240442
+vn 0.397626 0.180944 -0.899529
+vn 0.398824 0.162467 0.902521
+vn 0.398824 -0.162469 -0.90252
+vn 0.398824 -0.734582 -0.548934
+vn 0.398825 0.734582 0.548934
+vn 0.463014 -0.885484 -0.0391978
+vn 0.463014 0.885484 0.0391978
+vn 0.463014 -0.360941 0.80953
+vn 0.463014 0.360941 -0.80953
+vn 0.472095 -0.595743 -0.649782
+vn 0.472095 -0.314759 -0.82344
+vn 0.472095 0.595743 0.649782
+vn 0.472095 0.31476 0.823439
+vn 0.498869 -0.77903 -0.379792
+vn 0.498869 0.77903 0.379792
+vn 0.49887 -0.00869757 0.866633
+vn 0.498871 0.00869589 -0.866633
+vn 0.5 -0.850651 0.16246
+vn 0.5 0.850651 -0.16246
+vn 0.5 0.525729 -0.688192
+vn 0.500001 -0.52573 0.688191
+vn 0.515362 -0.77903 0.357091
+vn 0.515362 0.77903 -0.35709
+vn 0.515363 -0.667785 0.537089
+vn 0.515363 0.667785 -0.537089
+vn 0.525731 -0.447214 -0.723607
+vn 0.525731 0.447214 0.723607
+vn 0.577349 0.794656 0.187593
+vn 0.57735 -0.794655 -0.187592
+vn 0.57735 -0.187593 0.794655
+vn 0.57735 0.187593 -0.794655
+vn 0.580467 -0.644258 -0.497986
+vn 0.580467 0.644258 0.497986
+vn 0.580468 -0.157292 -0.798947
+vn 0.580469 0.157292 0.798946
+vn 0.626829 -0.360942 0.690512
+vn 0.626829 0.360942 -0.690512
+vn 0.626829 0.779031 -0.0140304
+vn 0.62683 -0.77903 0.0140295
+vn 0.637251 0.488417 0.596121
+vn 0.637251 0.31476 0.703447
+vn 0.637252 -0.488417 -0.59612
+vn 0.637252 -0.31476 -0.703446
+vn 0.64531 -0.516053 0.563262
+vn 0.645311 0.516052 -0.563262
+vn 0.645311 -0.734582 0.209674
+vn 0.645311 0.734582 -0.209674
+vn 0.652987 -0.644257 0.398172
+vn 0.652987 0.644257 -0.398171
+vn 0.670057 -0.667786 -0.324169
+vn 0.670057 0.667785 0.32417
+vn 0.670057 0.00869565 -0.742258
+vn 0.670058 -0.00869665 0.742258
+vn 0.732629 0.180942 -0.656136
+vn 0.732629 -0.667786 -0.131592
+vn 0.73263 0.667785 0.131592
+vn 0.73263 -0.180943 0.656135
+vn 0.735104 -0.162467 -0.6582
+vn 0.735104 -0.516053 -0.439671
+vn 0.735104 0.516054 0.43967
+vn 0.735104 0.162466 0.658199
+vn 0.757369 -0.343296 -0.555465
+vn 0.757369 0.343296 0.555464
+vn 0.762317 -0.644257 0.0616879
+vn 0.762317 0.343297 -0.548653
+vn 0.762317 0.644257 -0.0616893
+vn 0.762317 -0.343296 0.548653
+vn 0.763865 -0.595742 0.248195
+vn 0.763865 0.595742 -0.248195
+vn 0.763866 -0.488416 0.421851
+vn 0.763866 0.488416 -0.421851
+vn 0.809017 -5.86372e-007 -0.587785
+vn 0.809017 -0.525731 -0.262865
+vn 0.809017 -2.413e-007 0.587785
+vn 0.809018 0.52573 0.262865
+vn 0.850416 -0.180943 -0.494016
+vn 0.850416 -0.360941 -0.382771
+vn 0.850417 0.180942 0.494015
+vn 0.850417 0.360942 0.382769
+vn 0.850652 -0.447212 0.276392
+vn 0.850652 0.447212 -0.276393
+vn 0.853144 -0.516053 -0.0763836
+vn 0.853145 0.516052 0.0763834
+vn 0.853145 0.162466 -0.495731
+vn 0.853145 -0.162466 0.49573
+vn 0.865939 -0.488415 0.107705
+vn 0.865939 0.488415 -0.107705
+vn 0.865939 -0.31476 0.388685
+vn 0.865939 0.31476 -0.388684
+vn 0.912988 0.360942 0.190194
+vn 0.912988 0.00869627 0.407893
+vn 0.912988 -0.360941 -0.190194
+vn 0.912988 -0.00869702 -0.407893
+vn 0.929022 -0.314761 0.194533
+vn 0.929022 0.314761 -0.194533
+vn 0.934172 -0.187593 -0.303531
+vn 0.934172 0.187593 0.303531
+vn 0.939218 -0.157293 0.305171
+vn 0.939218 -0.343297 0.00421008
+vn 0.939218 0.343297 -0.0042101
+vn 0.939218 0.157293 -0.305171
+vn 0.978376 -0.0086971 -0.20665
+vn 0.978376 0.00869708 0.20665
+vn 0.978376 -0.180943 -0.100195
+vn 0.978376 0.180943 0.100195
+vn 0.981591 -0.162468 0.100411
+vn 0.981591 0.162468 -0.100411
+vn 1 -8.75182e-009 -1.62534e-008
+usemtl Default_Smoothing
+s 1
+f 181/292/176 182/250/182 209/210/208
+f 213/254/213 209/210/208 243/218/243
+f 181/292/176 213/254/213 180/291/179
+f 181/292/176 209/210/208 213/254/213
+f 247/235/246 243/218/243 275/216/273
+f 217/264/216 213/254/213 247/235/246
+f 180/291/179 217/264/216 179/290/175
+f 213/254/213 243/218/243 247/235/246
+f 180/291/179 213/254/213 217/264/216
+f 279/229/277 275/216/273 297/214/301
+f 249/247/248 247/235/246 279/229/277
+f 217/264/216 249/247/248 216/270/215
+f 179/290/175 216/270/215 178/289/178
+f 247/235/246 275/216/273 279/229/277
+f 217/264/216 247/235/246 249/247/248
+f 179/290/175 217/264/216 216/270/215
+f 303/228/303 297/214/301 321/213/323
+f 278/240/279 279/229/277 303/228/303
+f 246/259/244 249/247/248 278/240/279
+f 216/270/215 246/259/244 212/271/211
+f 178/289/178 212/271/211 177/288/177
+f 279/229/277 297/214/301 303/228/303
+f 249/247/248 279/229/277 278/240/279
+f 216/270/215 249/247/248 246/259/244
+f 178/289/178 216/270/215 212/271/211
+f 320/223/325 321/213/323 335/209/335
+f 296/238/299 303/228/303 320/223/325
+f 274/249/274 278/240/279 296/238/299
+f 246/259/244 274/249/274 242/261/242
+f 212/271/211 242/261/242 208/276/206
+f 177/288/177 208/276/206 176/287/181
+f 303/228/303 321/213/323 320/223/325
+f 278/240/279 303/228/303 296/238/299
+f 246/259/244 278/240/279 274/249/274
+f 212/271/211 246/259/244 242/261/242
+f 177/288/177 212/271/211 208/276/206
+f 209/210/208 182/171/182 201/133/201
+f 231/175/231 201/133/201 223/144/227
+f 209/210/208 231/175/231 243/218/243
+f 209/210/208 201/133/201 231/175/231
+f 255/161/254 223/144/227 239/142/239
+f 263/190/261 231/175/231 255/161/254
+f 243/218/243 263/190/261 275/216/273
+f 231/175/231 223/144/227 255/161/254
+f 243/218/243 231/175/231 263/190/261
+f 271/155/269 239/142/239 258/136/259
+f 285/181/282 255/161/254 271/155/269
+f 263/190/261 285/181/282 293/196/292
+f 275/216/273 293/196/292 297/214/301
+f 255/161/254 239/142/239 271/155/269
+f 263/190/261 255/161/254 285/181/282
+f 275/216/273 263/190/261 293/196/292
+f 288/154/287 258/136/259 267/141/266
+f 307/166/305 271/155/269 288/154/287
+f 311/185/310 285/181/282 307/166/305
+f 293/196/292 311/185/310 325/197/320
+f 297/214/301 325/197/320 321/213/323
+f 271/155/269 258/136/259 288/154/287
+f 285/181/282 271/155/269 307/166/305
+f 293/196/292 285/181/282 311/185/310
+f 297/214/301 293/196/292 325/197/320
+f 301/149/294 267/141/266 281/135/281
+f 315/164/314 288/154/287 301/149/294
+f 329/180/329 307/166/305 315/164/314
+f 311/185/310 329/180/329 339/187/337
+f 325/197/320 339/187/337 343/202/341
+f 321/213/323 343/202/341 335/209/335
+f 288/154/287 267/141/266 301/149/294
+f 307/166/305 288/154/287 315/164/314
+f 311/185/310 307/166/305 329/180/329
+f 325/197/320 311/185/310 339/187/337
+f 321/213/323 325/197/320 343/202/341
+f 201/133/201 182/107/182 165/70/163
+f 184/106/185 165/70/163 142/59/137
+f 201/133/201 184/106/185 223/144/227
+f 201/133/201 165/70/163 184/106/185
+f 169/87/160 142/59/137 127/61/127
+f 197/116/203 184/106/185 169/87/160
+f 223/144/227 197/116/203 239/142/239
+f 184/106/185 142/59/137 169/87/160
+f 223/144/227 184/106/185 197/116/203
+f 139/81/142 127/61/127 107/65/106
+f 187/105/186 169/87/160 139/81/142
+f 197/116/203 187/105/186 226/122/221
+f 239/142/239 226/122/221 258/136/259
+f 169/87/160 127/61/127 139/81/142
+f 197/116/203 169/87/160 187/105/186
+f 239/142/239 197/116/203 226/122/221
+f 131/80/129 107/65/106 99/60/99
+f 161/92/168 139/81/142 131/80/129
+f 205/111/194 187/105/186 161/92/168
+f 226/122/221 205/111/194 235/123/235
+f 258/136/259 235/123/235 267/141/266
+f 139/81/142 107/65/106 131/80/129
+f 187/105/186 139/81/142 161/92/168
+f 226/122/221 187/105/186 205/111/194
+f 258/136/259 226/122/221 235/123/235
+f 113/75/113 99/60/99 83/67/83
+f 145/90/144 131/80/129 113/75/113
+f 190/104/189 161/92/168 145/90/144
+f 205/111/194 190/104/189 219/113/218
+f 235/123/235 219/113/218 251/128/251
+f 267/141/266 251/128/251 281/135/281
+f 131/80/129 99/60/99 113/75/113
+f 161/92/168 131/80/129 145/90/144
+f 205/111/194 161/92/168 190/104/189
+f 235/123/235 205/111/194 219/113/218
+f 267/141/266 235/123/235 251/128/251
+f 182/32/182 157/2/155 165/70/163
+f 135/387/133 157/364/155 123/356/123
+f 165/70/163 135/27/133 142/59/137
+f 165/70/163 157/2/155 135/27/133
+f 103/383/102 123/356/123 91/357/90
+f 135/27/133 103/13/102 111/42/110
+f 142/59/137 111/42/110 127/61/127
+f 135/387/133 123/356/123 103/383/102
+f 142/59/137 135/27/133 111/42/110
+f 73/377/71 91/357/90 69/360/63
+f 81/31/79 103/13/102 73/7/71
+f 111/42/110 81/31/79 95/48/95
+f 127/61/127 95/48/95 107/65/106
+f 103/383/102 91/357/90 73/377/71
+f 111/42/110 103/13/102 81/31/79
+f 127/61/127 111/42/110 95/48/95
+f 41/376/44 69/360/63 45/359/40
+f 55/18/55 73/7/71 41/6/44
+f 81/31/79 55/18/55 59/37/58
+f 95/48/95 59/37/58 77/49/77
+f 107/65/106 77/49/77 99/60/99
+f 73/377/71 69/360/63 41/376/44
+f 81/31/79 73/7/71 55/18/55
+f 95/48/95 81/31/79 59/37/58
+f 107/65/106 95/48/95 77/49/77
+f 23/371/23 45/359/40 29/363/28
+f 27/385/27 41/376/44 23/371/23
+f 37/30/36 55/18/55 27/16/27
+f 59/37/58 37/30/36 51/39/51
+f 77/49/77 51/39/51 65/54/66
+f 99/60/99 65/54/66 83/67/83
+f 41/376/44 45/359/40 23/371/23
+f 55/18/55 41/6/44 27/16/27
+f 59/37/58 55/18/55 37/30/36
+f 77/49/77 59/37/58 51/39/51
+f 99/60/99 77/49/77 65/54/66
+f 182/323/182 181/292/176 157/364/155
+f 153/319/150 181/292/176 180/291/179
+f 157/364/155 153/319/150 123/356/123
+f 157/364/155 181/292/176 153/319/150
+f 149/309/148 180/291/179 179/290/175
+f 153/319/150 149/309/148 119/338/118
+f 123/356/123 119/338/118 91/357/90
+f 153/319/150 180/291/179 149/309/148
+f 123/356/123 153/319/150 119/338/118
+f 148/303/149 179/290/175 178/289/178
+f 115/327/114 149/309/148 148/303/149
+f 119/338/118 115/327/114 87/344/85
+f 91/357/90 87/344/85 69/360/63
+f 149/309/148 179/290/175 148/303/149
+f 119/338/118 149/309/148 115/327/114
+f 91/357/90 119/338/118 87/344/85
+f 152/302/152 178/289/178 177/288/177
+f 118/314/116 148/303/149 152/302/152
+f 115/327/114 118/314/116 86/333/84
+f 87/344/85 86/333/84 61/345/61
+f 69/360/63 61/345/61 45/359/40
+f 148/303/149 178/289/178 152/302/152
+f 115/327/114 148/303/149 118/314/116
+f 87/344/85 115/327/114 86/333/84
+f 69/360/63 87/344/85 61/345/61
+f 156/297/156 177/288/177 176/287/181
+f 122/312/122 152/302/152 156/297/156
+f 90/322/88 118/314/116 122/312/122
+f 86/333/84 90/322/88 68/335/65
+f 61/345/61 68/335/65 44/350/38
+f 45/359/40 44/350/38 29/363/28
+f 152/302/152 177/288/177 156/297/156
+f 118/314/116 152/302/152 122/312/122
+f 86/333/84 118/314/116 90/322/88
+f 61/345/61 86/333/84 68/335/65
+f 45/359/40 61/345/61 44/350/38
+f 198/255/200 206/178/209 175/217/180
+f 220/244/226 228/211/230 198/255/200
+f 228/211/230 240/170/240 206/178/209
+f 198/255/200 228/211/230 206/178/209
+f 236/245/238 252/227/253 220/244/226
+f 252/227/253 260/198/260 228/211/230
+f 260/198/260 272/172/272 240/170/240
+f 220/244/226 252/227/253 228/211/230
+f 260/198/260 240/170/240 228/211/230
+f 256/251/258 268/233/268 236/245/238
+f 268/233/268 282/207/283 252/227/253
+f 282/207/283 290/192/293 260/198/260
+f 290/192/293 294/176/300 272/172/272
+f 236/245/238 268/233/268 252/227/253
+f 252/227/253 282/207/283 260/198/260
+f 290/192/293 272/172/272 260/198/260
+f 264/246/264 286/234/286 256/251/258
+f 286/234/286 304/222/304 268/233/268
+f 304/222/304 308/203/309 282/207/283
+f 308/203/309 322/191/318 290/192/293
+f 322/191/318 318/173/322 294/176/300
+f 256/251/258 286/234/286 268/233/268
+f 268/233/268 304/222/304 282/207/283
+f 308/203/309 290/192/293 282/207/283
+f 322/191/318 294/176/300 290/192/293
+f 280/252/280 298/239/296 264/246/264
+f 298/239/296 312/224/313 286/234/286
+f 312/224/313 326/215/327 304/222/304
+f 326/215/327 336/201/336 308/203/309
+f 336/201/336 340/186/340 322/191/318
+f 340/186/340 334/179/334 318/173/322
+f 264/246/264 298/239/296 286/234/286
+f 286/234/286 312/224/313 304/222/304
+f 304/222/304 326/215/327 308/203/309
+f 336/201/336 322/191/318 308/203/309
+f 340/186/340 318/173/322 322/191/318
+f 206/178/209 183/96/183 175/138/180
+f 240/170/240 210/134/212 206/178/209
+f 210/134/212 185/97/184 183/96/183
+f 206/178/209 210/134/212 183/96/183
+f 272/172/272 244/153/245 240/170/240
+f 244/153/245 214/124/217 210/134/212
+f 214/124/217 186/98/187 185/97/184
+f 240/170/240 244/153/245 210/134/212
+f 214/124/217 185/97/184 210/134/212
+f 294/176/300 276/159/276 272/172/272
+f 276/159/276 248/140/249 244/153/245
+f 248/140/249 215/118/214 214/124/217
+f 215/118/214 188/99/188 186/98/187
+f 272/172/272 276/159/276 244/153/245
+f 244/153/245 248/140/249 214/124/217
+f 215/118/214 186/98/187 214/124/217
+f 318/173/322 302/160/302 294/176/300
+f 302/160/302 277/148/278 276/159/276
+f 277/148/278 245/129/247 248/140/249
+f 245/129/247 211/117/210 215/118/214
+f 211/117/210 189/100/190 188/99/188
+f 294/176/300 302/160/302 276/159/276
+f 276/159/276 277/148/278 248/140/249
+f 245/129/247 215/118/214 248/140/249
+f 211/117/210 188/99/188 215/118/214
+f 334/179/334 319/165/324 318/173/322
+f 319/165/324 295/150/298 302/160/302
+f 295/150/298 273/137/275 277/148/278
+f 273/137/275 241/127/241 245/129/247
+f 241/127/241 207/112/207 211/117/210
+f 207/112/207 191/101/191 189/100/190
+f 318/173/322 319/165/324 302/160/302
+f 302/160/302 295/150/298 277/148/278
+f 277/148/278 273/137/275 245/129/247
+f 241/127/241 211/117/210 245/129/247
+f 207/112/207 189/100/190 211/117/210
+f 183/96/183 154/22/154 175/63/180
+f 185/97/184 150/69/151 183/96/183
+f 150/69/151 120/33/120 154/22/154
+f 150/69/151 154/22/154 183/96/183
+f 186/98/187 146/79/146 185/97/184
+f 146/79/146 116/50/117 150/69/151
+f 116/50/117 88/29/91 120/33/120
+f 185/97/184 146/79/146 150/69/151
+f 116/50/117 120/33/120 150/69/151
+f 188/99/188 147/85/147 186/98/187
+f 147/85/147 114/62/115 146/79/146
+f 114/62/115 84/44/87 116/50/117
+f 84/44/87 66/25/62 88/29/91
+f 186/98/187 147/85/147 146/79/146
+f 114/62/115 116/50/117 146/79/146
+f 84/44/87 88/29/91 116/50/117
+f 189/100/190 151/86/153 188/99/188
+f 151/86/153 117/74/119 147/85/147
+f 117/74/119 85/55/86 114/62/115
+f 85/55/86 60/43/60 84/44/87
+f 60/43/60 42/26/41 66/25/62
+f 188/99/188 151/86/153 147/85/147
+f 147/85/147 117/74/119 114/62/115
+f 85/55/86 84/44/87 114/62/115
+f 60/43/60 66/25/62 84/44/87
+f 191/101/191 155/91/157 189/100/190
+f 155/91/157 121/76/121 151/86/153
+f 121/76/121 89/64/89 117/74/119
+f 89/64/89 67/53/64 85/55/86
+f 67/53/64 43/38/39 60/43/60
+f 43/38/39 28/23/29 42/26/41
+f 189/100/190 155/91/157 151/86/153
+f 151/86/153 121/76/121 117/74/119
+f 89/64/89 85/55/86 117/74/119
+f 67/53/64 60/43/60 85/55/86
+f 43/38/39 42/26/41 60/43/60
+f 154/386/154 162/318/162 175/355/180
+f 120/33/120 132/1/132 154/22/154
+f 132/361/132 140/329/136 162/318/162
+f 132/361/132 162/318/162 154/386/154
+f 88/29/91 100/5/101 120/33/120
+f 100/375/101 108/346/108 132/361/132
+f 108/346/108 124/324/124 140/329/136
+f 120/33/120 100/5/101 132/1/132
+f 108/346/108 140/329/136 132/361/132
+f 66/25/62 70/11/72 88/29/91
+f 70/381/72 78/365/81 100/375/101
+f 78/365/81 92/340/94 108/346/108
+f 92/340/94 104/328/104 124/324/124
+f 88/29/91 70/11/72 100/5/101
+f 78/365/81 108/346/108 100/375/101
+f 92/340/94 124/324/124 108/346/108
+f 42/26/41 38/12/43 66/25/62
+f 38/382/43 52/370/52 70/381/72
+f 52/370/52 56/351/59 78/365/81
+f 56/351/59 74/339/76 92/340/94
+f 74/339/76 96/325/97 104/328/104
+f 66/25/62 38/12/43 70/11/72
+f 70/381/72 52/370/52 78/365/81
+f 56/351/59 92/340/94 78/365/81
+f 74/339/76 104/328/104 92/340/94
+f 28/23/29 20/17/22 42/26/41
+f 20/17/22 24/3/25 38/12/43
+f 24/372/25 34/366/34 52/370/52
+f 34/366/34 48/349/48 56/351/59
+f 48/349/48 62/334/68 74/339/76
+f 62/334/68 82/320/82 96/325/97
+f 42/26/41 20/17/22 38/12/43
+f 38/382/43 24/372/25 52/370/52
+f 34/366/34 56/351/59 52/370/52
+f 48/349/48 74/339/76 56/351/59
+f 62/334/68 96/325/97 74/339/76
+f 162/318/162 198/255/200 175/281/180
+f 140/329/136 174/282/173 162/318/162
+f 174/282/173 220/244/226 198/255/200
+f 174/282/173 198/255/200 162/318/162
+f 124/324/124 166/301/159 140/329/136
+f 166/301/159 194/272/204 174/282/173
+f 194/272/204 236/245/238 220/244/226
+f 140/329/136 166/301/159 174/282/173
+f 194/272/204 220/244/226 174/282/173
+f 104/328/104 136/307/140 124/324/124
+f 136/307/140 172/283/193 166/301/159
+f 172/283/193 224/266/223 194/272/204
+f 224/266/223 256/251/258 236/245/238
+f 124/324/124 136/307/140 166/301/159
+f 172/283/193 194/272/204 166/301/159
+f 224/266/223 236/245/238 194/272/204
+f 96/325/97 128/308/128 104/328/104
+f 128/308/128 158/296/167 136/307/140
+f 158/296/167 202/277/197 172/283/193
+f 202/277/197 232/265/234 224/266/223
+f 232/265/234 264/246/264 256/251/258
+f 104/328/104 128/308/128 136/307/140
+f 136/307/140 158/296/167 172/283/193
+f 202/277/197 224/266/223 172/283/193
+f 232/265/234 256/251/258 224/266/223
+f 82/320/82 112/313/112 96/325/97
+f 112/313/112 144/298/145 128/308/128
+f 144/298/145 170/284/172 158/296/167
+f 170/284/172 218/275/219 202/277/197
+f 218/275/219 250/260/250 232/265/234
+f 250/260/250 280/252/280 264/246/264
+f 96/325/97 112/313/112 128/308/128
+f 128/308/128 144/298/145 158/296/167
+f 158/296/167 170/284/172 202/277/197
+f 218/275/219 232/265/234 202/277/197
+f 250/260/250 264/246/264 232/265/234
+f 176/287/181 208/276/206 200/279/198
+f 208/276/206 242/261/242 230/269/229
+f 200/279/198 230/269/229 222/274/224
+f 208/276/206 230/269/229 200/279/198
+f 242/261/242 274/249/274 262/258/263
+f 230/269/229 262/258/263 254/263/255
+f 222/274/224 254/263/255 238/268/236
+f 242/261/242 262/258/263 230/269/229
+f 230/269/229 254/263/255 222/274/224
+f 274/249/274 296/238/299 292/241/291
+f 262/258/263 292/241/291 284/248/285
+f 254/263/255 284/248/285 270/256/271
+f 238/268/236 270/256/271 257/262/257
+f 262/258/263 274/249/274 292/241/291
+f 262/258/263 284/248/285 254/263/255
+f 238/268/236 254/263/255 270/256/271
+f 296/238/299 320/223/325 324/230/319
+f 292/241/291 324/230/319 310/236/308
+f 284/248/285 310/236/308 306/243/306
+f 270/256/271 306/243/306 287/253/288
+f 257/262/257 287/253/288 265/257/265
+f 292/241/291 296/238/299 324/230/319
+f 284/248/285 292/241/291 310/236/308
+f 270/256/271 284/248/285 306/243/306
+f 257/262/257 270/256/271 287/253/288
+f 320/223/325 335/209/335 342/220/343
+f 324/230/319 342/220/343 338/225/338
+f 310/236/308 338/225/338 328/231/326
+f 306/243/306 328/231/326 313/237/312
+f 287/253/288 313/237/312 299/242/297
+f 265/257/265 299/242/297 280/252/280
+f 324/230/319 320/223/325 342/220/343
+f 310/236/308 324/230/319 338/225/338
+f 306/243/306 310/236/308 328/231/326
+f 306/243/306 313/237/312 287/253/288
+f 265/257/265 287/253/288 299/242/297
+f 335/209/335 343/202/341 349/205/349
+f 343/202/341 339/187/337 355/195/354
+f 349/205/349 355/195/354 361/200/361
+f 343/202/341 355/195/354 349/205/349
+f 339/187/337 329/180/329 347/184/344
+f 355/195/354 347/184/344 359/189/359
+f 361/200/361 359/189/359 362/194/362
+f 339/187/337 347/184/344 355/195/354
+f 355/195/354 359/189/359 361/200/361
+f 329/180/329 315/164/314 333/167/333
+f 347/184/344 333/167/333 351/174/351
+f 359/189/359 351/174/351 357/182/357
+f 362/194/362 357/182/357 360/188/360
+f 347/184/344 329/180/329 333/167/333
+f 347/184/344 351/174/351 359/189/359
+f 362/194/362 359/189/359 357/182/357
+f 315/164/314 301/149/294 317/156/317
+f 333/167/333 317/156/317 332/162/332
+f 351/174/351 332/162/332 345/169/345
+f 357/182/357 345/169/345 353/177/352
+f 360/188/360 353/177/352 348/183/348
+f 333/167/333 315/164/314 317/156/317
+f 351/174/351 333/167/333 332/162/332
+f 357/182/357 351/174/351 345/169/345
+f 360/188/360 357/182/357 353/177/352
+f 301/149/294 281/135/281 300/146/295
+f 317/156/317 300/146/295 314/151/315
+f 332/162/332 314/151/315 327/157/328
+f 345/169/345 327/157/328 337/163/339
+f 353/177/352 337/163/339 341/168/342
+f 348/183/348 341/168/342 334/179/334
+f 317/156/317 301/149/294 300/146/295
+f 332/162/332 317/156/317 314/151/315
+f 345/169/345 332/162/332 327/157/328
+f 345/169/345 337/163/339 353/177/352
+f 348/183/348 353/177/352 341/168/342
+f 281/135/281 251/128/251 266/131/267
+f 251/128/251 219/113/218 234/121/233
+f 266/131/267 234/121/233 259/126/256
+f 251/128/251 234/121/233 266/131/267
+f 219/113/218 190/104/189 204/110/195
+f 234/121/233 204/110/195 227/115/222
+f 259/126/256 227/115/222 237/120/237
+f 219/113/218 204/110/195 234/121/233
+f 234/121/233 227/115/222 259/126/256
+f 190/104/189 145/90/144 160/93/166
+f 204/110/195 160/93/166 192/103/170
+f 227/115/222 192/103/170 195/108/205
+f 237/120/237 195/108/205 221/114/225
+f 204/110/195 190/104/189 160/93/166
+f 204/110/195 192/103/170 227/115/222
+f 237/120/237 227/115/222 195/108/205
+f 145/90/144 113/75/113 130/82/131
+f 160/93/166 130/82/131 138/88/143
+f 192/103/170 138/88/143 167/95/161
+f 195/108/205 167/95/161 193/102/171
+f 221/114/225 193/102/171 199/109/199
+f 160/93/166 145/90/144 130/82/131
+f 192/103/170 160/93/166 138/88/143
+f 195/108/205 192/103/170 167/95/161
+f 221/114/225 195/108/205 193/102/171
+f 113/75/113 83/67/83 98/72/98
+f 130/82/131 98/72/98 106/77/105
+f 138/88/143 106/77/105 125/83/126
+f 167/95/161 125/83/126 143/89/139
+f 193/102/171 143/89/139 163/94/164
+f 199/109/199 163/94/164 191/101/191
+f 130/82/131 113/75/113 98/72/98
+f 138/88/143 130/82/131 106/77/105
+f 138/88/143 125/83/126 167/95/161
+f 167/95/161 143/89/139 193/102/171
+f 199/109/199 193/102/171 163/94/164
+f 83/67/83 65/54/66 64/57/67
+f 65/54/66 51/39/51 47/47/47
+f 64/57/67 47/47/47 50/52/50
+f 65/54/66 47/47/47 64/57/67
+f 51/39/51 37/30/36 33/36/33
+f 47/47/47 33/36/33 32/41/32
+f 50/52/50 32/41/32 35/46/37
+f 51/39/51 33/36/33 47/47/47
+f 47/47/47 32/41/32 50/52/50
+f 37/30/36 27/16/27 19/19/16
+f 33/36/33 19/19/16 13/28/12
+f 32/41/32 13/28/12 17/34/17
+f 35/46/37 17/34/17 25/40/26
+f 37/30/36 19/19/16 33/36/33
+f 33/36/33 13/28/12 32/41/32
+f 32/41/32 17/34/17 35/46/37
+f 27/385/27 23/371/23 11/378/10
+f 19/19/16 11/8/10 7/14/5
+f 13/28/12 7/14/5 5/21/7
+f 17/34/17 5/21/7 9/24/8
+f 25/40/26 9/24/8 21/35/21
+f 19/19/16 27/16/27 11/8/10
+f 13/28/12 19/19/16 7/14/5
+f 13/28/12 5/21/7 17/34/17
+f 25/40/26 17/34/17 9/24/8
+f 23/371/23 29/363/28 15/368/15
+f 11/378/10 15/368/15 3/373/3
+f 7/384/5 3/373/3 1/379/1
+f 5/21/7 1/9/1 2/15/2
+f 9/24/8 2/15/2 14/20/14
+f 21/35/21 14/20/14 28/23/29
+f 11/378/10 23/371/23 15/368/15
+f 7/384/5 11/378/10 3/373/3
+f 7/14/5 1/9/1 5/21/7
+f 5/21/7 2/15/2 9/24/8
+f 9/24/8 14/20/14 21/35/21
+f 29/363/28 44/350/38 22/353/20
+f 44/350/38 68/335/65 40/343/42
+f 22/353/20 40/343/42 26/348/24
+f 44/350/38 40/343/42 22/353/20
+f 68/335/65 90/322/88 72/332/73
+f 40/343/42 72/332/73 53/337/53
+f 26/348/24 53/337/53 36/342/35
+f 68/335/65 72/332/73 40/343/42
+f 40/343/42 53/337/53 26/348/24
+f 90/322/88 122/312/122 102/315/100
+f 72/332/73 102/315/100 80/321/80
+f 53/337/53 80/321/80 58/330/57
+f 36/342/35 58/330/57 49/336/49
+f 90/322/88 102/315/100 72/332/73
+f 72/332/73 80/321/80 53/337/53
+f 53/337/53 58/330/57 36/342/35
+f 122/312/122 156/297/156 134/304/134
+f 102/315/100 134/304/134 110/310/109
+f 80/321/80 110/310/109 94/317/93
+f 58/330/57 94/317/93 75/326/74
+f 49/336/49 75/326/74 63/331/69
+f 102/315/100 122/312/122 134/304/134
+f 80/321/80 102/315/100 110/310/109
+f 80/321/80 94/317/93 58/330/57
+f 49/336/49 58/330/57 75/326/74
+f 156/297/156 176/287/181 164/294/165
+f 134/304/134 164/294/165 141/299/138
+f 110/310/109 141/299/138 126/305/125
+f 94/317/93 126/305/125 105/311/107
+f 75/326/74 105/311/107 97/316/96
+f 63/331/69 97/316/96 82/320/82
+f 134/304/134 156/297/156 164/294/165
+f 110/310/109 134/304/134 141/299/138
+f 110/310/109 126/305/125 94/317/93
+f 94/317/93 105/311/107 75/326/74
+f 75/326/74 97/316/96 63/331/69
+f 348/183/348 334/179/334 340/186/340
+f 352/193/353 340/186/340 336/201/336
+f 360/188/360 348/183/348 352/193/353
+f 352/193/353 348/183/348 340/186/340
+f 344/204/346 336/201/336 326/215/327
+f 356/199/358 352/193/353 344/204/346
+f 362/194/362 360/188/360 356/199/358
+f 344/204/346 352/193/353 336/201/336
+f 356/199/358 360/188/360 352/193/353
+f 312/224/313 330/221/331 326/215/327
+f 330/221/331 350/212/350 344/204/346
+f 358/206/356 356/199/358 350/212/350
+f 358/206/356 361/200/361 362/194/362
+f 330/221/331 344/204/346 326/215/327
+f 350/212/350 356/199/358 344/204/346
+f 358/206/356 362/194/362 356/199/358
+f 298/239/296 316/232/316 312/224/313
+f 316/232/316 331/226/330 330/221/331
+f 331/226/330 346/219/347 350/212/350
+f 346/219/347 354/208/355 358/206/356
+f 354/208/355 349/205/349 361/200/361
+f 316/232/316 330/221/331 312/224/313
+f 331/226/330 350/212/350 330/221/331
+f 346/219/347 358/206/356 350/212/350
+f 354/208/355 361/200/361 358/206/356
+f 280/252/280 299/242/297 298/239/296
+f 299/242/297 313/237/312 316/232/316
+f 313/237/312 328/231/326 331/226/330
+f 328/231/326 338/225/338 346/219/347
+f 342/220/343 354/208/355 338/225/338
+f 342/220/343 335/209/335 349/205/349
+f 299/242/297 316/232/316 298/239/296
+f 313/237/312 331/226/330 316/232/316
+f 328/231/326 346/219/347 331/226/330
+f 338/225/338 354/208/355 346/219/347
+f 342/220/343 349/205/349 354/208/355
+f 199/109/199 191/101/191 207/112/207
+f 229/119/228 207/112/207 241/127/241
+f 221/114/225 199/109/199 229/119/228
+f 229/119/228 199/109/199 207/112/207
+f 261/130/262 241/127/241 273/137/275
+f 253/125/252 229/119/228 261/130/262
+f 237/120/237 221/114/225 253/125/252
+f 261/130/262 229/119/228 241/127/241
+f 253/125/252 221/114/225 229/119/228
+f 295/150/298 291/147/290 273/137/275
+f 291/147/290 283/139/284 261/130/262
+f 269/132/270 253/125/252 283/139/284
+f 269/132/270 259/126/256 237/120/237
+f 291/147/290 261/130/262 273/137/275
+f 283/139/284 253/125/252 261/130/262
+f 269/132/270 237/120/237 253/125/252
+f 319/165/324 323/158/321 295/150/298
+f 323/158/321 309/152/311 291/147/290
+f 309/152/311 305/145/307 283/139/284
+f 305/145/307 289/143/289 269/132/270
+f 289/143/289 266/131/267 259/126/256
+f 323/158/321 291/147/290 295/150/298
+f 309/152/311 283/139/284 291/147/290
+f 305/145/307 269/132/270 283/139/284
+f 289/143/289 259/126/256 269/132/270
+f 334/179/334 341/168/342 319/165/324
+f 341/168/342 337/163/339 323/158/321
+f 337/163/339 327/157/328 309/152/311
+f 327/157/328 314/151/315 305/145/307
+f 300/146/295 289/143/289 314/151/315
+f 300/146/295 281/135/281 266/131/267
+f 341/168/342 323/158/321 319/165/324
+f 337/163/339 309/152/311 323/158/321
+f 327/157/328 305/145/307 309/152/311
+f 314/151/315 289/143/289 305/145/307
+f 300/146/295 266/131/267 289/143/289
+f 21/35/21 28/23/29 43/38/39
+f 39/45/45 43/38/39 67/53/64
+f 25/40/26 21/35/21 39/45/45
+f 39/45/45 21/35/21 43/38/39
+f 71/56/70 67/53/64 89/64/89
+f 54/51/54 39/45/45 71/56/70
+f 35/46/37 25/40/26 54/51/54
+f 71/56/70 39/45/45 67/53/64
+f 54/51/54 25/40/26 39/45/45
+f 121/76/121 101/73/103 89/64/89
+f 79/68/78 71/56/70 101/73/103
+f 57/58/56 54/51/54 79/68/78
+f 50/52/50 35/46/37 57/58/56
+f 101/73/103 71/56/70 89/64/89
+f 79/68/78 54/51/54 71/56/70
+f 57/58/56 35/46/37 54/51/54
+f 155/91/157 133/84/135 121/76/121
+f 133/84/135 109/78/111 101/73/103
+f 109/78/111 93/71/92 79/68/78
+f 76/66/75 57/58/56 93/71/92
+f 76/66/75 64/57/67 50/52/50
+f 133/84/135 101/73/103 121/76/121
+f 109/78/111 79/68/78 101/73/103
+f 93/71/92 57/58/56 79/68/78
+f 76/66/75 50/52/50 57/58/56
+f 191/101/191 163/94/164 155/91/157
+f 163/94/164 143/89/139 133/84/135
+f 143/89/139 125/83/126 109/78/111
+f 106/77/105 93/71/92 125/83/126
+f 98/72/98 76/66/75 106/77/105
+f 83/67/83 64/57/67 98/72/98
+f 163/94/164 133/84/135 155/91/157
+f 143/89/139 109/78/111 133/84/135
+f 125/83/126 93/71/92 109/78/111
+f 106/77/105 76/66/75 93/71/92
+f 98/72/98 64/57/67 76/66/75
+f 63/331/69 82/320/82 62/334/68
+f 46/341/46 62/334/68 48/349/48
+f 49/336/49 63/331/69 46/341/46
+f 46/341/46 63/331/69 62/334/68
+f 30/352/31 48/349/48 34/366/34
+f 31/347/30 46/341/46 30/352/31
+f 36/342/35 49/336/49 31/347/30
+f 30/352/31 46/341/46 48/349/48
+f 31/347/30 49/336/49 46/341/46
+f 24/372/25 16/369/18 34/366/34
+f 12/358/13 30/352/31 16/369/18
+f 18/354/19 31/347/30 12/358/13
+f 26/348/24 36/342/35 18/354/19
+f 16/369/18 30/352/31 34/366/34
+f 12/358/13 31/347/30 30/352/31
+f 18/354/19 36/342/35 31/347/30
+f 20/17/22 8/10/9 24/3/25
+f 8/380/9 4/374/4 16/369/18
+f 4/374/4 6/367/6 12/358/13
+f 10/362/11 18/354/19 6/367/6
+f 10/362/11 22/353/20 26/348/24
+f 8/380/9 16/369/18 24/372/25
+f 4/374/4 12/358/13 16/369/18
+f 6/367/6 18/354/19 12/358/13
+f 10/362/11 26/348/24 18/354/19
+f 28/23/29 14/20/14 20/17/22
+f 14/20/14 2/15/2 8/10/9
+f 2/15/2 1/9/1 4/4/4
+f 3/373/3 6/367/6 1/379/1
+f 15/368/15 10/362/11 3/373/3
+f 29/363/28 22/353/20 15/368/15
+f 14/20/14 8/10/9 20/17/22
+f 2/15/2 4/4/4 8/10/9
+f 1/379/1 6/367/6 4/374/4
+f 3/373/3 10/362/11 6/367/6
+f 15/368/15 22/353/20 10/362/11
+f 265/257/265 280/252/280 250/260/250
+f 233/267/232 250/260/250 218/275/219
+f 257/262/257 265/257/265 233/267/232
+f 233/267/232 265/257/265 250/260/250
+f 203/278/196 218/275/219 170/284/172
+f 225/273/220 233/267/232 203/278/196
+f 238/268/236 257/262/257 225/273/220
+f 203/278/196 233/267/232 218/275/219
+f 225/273/220 257/262/257 233/267/232
+f 144/298/145 159/295/169 170/284/172
+f 159/295/169 171/285/192 203/278/196
+f 196/280/202 225/273/220 171/285/192
+f 196/280/202 222/274/224 238/268/236
+f 159/295/169 203/278/196 170/284/172
+f 171/285/192 225/273/220 203/278/196
+f 196/280/202 238/268/236 225/273/220
+f 112/313/112 129/306/130 144/298/145
+f 129/306/130 137/300/141 159/295/169
+f 137/300/141 168/293/158 171/285/192
+f 168/293/158 173/286/174 196/280/202
+f 173/286/174 200/279/198 222/274/224
+f 129/306/130 159/295/169 144/298/145
+f 137/300/141 171/285/192 159/295/169
+f 168/293/158 196/280/202 171/285/192
+f 173/286/174 222/274/224 196/280/202
+f 82/320/82 97/316/96 112/313/112
+f 97/316/96 105/311/107 129/306/130
+f 105/311/107 126/305/125 137/300/141
+f 141/299/138 168/293/158 126/305/125
+f 164/294/165 173/286/174 141/299/138
+f 164/294/165 176/287/181 200/279/198
+f 97/316/96 129/306/130 112/313/112
+f 105/311/107 137/300/141 129/306/130
+f 126/305/125 168/293/158 137/300/141
+f 141/299/138 173/286/174 168/293/158
+f 164/294/165 200/279/198 173/286/174
diff --git a/hw3/include/.directory b/hw3/include/.directory
new file mode 100644
index 0000000..f009e80
--- /dev/null
+++ b/hw3/include/.directory
@@ -0,0 +1,4 @@
+[Dolphin]
+Timestamp=2016,2,3,13,45,20
+Version=3
+ViewMode=1
diff --git a/hw3/include/boundedCompound.h b/hw3/include/boundedCompound.h
new file mode 100644
index 0000000..ab396f3
--- /dev/null
+++ b/hw3/include/boundedCompound.h
@@ -0,0 +1,55 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _BOUNDED_COMPOUND_H_
+#define _BOUNDED_COMPOUND_H_
+
+#include "intersector_base.h"
+#include "transformation3d.h"
+#include "boundedPrimitive.h"
+
+class boundedCompound : public boundedPrimitive {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ boundedCompound(void);
+ boundedCompound(const transformation3d& transform, const std::shared_ptr<const shader_base>& shader=nullptr);
+ boundedCompound(const boundedCompound&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ boundedCompound& operator=(const boundedCompound&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ void initialize(const class intersector_factory_base& ifb);
+
+ virtual bool hasShader(void) const override;
+
+ virtual intersectionPoint intersect(const ray& r) const final override;
+
+ virtual const std::vector<std::shared_ptr<const boundedPrimitive>>& compounds(void) const = 0;
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ void initializeBoundingBox(void);
+ virtual void _print(std::ostream& s) const override;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ transformation3d _transform;
+ std::unique_ptr<const intersector_base> _intersector;
+};
+
+#endif /* _BOUNDED_COMPOUND_H_ */
diff --git a/hw3/include/boundedPrimitive.h b/hw3/include/boundedPrimitive.h
new file mode 100644
index 0000000..ef467a2
--- /dev/null
+++ b/hw3/include/boundedPrimitive.h
@@ -0,0 +1,67 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _BOUNDED_PRIMITIVE_H_
+#define _BOUNDED_PRIMITIVE_H_
+
+#include <vector>
+#include <memory>
+#include <ostream>
+
+#include "ray.h"
+#include "shader_base.h"
+#include "boundingBox.h"
+#include "intersectionPoint.h"
+
+class boundedPrimitive {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ boundedPrimitive(void);
+ boundedPrimitive(const boundingBox& bb, const std::shared_ptr<const shader_base>& shader);
+ boundedPrimitive(const boundedPrimitive&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ boundedPrimitive& operator=(const boundedPrimitive& ) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ const boundingBox& boundingbox(void) const;
+ bool hitBoundingBox(const ray& r) const;
+ virtual bool hasShader(void) const;
+
+ virtual intersectionPoint intersect(const ray& r) const = 0;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend std::ostream& operator<<(std::ostream& s, const boundedPrimitive& bp)
+ {
+ bp._print(s);
+ return s;
+ }
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ boundingBox _bb;
+ std::shared_ptr<const shader_base> _shader;
+};
+
+#endif /* _BOUNDED_PRIMITIVE_H_ */
+
diff --git a/hw3/include/boundedTriangle.h b/hw3/include/boundedTriangle.h
new file mode 100644
index 0000000..965c0ff
--- /dev/null
+++ b/hw3/include/boundedTriangle.h
@@ -0,0 +1,46 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _BOUNDEDTRIANGLE_H_
+#define _BOUNDEDTRIANGLE_H_
+
+#include "triangle.h"
+#include "boundedPrimitive.h"
+
+class boundedTriangle : public boundedPrimitive {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ boundedTriangle(void);
+ boundedTriangle(const triangle& tri, const std::shared_ptr<const shader_base>& shader);
+ boundedTriangle(const boundedTriangle&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ boundedTriangle& operator=(const boundedTriangle&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual intersectionPoint intersect(const ray& r) const final override;
+
+ private:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const override;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ triangle _triangle;
+};
+
+#endif /* _BOUNDEDTRIANGLE_H_ */
diff --git a/hw3/include/boundingBox.h b/hw3/include/boundingBox.h
new file mode 100644
index 0000000..522672e
--- /dev/null
+++ b/hw3/include/boundingBox.h
@@ -0,0 +1,77 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _BOUNDINGBOX_H_
+#define _BOUNDINGBOX_H_
+
+#include <ostream>
+
+#include "ray.h"
+#include "vec3d.h"
+#include "transformation3d.h"
+
+class boundingBox {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ boundingBox(void);
+ boundingBox(const vec3d& lfb, const vec3d& rbt);
+ boundingBox(const boundingBox& bb);
+
+ //////////////
+ // Operator //
+ //////////////
+ boundingBox& operator=(const boundingBox& src);
+
+ boundingBox& operator+=(const boundingBox& bb);
+ boundingBox& operator+=(const vec3d& point);
+
+ boundingBox operator+(const boundingBox& bb) const;
+
+ /////////////
+ // Methods //
+ /////////////
+ bool isHit(const ray& r) const;
+
+ vec3d center(void) const;
+ vec3d corner(bool left, bool front, bool bottom) const;
+
+ //////////////
+ // Mutators //
+ //////////////
+ boundingBox& transform(const transformation3d& t);
+ boundingBox& inverseTransform(const transformation3d& t);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(boundingBox& a, boundingBox& b) { a._swap(b); }
+ friend boundingBox transform(const boundingBox& bb, const transformation3d& t) { return boundingBox(bb).transform(t); }
+ friend boundingBox inverseTransform(const boundingBox& bb, const transformation3d& t) { return boundingBox(bb).inverseTransform(t); }
+ friend std::ostream& operator<<(std::ostream& s, const boundingBox& bb)
+ {
+ s << bb._lfb << " - " << bb._rbt;
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _swap(boundingBox& bb);
+ void _assign(const boundingBox& bb);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ vec3d _lfb, _rbt;
+};
+
+
+#endif /* _BOUNDINGBOX_H_ */
diff --git a/hw3/include/brdf_base.h b/hw3/include/brdf_base.h
new file mode 100644
index 0000000..e0d8009
--- /dev/null
+++ b/hw3/include/brdf_base.h
@@ -0,0 +1,47 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _BRDF_BASE_H_
+#define _BRDF_BASE_H_
+
+#include <ostream>
+#include "vec3d.h"
+#include "color.h"
+
+class brdf_base {
+ public:
+ /////////////
+ // Methods //
+ /////////////
+
+ // Note: 'in' and 'out' point away from the surface point
+ // Note: 'in' and 'out' are specified in the local shading frame,
+ // where the normal=(0.0, 0.0, 1.0).
+ virtual color shade(const vec3d& in, const vec3d& out) const = 0;
+
+ // returns true if BRDF has a specular/diffuse component
+ virtual bool isSpecular(void) const = 0;
+ virtual bool isDiffuse(void) const = 0;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend std::ostream& operator<<(std::ostream& s, const brdf_base& b)
+ {
+ b._print(s);
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ virtual void _print(std::ostream& s) const = 0;
+};
+
+#endif /* _BRDF_BASE_H_ */
diff --git a/hw3/include/camera.h b/hw3/include/camera.h
new file mode 100644
index 0000000..9e3be04
--- /dev/null
+++ b/hw3/include/camera.h
@@ -0,0 +1,80 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _CAMERA_H_
+#define _CAMERA_H_
+
+#include <ostream>
+
+#include "ray.h"
+#include "vec2d.h"
+#include "boundingBox.h"
+
+/**************************************************************/
+/* Note: Field of View (fov) is expressed in degrees, and */
+/* represents the angular spread in the horizontal direction. */
+/**************************************************************/
+class camera {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ camera(void);
+ camera(const vec3d& eye, const vec3d& viewDirection, const vec3d& up, float fov, size_t xres, size_t yres);
+ camera(const camera& cam);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ camera& operator=(const camera& cam);
+
+ ray operator()(float x, float y) const;
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ size_t width(void) const { return _width; }
+ size_t height(void) const { return _height; }
+
+ //////////////
+ // Mutators //
+ //////////////
+ void frameBoundingBox(const boundingBox& bb);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(camera& a, camera& b) { a._swap(b); }
+ friend std::ostream& operator<<(std::ostream& s, const camera& cam)
+ {
+ s << "Camera: {";
+ s << "eye=" << cam._eye << ", ";
+ s << "view=" << cam._view << ", ";
+ s << "up=" << cam._up << "}, ";
+ s << "fov=" << cam._fov << ", ";
+ s << "resolution=[" << cam._width << "x" << cam._height << "]";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _swap(camera& cam);
+ void _assign(const camera& cam);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ vec3d _eye, _view, _up;
+ float _fov;
+ size_t _width, _height;
+};
+
+#endif /* _CAMERA_H_ */
+
diff --git a/hw3/include/color.h b/hw3/include/color.h
new file mode 100644
index 0000000..b2ca490
--- /dev/null
+++ b/hw3/include/color.h
@@ -0,0 +1,105 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _COLOR_H_
+#define _COLOR_H_
+
+#include <ostream>
+
+class color {
+ public:
+ /////////////
+ // Typedef //
+ /////////////
+ typedef float value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ union {
+ struct { value_type r, g, b; };
+ struct { value_type red, green, blue; };
+ value_type data[3];
+ };
+
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ explicit color(const_reference value=0.0f);
+ color(const_reference r, const_reference g, const_reference b);
+ color(const color& col);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ const_reference operator[](size_t index) const;
+ reference operator[](size_t index);
+
+ size_t size(void) const { return 3; }
+
+ iterator begin(void);
+ const_iterator begin(void) const;
+ iterator end(void);
+ const_iterator end(void) const;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ color& operator=(const color& col);
+
+ bool operator==(const color& col) const;
+ bool operator!=(const color& col) const;
+
+ color operator+(const color& col) const;
+ color operator-(const color& col) const;
+ color operator*(const color& col) const;
+ color operator*(const_reference scale) const;
+ color operator/(const color& col) const;
+ color operator/(const_reference scale) const;
+
+ color& operator+=(const color& col);
+ color& operator-=(const color& col);
+ color& operator*=(const color& col);
+ color& operator*=(const_reference scale);
+ color& operator/=(const color& col);
+ color& operator/=(const_reference scale);
+
+ ///////////////
+ // Modifiers //
+ ///////////////
+ color& abs(void);
+ color& clamp(const_reference lowerBound=0.0f, const_reference upperBounds=1.0f);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(color& a, color& b) { return a._swap(b); }
+ friend color abs(const color& c) { return color(c).abs(); }
+ friend color clamp(const color& c, const_reference lowerBound=0.0f, const_reference upperBound=1.0f) { return color(c).clamp(lowerBound, upperBound); }
+ friend color operator*(const_reference scale, const color& col) { return (col*scale); }
+
+ friend std::ostream& operator<<(std::ostream& s, const color& col)
+ {
+ s << "(" << col.r << "," << col.g << "," << col.b << ")";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const color& col);
+ void _swap(color& col);
+};
+
+#endif /* _COLOR_H_ */
diff --git a/hw3/include/compoundShader.h b/hw3/include/compoundShader.h
new file mode 100644
index 0000000..293e7d6
--- /dev/null
+++ b/hw3/include/compoundShader.h
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _COMPOUND_SHADER_H_
+#define _COMPOUND_SHADER_H_
+
+#include <vector>
+#include <memory>
+
+#include "shader_base.h"
+
+class compoundShader : public shader_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ compoundShader(const std::vector<std::shared_ptr<const shader_base>>& shader_list);
+ compoundShader(const compoundShader&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ compoundShader& operator=(const compoundShader&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const override;
+
+ virtual shaderProperties properties(const intersectionPoint& ip) const override;
+
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const override;
+
+ private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::vector<std::shared_ptr<const shader_base>> _compound;
+};
+
+#endif /* _COMPOUND_SHADER_H_ */
diff --git a/hw3/include/constants.h b/hw3/include/constants.h
new file mode 100644
index 0000000..daa1c45
--- /dev/null
+++ b/hw3/include/constants.h
@@ -0,0 +1,16 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+static const float EPSILON = 10e-6;
+static const float LARGE = 10e10;
+static const float PI = 3.14159265359;
+
+#endif /* _CONSTANTS_H_ */
diff --git a/hw3/include/coordinateTransform.h b/hw3/include/coordinateTransform.h
new file mode 100644
index 0000000..008cba7
--- /dev/null
+++ b/hw3/include/coordinateTransform.h
@@ -0,0 +1,31 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _COORDINATETRANSFORMATION3D_H_
+#define _COORDINATETRANSFORMATION3D_H_
+
+#include "transformation3d.h"
+
+///////////////////////////////////////////////
+// Transformation between coordinate systems //
+// forward transform: from local to global //
+// inverse transform: from global to local //
+///////////////////////////////////////////////
+class coordinateTransformation : public transformation3d {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ coordinateTransformation(void);
+ coordinateTransformation(const vec3d& normal);
+ coordinateTransformation(const vec3d& normal, const vec3d& other);
+ coordinateTransformation(const vec3d& X, const vec3d& Y, const vec3d& Z);
+};
+
+#endif /* _COORDINATETRANSFORMATION3D_H_ */
+
diff --git a/hw3/include/diffuseBrdf.h b/hw3/include/diffuseBrdf.h
new file mode 100644
index 0000000..e4ab19f
--- /dev/null
+++ b/hw3/include/diffuseBrdf.h
@@ -0,0 +1,59 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _DIFFUSEBRDF_H_
+#define _DIFFUSEBRDF_H_
+
+#include "brdf_base.h"
+
+class diffuseBrdf : public brdf_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ diffuseBrdf(const color& albedo);
+ diffuseBrdf(const diffuseBrdf& src);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ diffuseBrdf& operator=(const diffuseBrdf& src);
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const vec3d& in, const vec3d& out) const final override;
+
+ virtual bool isSpecular(void) const final override;
+ virtual bool isDiffuse(void) const final override;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(diffuseBrdf& a, diffuseBrdf& b) { a._swap(b); }
+ friend std::ostream& operator<<(std::ostream& s, const diffuseBrdf& b)
+ {
+ b._print(s);
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const diffuseBrdf& src);
+ void _swap(diffuseBrdf& src);
+ virtual void _print(std::ostream& s) const override;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ color _albedo;
+};
+
+#endif /* _DIFFUSEBRDF_H_ */
diff --git a/hw3/include/diffuseReflectanceShader.h b/hw3/include/diffuseReflectanceShader.h
new file mode 100644
index 0000000..bee9d8d
--- /dev/null
+++ b/hw3/include/diffuseReflectanceShader.h
@@ -0,0 +1,45 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _DIFFUSEREFLECTANCESHADER_H_
+#define _DIFFUSEREFLECTANCESHADER_H_
+
+#include "diffuseBrdf.h"
+#include "reflectanceParameter.h"
+#include "reflectanceShader_base.h"
+
+class diffuseReflectanceShader : public reflectanceShader_base {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ diffuseReflectanceShader(const colorReflectanceParameter& albedo=colorReflectanceParameter(color(1.0f, 1.0f, 1.0f)));
+ diffuseReflectanceShader(const diffuseReflectanceShader& ) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ diffuseReflectanceShader& operator=(const diffuseReflectanceShader&) = delete;
+
+protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual std::unique_ptr<const brdf_base> make_brdf(const vec2d& textureCoord) const override;
+
+ virtual void _print(std::ostream& s) const override;
+
+private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ colorReflectanceParameter _albedo;
+};
+
+#endif /* _DIFFUSEREFLECTANCESHADER_H_ */
+
diff --git a/hw3/include/directionalLightsource.h b/hw3/include/directionalLightsource.h
new file mode 100644
index 0000000..b33dfaf
--- /dev/null
+++ b/hw3/include/directionalLightsource.h
@@ -0,0 +1,55 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _DIRECTIONALLIGHTSOURCE_H_
+#define _DIRECTIONALLIGHTSOURCE_H_
+
+#include "lightsource_base.h"
+
+class directionalLightsource : public lightsource_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ directionalLightsource(const vec3d& direction=vec3d(0.0f, 0.0f, 1.0f), const color& power=color(1.0f, 1.0f, 1.0f));
+ directionalLightsource(const directionalLightsource&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ directionalLightsource& operator=(const directionalLightsource&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual lightSample intensityAt(const vec3d& point) const override;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend std::ostream& operator<<(std::ostream& s, const directionalLightsource& d)
+ {
+ d._print(s);
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ virtual void _print(std::ostream& s) const override;
+
+ private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ vec3d _direction;
+ color _power;
+};
+
+#endif /* _DIRECTIONALLIGHTSOURCE_H_ */
diff --git a/hw3/include/errorMessage.h b/hw3/include/errorMessage.h
new file mode 100644
index 0000000..7ec99d1
--- /dev/null
+++ b/hw3/include/errorMessage.h
@@ -0,0 +1,17 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _ERROR_MESSAGE_H_
+#define _ERROR_MESSAGE_H_
+
+#include <cstdarg>
+
+void errorMessage(const char* msg, ...);
+void warningMessage(const char* msg, ...);
+
+#endif /* _ERROR_MESSAGE_H_ */
diff --git a/hw3/include/image.h b/hw3/include/image.h
new file mode 100644
index 0000000..938e6c0
--- /dev/null
+++ b/hw3/include/image.h
@@ -0,0 +1,89 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+#include <string>
+#include <memory>
+#include <ostream>
+
+#include "color.h"
+
+class image {
+ public:
+ //////////////
+ // Typedefs //
+ //////////////
+ typedef color value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef std::unique_ptr<value_type[]>::pointer iterator;
+ typedef std::unique_ptr<const value_type[]>::pointer const_iterator;
+ typedef size_t difference_type;
+ typedef size_t size_type;
+
+ //////////////////
+ // Constructors //
+ //////////////////
+ image(size_type width=0, size_type height=0);
+ image(size_type width, size_type height, const_reference col);
+ image(const image& src);
+ image(image&& src);
+
+ virtual ~image(void) { _data.reset(); }
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ iterator begin(void);
+ const_iterator begin(void) const;
+
+ iterator end(void);
+ const_iterator end(void) const;
+
+ size_type size(void) const { return width()*height(); }
+ size_type width(void) const { return _width; }
+ size_type height(void) const { return _height; }
+
+
+ ///////////////
+ // Operators //
+ ///////////////
+ image& operator=(const image& src);
+ image& operator=(image&& src);
+
+ reference operator()(size_type x, size_type y);
+ const_reference operator()(size_type x, size_type y) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(image& a, image& b) { a._swap(b); }
+ friend std::ostream& operator<<(std::ostream& s, const image& img)
+ {
+ s << "Image: (" << img.width() << ", " << img.height() << ")";
+ return s;
+ }
+
+protected:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _swap(image& img);
+ void _assign(const image& src);
+
+private:
+ //////////////////////////
+ // Private Data Members //
+ //////////////////////////
+ size_type _width, _height;
+ std::unique_ptr<value_type[]> _data;
+};
+
+#endif /* _IMAGE_H_ */
diff --git a/hw3/include/imageIO.h b/hw3/include/imageIO.h
new file mode 100644
index 0000000..9e1ecfa
--- /dev/null
+++ b/hw3/include/imageIO.h
@@ -0,0 +1,19 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _IMAGEIO_H_
+#define _IMAGEIO_H_
+
+#include <string>
+#include "image.h"
+
+void importImage(const std::string& name, image& img);
+void exportImage(const std::string& name, const image& img);
+
+#endif /* _IMAGEIO_H_ */
+
diff --git a/hw3/include/imageIO.pfm.h b/hw3/include/imageIO.pfm.h
new file mode 100644
index 0000000..d09531a
--- /dev/null
+++ b/hw3/include/imageIO.pfm.h
@@ -0,0 +1,18 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _IMAGEIO_PFM_H_
+#define _IMAGEIO_PFM_H_
+
+#include <string>
+#include "image.h"
+
+void importPFM(const std::string& name, image& img);
+void exportPFM(const std::string& name, const image& img);
+
+#endif /* _IMAGEIO_PFM_H_ */
diff --git a/hw3/include/imageIO.ppm.h b/hw3/include/imageIO.ppm.h
new file mode 100644
index 0000000..7a8db42
--- /dev/null
+++ b/hw3/include/imageIO.ppm.h
@@ -0,0 +1,18 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _IMAGEIO_PPM_H_
+#define _IMAGEIO_PPM_H_
+
+#include <string>
+#include "image.h"
+
+void importPPM(const std::string& name, image& img);
+void exportPPM(const std::string& name, const image& img);
+
+#endif /* _IMAGEIO_PPM_H_ */
diff --git a/hw3/include/importOBJ.h b/hw3/include/importOBJ.h
new file mode 100644
index 0000000..056a420
--- /dev/null
+++ b/hw3/include/importOBJ.h
@@ -0,0 +1,18 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _IMPORTOBJ_H_
+#define _IMPORTOBJ_H_
+
+#include <string>
+#include <vector>
+#include "triangle.h"
+
+void importOBJ(const std::string filename, std::vector<triangle>& triangle_list);
+
+#endif /* _IMPORTOBJ_H_ */
diff --git a/hw3/include/intersectionPoint.h b/hw3/include/intersectionPoint.h
new file mode 100644
index 0000000..a4d8888
--- /dev/null
+++ b/hw3/include/intersectionPoint.h
@@ -0,0 +1,110 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _INTERSECTIONPOINT_H_
+#define _INTERSECTIONPOINT_H_
+
+#include <memory>
+#include <ostream>
+
+#include "ray.h"
+#include "vec3d.h"
+#include "vec2d.h"
+#include "color.h"
+#include "constants.h"
+#include "lightSample.h"
+#include "transformation3d.h"
+#include "shaderProperties.h"
+#include "coordinateTransform.h"
+
+
+class intersectionPoint
+{
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ intersectionPoint(void);
+ intersectionPoint(const ray& r, float rayParameter=+LARGE, const std::shared_ptr<const class shader_base>& shader=nullptr, const vec3d& normal=vec3d(0.0f, 0.0f, 1.0f), const vec3d& U=vec3d(1.0f, 0.0f, 0.0f), const vec2d& textureCoordinate=vec2d(0.0f, 0.0f));
+ intersectionPoint(const intersectionPoint& ip);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ intersectionPoint& operator=(const intersectionPoint& ip);
+
+ bool operator<(const intersectionPoint& ip) const;
+ bool operator>(const intersectionPoint& ip) const;
+ bool operator<(const lightSample& ls) const;
+ bool operator>(const lightSample& ls) const;
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ bool isHit(void) const;
+ bool hasShader(void) const;
+ shaderProperties getShaderProperties(void) const;
+ float distance(const intersectionPoint& ip) const;
+ const vec3d& position(void) const;
+ const vec3d& direction(void) const;
+ const vec2d& textureCoordinate(void) const;
+ const vec3d& normal(void) const;
+ coordinateTransformation shadingFrame(void) const;
+
+ //////////////
+ // Mutators //
+ //////////////
+ void transform(const transformation3d& t);
+ void inverseTransform(const transformation3d& t);
+
+ void transformShadingFrame(const transformation3d& sft);
+ void inverseTransformShadingFrame(const transformation3d& sft);
+
+ void setShader(const std::shared_ptr<const class shader_base>& shader);
+
+ /////////////
+ // Methods //
+ /////////////
+ color shade(const vec3d& out) const;
+ color shade(const lightSample& ls) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(intersectionPoint& a, intersectionPoint& b) { a._swap(b); }
+
+ friend bool operator<(const lightSample& ls, const intersectionPoint& ip) { return (ip > ls); }
+ friend bool operator>(const lightSample& ls, const intersectionPoint& ip) { return (ip < ls); }
+
+ friend std::ostream& operator<<(std::ostream& s, const intersectionPoint& ip)
+ {
+ if(ip._hit) s << "IntersectionPoint: ray=" << ip._ray << ", position=" << ip._position << " (parameter=" << ip._rayParameter << ", normal=" << ip._normal << ", shading axis=" << ip._U << ", texture coordinate=" << ip._textureCoordinate;
+ else s << "IntersectionPoint: empty";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const intersectionPoint& ip);
+ void _swap(intersectionPoint& ip);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ ray _ray;
+ bool _hit;
+ float _rayParameter;
+ vec3d _position;
+ vec3d _normal, _U;
+ vec2d _textureCoordinate;
+ std::shared_ptr<const class shader_base> _shader;
+};
+
+#endif /* _INTERSECTIONPOINT_H_ */
diff --git a/hw3/include/intersector_base.h b/hw3/include/intersector_base.h
new file mode 100644
index 0000000..64fb05e
--- /dev/null
+++ b/hw3/include/intersector_base.h
@@ -0,0 +1,34 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _INTERSECTOR_BASE_H_
+#define _INTERSECTOR_BASE_H_
+
+#include "ray.h"
+#include "intersectionPoint.h"
+
+class intersector_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ intersector_base(void) {}
+ intersector_base(const intersector_base&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ intersector_base& operator=(const intersector_base&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual intersectionPoint intersect(const ray& r) const = 0;
+};
+
+#endif /* _INTERSECTOR_BASE_H_ */
diff --git a/hw3/include/intersector_factory_base.h b/hw3/include/intersector_factory_base.h
new file mode 100644
index 0000000..c6e9e98
--- /dev/null
+++ b/hw3/include/intersector_factory_base.h
@@ -0,0 +1,29 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _INTERSECTOR_FACTORY_BASE_H_
+#define _INTERSECTOR_FACTORY_BASE_H_
+
+#include <memory>
+#include "boundedCompound.h"
+#include "intersector_base.h"
+
+class intersector_factory_base {
+public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ intersector_factory_base(void) {}
+
+ //////////////
+ // Operator //
+ //////////////
+ virtual std::unique_ptr<const intersector_base> operator()(const boundedCompound& bc) const = 0;
+};
+
+#endif /* _INTERSECTOR_FACTORY_BASE_H_ */
diff --git a/hw3/include/interval.h b/hw3/include/interval.h
new file mode 100644
index 0000000..ccb720a
--- /dev/null
+++ b/hw3/include/interval.h
@@ -0,0 +1,77 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _INTERVAL_H_
+#define _INTERVAL_H_
+
+#include <ostream>
+
+#include "constants.h"
+
+class interval
+{
+ public:
+ //////////////////
+ // Constrructor //
+ //////////////////
+ interval(float lower=-LARGE, float upper=+LARGE);
+ interval(const interval& i);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ interval& operator=(const interval& i);
+
+ interval operator+(float v) const;
+ interval operator-(float v) const;
+ interval operator*(float v) const;
+ interval operator/(float v) const;
+
+ interval& operator+=(float v);
+ interval& operator-=(float v);
+ interval& operator*=(float v);
+ interval& operator/=(float v);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ float lower(void) const;
+ float upper(void) const;
+
+ bool empty(void) const;
+
+ //////////////
+ // Mutators //
+ //////////////
+ void intersect(const interval& i);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(interval& a, interval& b) { a._swap(b); }
+
+ friend std::ostream& operator<<(std::ostream& s, const interval& i)
+ {
+ s << "[" << i.lower() << ", " << i.upper() << "]";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const interval& i);
+ void _swap(interval& i);
+
+ //////////////////////////
+ // Private Data Members //
+ //////////////////////////
+ float _lower, _upper;
+};
+
+#endif /* _INTERVAL_H_ */
diff --git a/hw3/include/lightSample.h b/hw3/include/lightSample.h
new file mode 100644
index 0000000..3dd76b5
--- /dev/null
+++ b/hw3/include/lightSample.h
@@ -0,0 +1,75 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _LIGHTSAMPLE_H_
+#define _LIGHTSAMPLE_H_
+
+#include "vec3d.h"
+#include "color.h"
+#include "constants.h"
+
+class lightSample {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ lightSample(const vec3d& direction=vec3d(0.0f, 0.0f, 0.0f),
+ const color& emittance=color(0.0f, 0.0f, 0.0f),
+ float distance=+LARGE,
+ float pdf=1.0f,
+ float foreshortening=1.0f);
+
+ lightSample(const lightSample& ls);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ lightSample& operator=(const lightSample& ls);
+
+ const color& operator()(void) const;
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ const vec3d& directionToPoint(void) const;
+ vec3d directionToLight(void) const;
+
+ const color& emittance(void) const;
+ float distance(void) const;
+
+ float pdf(void) const;
+ float foreshortening(void) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(lightSample& a, lightSample& b) { a._swap(b); }
+ friend std::ostream& operator<<(std::ostream& s, const lightSample& ls)
+ {
+ s << "LightSample: direction=" << ls.directionToPoint() << ", emittance=" << ls() << ", distance=" << ls.distance() << ", pdf=" << ls.pdf() << ", foreshortening=" << ls.foreshortening();
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const lightSample& ls);
+ void _swap(lightSample& ls);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ vec3d _direction;
+ color _emittance;
+ float _distance;
+ float _pdf;
+ float _foreshortening;
+};
+
+#endif /* _LIGHTSAMPLE_H_ */
diff --git a/hw3/include/lightsource_base.h b/hw3/include/lightsource_base.h
new file mode 100644
index 0000000..0a2f0df
--- /dev/null
+++ b/hw3/include/lightsource_base.h
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _LIGHTSOURCE_BASE_H_
+#define _LIGHTSOURCE_BASE_H_
+
+#include <ostream>
+
+#include "vec3d.h"
+#include "lightSample.h"
+
+class lightsource_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ lightsource_base(void) {}
+ lightsource_base(const lightsource_base&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ lightsource_base& operator=(const lightsource_base&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual lightSample intensityAt(const vec3d& point) const = 0;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend std::ostream& operator<<(std::ostream& s, const lightsource_base& lsb)
+ {
+ lsb._print(s);
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ virtual void _print(std::ostream& s) const = 0;
+};
+
+#endif /* _LIGHTSOURCE_BASE_H_ */
diff --git a/hw3/include/linear_intersector.h b/hw3/include/linear_intersector.h
new file mode 100644
index 0000000..221e5fe
--- /dev/null
+++ b/hw3/include/linear_intersector.h
@@ -0,0 +1,62 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _LINEAR_INTERSECTOR_H_
+#define _LINEAR_INTERSECTOR_H_
+
+#include <memory>
+
+#include "boundedPrimitive.h"
+#include "intersector_base.h"
+#include "intersector_factory_base.h"
+
+class linear_intersector : public intersector_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ linear_intersector(void);
+ linear_intersector(const std::vector<std::shared_ptr<const boundedPrimitive>>& compounds);
+ linear_intersector(const linear_intersector&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ linear_intersector& operator=(const linear_intersector&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual intersectionPoint intersect(const ray& r) const final override;
+
+ private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::vector<std::shared_ptr<const boundedPrimitive>> _compounds;
+};
+
+
+class linear_intersector_factory : public intersector_factory_base {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ linear_intersector_factory(void) {}
+
+ ///////////////
+ // Operators //
+ ///////////////
+ std::unique_ptr<const intersector_base> operator()(const boundedCompound& boundedCompound) const final override
+ {
+ return std::unique_ptr<const intersector_base>(new linear_intersector(boundedCompound.compounds()));
+ }
+};
+
+#endif /* _LINEAR_INTERSECTOR_H_ */
+
diff --git a/hw3/include/mat3d.h b/hw3/include/mat3d.h
new file mode 100644
index 0000000..e70ece4
--- /dev/null
+++ b/hw3/include/mat3d.h
@@ -0,0 +1,112 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _MAT3D_H_
+#define _MAT3D_H_
+
+#include <array>
+#include <ostream>
+
+#include "vec3d.h"
+
+class mat3d {
+ public:
+ /////////////
+ // Typedef //
+ /////////////
+ typedef float value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef std::array<value_type,9>::iterator iterator;
+ typedef std::array<value_type,9>::const_iterator const_iterator;
+ typedef std::size_t difference;
+ typedef std::size_t size_type;
+
+ /////////////////
+ // Constructor //
+ /////////////////
+ mat3d(void); // all elements are set to 0
+ explicit mat3d(value_type diag); // all elements are set to 0, the diagonal elements are set to 'diag'
+ mat3d(const vec3d& X, const vec3d& Y, const vec3d& Z); // set columns to X, Y, and Z
+ mat3d(const mat3d& m); // copy constructor
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ static size_type width(void) { return 3; }
+ static size_type height(void) { return 3; }
+ static size_type size(void) { return 9; }
+
+ iterator begin(void);
+ const_iterator begin(void) const;
+ iterator end(void);
+ const_iterator end(void) const;
+
+ //////////////
+ // Mutators //
+ //////////////
+ void clear(value_type value=0.0f);
+ void setDiagonal(value_type value=1.0f);
+
+ mat3d& transpose(void);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ mat3d& operator=(const mat3d& m);
+
+ reference operator()(size_type row, size_type col);
+ const_reference operator()(size_type row, size_type col) const;
+
+ mat3d operator+(const mat3d& m) const;
+ mat3d operator-(const mat3d& m) const;
+ mat3d operator*(const mat3d& m) const;
+ vec3d operator*(const vec3d& v) const;
+ mat3d operator*(value_type scale) const;
+ mat3d operator/(value_type scale) const;
+
+ mat3d& operator+=(const mat3d& m);
+ mat3d& operator-=(const mat3d& m);
+ mat3d& operator*=(const mat3d& m);
+ mat3d& operator*=(value_type scale);
+ mat3d& operator/=(value_type scale);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(mat3d& a, mat3d& b) { a._swap(b); }
+
+ friend vec3d operator*(const vec3d& v, const mat3d& m) { return m._premultiply(v); }
+ friend mat3d operator*(value_type scale, const mat3d& m) { return (m * scale); }
+
+ friend mat3d transpose(mat3d& m) { mat3d n(m); return n.transpose(); }
+
+ friend std::ostream& operator<<(std::ostream& s, const mat3d& m)
+ {
+ s << "[[" << m(0,0) << ", " << m(0,1) << ", " << m(0,2) << "],[";
+ s << m(1,0) << ", " << m(1,1) << ", " << m(1,2) << "],[";
+ s << m(2,0) << ", " << m(2,1) << ", " << m(2,2) << "]]";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _swap(mat3d& m);
+ void _assign(const mat3d& m);
+
+ vec3d _premultiply(const vec3d& v) const;
+
+ //////////////////////////
+ // Private Data Members //
+ //////////////////////////
+ std::array<value_type, 9> _data;
+};
+
+#endif /* _MAT3D_H_ */
diff --git a/hw3/include/phongBrdf.h b/hw3/include/phongBrdf.h
new file mode 100644
index 0000000..588efa2
--- /dev/null
+++ b/hw3/include/phongBrdf.h
@@ -0,0 +1,60 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _PHONGBRDF_H_
+#define _PHONGBRDF_H_
+
+#include "brdf_base.h"
+
+class phongBrdf : public brdf_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ phongBrdf(const color& albedo, float sharpness);
+ phongBrdf(const phongBrdf& src);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ phongBrdf& operator=(const phongBrdf& src);
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const vec3d& in, const vec3d& out) const override;
+
+ virtual bool isSpecular(void) const final override;
+ virtual bool isDiffuse(void) const final override;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(phongBrdf& a, phongBrdf& b) { a._swap(b); }
+ friend std::ostream& operator<<(std::ostream& s, const phongBrdf& b)
+ {
+ b._print(s);
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const phongBrdf& src);
+ void _swap(phongBrdf& src);
+ virtual void _print(std::ostream& s) const override;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ color _albedo;
+ float _sharpness;
+};
+
+#endif /* _PHONGBRDF_H_ */
diff --git a/hw3/include/phongReflectanceShader.h b/hw3/include/phongReflectanceShader.h
new file mode 100644
index 0000000..13291f2
--- /dev/null
+++ b/hw3/include/phongReflectanceShader.h
@@ -0,0 +1,46 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _PHONGREFLECTANCESHADER_H_
+#define _PHONGREFLECTANCESHADER_H_
+
+#include "phongBrdf.h"
+#include "reflectanceParameter.h"
+#include "reflectanceShader_base.h"
+
+class phongReflectanceShader : public reflectanceShader_base {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ phongReflectanceShader(const colorReflectanceParameter& albedo=colorReflectanceParameter(color(1.0f, 1.0f, 1.0f)), const scalarReflectanceParameter& sharpness=20.0f);
+ phongReflectanceShader(const phongReflectanceShader& ) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ phongReflectanceShader& operator=(const phongReflectanceShader&) = delete;
+
+protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const override;
+
+ virtual std::unique_ptr<const brdf_base> make_brdf(const vec2d& textureCoord) const override;
+
+private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ colorReflectanceParameter _albedo;
+ scalarReflectanceParameter _sharpness;
+};
+
+#endif /* _PHONGREFLECTANCESHADER_H_ */
+
diff --git a/hw3/include/random_number.h b/hw3/include/random_number.h
new file mode 100644
index 0000000..328de25
--- /dev/null
+++ b/hw3/include/random_number.h
@@ -0,0 +1,50 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _RANDOM_NUMBER_H_
+#define _RANDOM_NUMBER_H_
+
+#include <random>
+#include "vec3d.h"
+#include "constants.h"
+#include "coordinateTransform.h"
+
+static std::random_device rd;
+static std::mt19937 rnd;
+
+static unsigned int random_int(unsigned int up=std::numeric_limits<unsigned int>::max())
+{
+ std::uniform_int_distribution<unsigned int> dist(0, up);
+ return dist(rnd);
+}
+
+
+static float random_float(float up=1.0f)
+{
+ std::uniform_real_distribution<float> dist(0, up);
+ return dist(rnd);
+}
+
+
+static vec3d random_direction(const vec3d& normal, float r1=random_float(), float r2=random_float())
+{
+ // generate in standard coordinate system (i.e., Z=(0,0,1))
+ vec3d out(cos(2.0f*PI*r1) * sqrt(std::max(1.0f-r2*r2, 0.0f)),
+ sin(2.0f*PI*r1) * sqrt(std::max(1.0f-r2*r2, 0.0f)),
+ r2);
+
+ // transform to global coordinates
+ coordinateTransformation trans(normal);
+ out = trans.transformDirection(out);
+
+ // Done (PDF = 1/(2.0f*PI))
+ return out;
+}
+
+
+#endif /* _RANDOM_NUMBER_H_ */
diff --git a/hw3/include/ray.h b/hw3/include/ray.h
new file mode 100644
index 0000000..743375f
--- /dev/null
+++ b/hw3/include/ray.h
@@ -0,0 +1,69 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _RAY_H_
+#define _RAY_H_
+
+#include <ostream>
+#include "vec3d.h"
+#include "transformation3d.h"
+
+class ray {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ ray(const vec3d& origin = vec3d(), const vec3d& direction = vec3d());
+ ray(const ray& src);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ const vec3d& origin(void) const { return _origin; }
+ const vec3d& direction(void) const { return _direction; }
+
+ ///////////////
+ // Operators //
+ ///////////////
+ ray& operator=(const ray& r);
+ vec3d operator()(float t) const;
+ float operator()(const vec3d& point) const;
+
+ //////////////
+ // Mutators //
+ //////////////
+ ray& transform(const transformation3d& t);
+ ray& inverseTransform(const transformation3d& t);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(ray& a, ray& b) { a._swap(b); }
+ friend ray transform(const ray& r, const transformation3d& t) { return ray(r).transform(t); }
+ friend ray inverseTransform(const ray& r, const transformation3d& t) { return ray(r).inverseTransform(t); }
+ friend std::ostream& operator<<(std::ostream& s, const ray& r)
+ {
+ s << r.origin() << "->" << r.direction();
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _swap(ray& r);
+ void _assign(const ray& r);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ vec3d _origin;
+ vec3d _direction;
+};
+
+#endif /* _RAY_H_ */
diff --git a/hw3/include/reflectanceParameter.h b/hw3/include/reflectanceParameter.h
new file mode 100644
index 0000000..c924653
--- /dev/null
+++ b/hw3/include/reflectanceParameter.h
@@ -0,0 +1,106 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _REFLECTANCEPARAMETER_H_
+#define _REFLECTANCEPARAMETER_H_
+
+#include <memory>
+#include <ostream>
+
+#include "vec2d.h"
+#include "vec3d.h"
+#include "color.h"
+#include "texture_base.h"
+
+class scalarReflectanceParameter {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ scalarReflectanceParameter(float value=0.0f);
+ scalarReflectanceParameter(const std::shared_ptr<const texture_base>& texture, unsigned int channel=0);
+ scalarReflectanceParameter(const scalarReflectanceParameter& src);
+
+ //////////////
+ // Operator //
+ //////////////
+ scalarReflectanceParameter& operator=(const scalarReflectanceParameter& src);
+
+ float operator()(const vec2d& textureCoord) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(scalarReflectanceParameter& a, scalarReflectanceParameter& b) { a._swap(b); }
+
+ friend std::ostream& operator<<(std::ostream& s, const scalarReflectanceParameter& param)
+ {
+ if(param._texture) s << param._texture << "(channel=" << param._channel << ")";
+ else s << param._value;
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const scalarReflectanceParameter& src);
+ void _swap(scalarReflectanceParameter& swp);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ float _value;
+ unsigned int _channel;
+ std::shared_ptr<const texture_base> _texture;
+};
+
+
+class colorReflectanceParameter {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ colorReflectanceParameter(color value=color(0.0f));
+ colorReflectanceParameter(const std::shared_ptr<const texture_base>& texture);
+ colorReflectanceParameter(const colorReflectanceParameter& src);
+
+ //////////////
+ // Operator //
+ //////////////
+ colorReflectanceParameter& operator=(const colorReflectanceParameter& src);
+
+ color operator()(const vec2d& textureCoord) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(colorReflectanceParameter& a, colorReflectanceParameter& b) { a._swap(b); }
+
+ friend std::ostream& operator<<(std::ostream& s, const colorReflectanceParameter& param)
+ {
+ if(param._texture) s << param._texture;
+ else s << param._value;
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const colorReflectanceParameter& src);
+ void _swap(colorReflectanceParameter& swp);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ color _value;
+ std::shared_ptr<const texture_base> _texture;
+};
+
+#endif /* _REFLECTANCEPARAMETER_BASE_H_ */
diff --git a/hw3/include/reflectanceShader_base.h b/hw3/include/reflectanceShader_base.h
new file mode 100644
index 0000000..ad91137
--- /dev/null
+++ b/hw3/include/reflectanceShader_base.h
@@ -0,0 +1,45 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _REFLECTANCESHADER_BASE_H_
+#define _REFLECTANCESHADER_BASE_H_
+
+#include <memory>
+#include "brdf_base.h"
+#include "shader_base.h"
+
+class reflectanceShader_base : public shader_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ reflectanceShader_base(void) {}
+ reflectanceShader_base(const reflectanceShader_base&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ reflectanceShader_base& operator=(const reflectanceShader_base&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const final override;
+
+ virtual shaderProperties properties(const intersectionPoint& ip) const final override;
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const = 0;
+
+ virtual std::unique_ptr<const brdf_base> make_brdf(const vec2d& textureCoord) const = 0;
+};
+
+#endif /* _REFLECTANCE_SHADER_BASE_H_ */
diff --git a/hw3/include/scene.h b/hw3/include/scene.h
new file mode 100644
index 0000000..ee3e416
--- /dev/null
+++ b/hw3/include/scene.h
@@ -0,0 +1,59 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENE_H_
+#define _SCENE_H_
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include "ray.h"
+#include "image.h"
+#include "camera.h"
+#include "boundedCompound.h"
+#include "lightsource_base.h"
+#include "intersectionPoint.h"
+
+class scene {
+ friend void importScene(const std::string&, scene&);
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ scene(void) {}
+ scene(const scene&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ camera& operator=(const camera&) = delete;
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ const camera& getCamera(void) const;
+
+ const lightsource_base& getLightsource(size_t idx) const;
+ size_t numberOfLightsources(void) const;
+
+ /////////////
+ // Methods //
+ /////////////
+ intersectionPoint intersect(const ray& r) const;
+
+ private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ camera _camera;
+ std::unique_ptr<const boundedCompound> _sceneGraphRoot;
+ std::vector<std::shared_ptr<const lightsource_base>> _lightsources;
+};
+
+#endif /* _SCENE_H_ */
diff --git a/hw3/include/sceneGraphNode.h b/hw3/include/sceneGraphNode.h
new file mode 100644
index 0000000..38e7de1
--- /dev/null
+++ b/hw3/include/sceneGraphNode.h
@@ -0,0 +1,45 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEGRAPHNODE_H_
+#define _SCENEGRAPHNODE_H_
+
+#include <vector>
+#include <memory>
+
+#include "shader_base.h"
+#include "boundedCompound.h"
+#include "transformation3d.h"
+
+class sceneGraphNode : public boundedCompound {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ sceneGraphNode(void);
+ sceneGraphNode(const std::vector<std::shared_ptr<const boundedPrimitive>>& nodes, const transformation3d& transform=transformation3d(), const std::shared_ptr<const shader_base>& shader=nullptr);
+ sceneGraphNode(const sceneGraphNode&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ sceneGraphNode& operator=(sceneGraphNode&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual const std::vector<std::shared_ptr<const boundedPrimitive>>& compounds(void) const final override;
+
+ private:
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::vector<std::shared_ptr<const boundedPrimitive>> _nodes;
+};
+
+#endif /* _SCENEGRAPHNODE_H_ */
diff --git a/hw3/include/sceneIO.h b/hw3/include/sceneIO.h
new file mode 100644
index 0000000..59fc6cd
--- /dev/null
+++ b/hw3/include/sceneIO.h
@@ -0,0 +1,17 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENE_IO_H_
+#define _SCENE_IO_H_
+
+#include <string>
+#include "scene.h"
+
+void importScene(const std::string& filename, scene& s);
+
+#endif /* _SCENE_IO_H_ */
diff --git a/hw3/include/sceneIO_basis.h b/hw3/include/sceneIO_basis.h
new file mode 100644
index 0000000..5f67172
--- /dev/null
+++ b/hw3/include/sceneIO_basis.h
@@ -0,0 +1,22 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_BASIS_H_
+#define _SCENEIO_BASIS_H_
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#include "camera.h"
+#include "intersector_factory_base.h"
+
+bool importCamera(const XMLNode& node, camera& cam);
+void importIntersector(const XMLNode& node, std::unique_ptr<const intersector_factory_base>& intersector);
+
+#endif /* _SCENEIO_BASIS_H_ */
diff --git a/hw3/include/sceneIO_cache.h b/hw3/include/sceneIO_cache.h
new file mode 100644
index 0000000..3807c86
--- /dev/null
+++ b/hw3/include/sceneIO_cache.h
@@ -0,0 +1,52 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_CACHE_H_
+#define _SCENEIO_CACHE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+template<typename T>
+class nodeCache {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ nodeCache(void) {}
+ nodeCache(const nodeCache<T>&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ nodeCache& operator=(const nodeCache& ) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ std::shared_ptr<T> get(const std::string& name) const;
+ bool add(const std::string& name, const std::shared_ptr<T>& node);
+
+ std::vector<std::shared_ptr<T>> unusedNodes(unsigned int maxCount=1) const;
+ std::vector<std::shared_ptr<T>> allNodes(void) const;
+
+ private:
+ //////////////////////////
+ // Private Data Members //
+ //////////////////////////
+ std::map<std::string, std::shared_ptr<T>> _cache;
+};
+
+////////////////////
+// Inline Methods //
+////////////////////
+#include "sceneIO_cache.inline.h"
+
+#endif /* _SCENEIO_CACHE_H_ */
diff --git a/hw3/include/sceneIO_cache.inline.h b/hw3/include/sceneIO_cache.inline.h
new file mode 100644
index 0000000..27d9cf0
--- /dev/null
+++ b/hw3/include/sceneIO_cache.inline.h
@@ -0,0 +1,66 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#if defined(_SCENEIO_CACHE_H_) && !defined(_SCENEIO_CACHE_INLINE_H_)
+#define _SCENEIO_CACHE_INLINE_H_
+
+#include <string>
+#include <memory>
+#include <vector>
+
+#include "errorMessage.h"
+
+template<typename T>
+std::shared_ptr<T> nodeCache<T>::get(const std::string& name) const
+{
+ // see if node exists
+ auto ref_node = _cache.find(name);
+
+ // return nullptr if not.
+ if(ref_node == _cache.end()) return nullptr;
+
+ // return node.
+ else return ref_node->second;
+}
+
+
+template<typename T>
+bool nodeCache<T>::add(const std::string& name, const std::shared_ptr<T>& node)
+{
+ _cache[name] = node;
+}
+
+template<typename T>
+std::vector<std::shared_ptr<T>> nodeCache<T>::unusedNodes(unsigned int maxCount) const
+{
+ std::vector<std::shared_ptr<T>> result;
+
+ // check each node if unique
+ for(auto itr=_cache.begin(); itr != _cache.end(); itr++)
+ if(itr->second.use_count() <= maxCount)
+ result.push_back(itr->second);
+
+ // done.
+ return result;
+}
+
+
+template<typename T>
+std::vector<std::shared_ptr<T>> nodeCache<T>::allNodes(void) const
+{
+ std::vector<std::shared_ptr<T>> result;
+
+ // check each node if unique
+ for(auto itr=_cache.begin(); itr != _cache.end(); itr++)
+ result.push_back(itr->second);
+
+ // done.
+ return result;
+}
+
+#endif /* _SCENEIO_CACHE_INLINE_H_ */
diff --git a/hw3/include/sceneIO_core.h b/hw3/include/sceneIO_core.h
new file mode 100644
index 0000000..8aa726a
--- /dev/null
+++ b/hw3/include/sceneIO_core.h
@@ -0,0 +1,24 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_CORE_H_
+#define _SCENEIO_CORE_H_
+
+#include "sceneIO_xml.h"
+#include "color.h"
+#include "vec2d.h"
+#include "vec3d.h"
+
+color getColor(const XMLNode& node, const std::string& name, const color& default_value=color());
+vec3d getVec3d(const XMLNode& node, const std::string& name, const vec3d& default_value=vec3d());
+vec2d getVec2d(const XMLNode& node, const std::string& name, const vec2d& default_value=vec2d());
+std::string getString(const XMLNode& node, const std::string& name, const std::string& default_value=std::string(""));
+float getFloat(const XMLNode& node, const std::string& name, float default_value=0.0f);
+unsigned int getInteger(const XMLNode& node, const std::string& name, unsigned int default_value=0);
+
+#endif /* _SCENEIO_CORE_H_ */
diff --git a/hw3/include/sceneIO_geometry.h b/hw3/include/sceneIO_geometry.h
new file mode 100644
index 0000000..fc4d80b
--- /dev/null
+++ b/hw3/include/sceneIO_geometry.h
@@ -0,0 +1,23 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_GEOMETRY_H_
+#define _SCENEIO_GEOMETRY_H_
+
+#include <memory>
+
+#include "sceneIO_xml.h"
+#include "sceneIO_cache.h"
+
+#include "shader_base.h"
+#include "texture_base.h"
+#include "boundedPrimitive.h"
+
+std::shared_ptr<boundedPrimitive> importGeometry(const XMLNode& node, nodeCache<boundedPrimitive>& shape_cache, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir);
+
+#endif /* _SCENEIO_GEOMETRY_H_ */
diff --git a/hw3/include/sceneIO_light.h b/hw3/include/sceneIO_light.h
new file mode 100644
index 0000000..e2745a2
--- /dev/null
+++ b/hw3/include/sceneIO_light.h
@@ -0,0 +1,25 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_LIGHT_H_
+#define _SCENEIO_LIGHT_H_
+
+#include <memory>
+
+#include "sceneIO_xml.h"
+#include "sceneIO_cache.h"
+
+#include "shader_base.h"
+#include "texture_base.h"
+#include "boundedPrimitive.h"
+
+#include "lightsource_base.h"
+
+std::shared_ptr<const lightsource_base> importLight(const XMLNode& node, nodeCache<boundedPrimitive>& shape_cache, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir);
+
+#endif /* _SCENEIO_LIGHT_H_ */
diff --git a/hw3/include/sceneIO_material.h b/hw3/include/sceneIO_material.h
new file mode 100644
index 0000000..9c0852b
--- /dev/null
+++ b/hw3/include/sceneIO_material.h
@@ -0,0 +1,22 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_MATERIAL_H_
+#define _SCENEIO_MATERIAL_H_
+
+#include <memory>
+
+#include "sceneIO_xml.h"
+#include "sceneIO_cache.h"
+
+#include "shader_base.h"
+#include "texture_base.h"
+
+std::shared_ptr<shader_base> importMaterial(const XMLNode& node, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir);
+
+#endif /* _SCENEIO_MATERIAL_H_ */
diff --git a/hw3/include/sceneIO_xml.h b/hw3/include/sceneIO_xml.h
new file mode 100644
index 0000000..5df35a2
--- /dev/null
+++ b/hw3/include/sceneIO_xml.h
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SCENEIO_XML_H_
+#define _SCENEIO_XML_H_
+
+#include <memory>
+#include <string>
+#include "tinyxml2.h"
+
+class XMLNode {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ XMLNode(const std::string& filename);
+ XMLNode(const tinyxml2::XMLElement* element, const std::shared_ptr<tinyxml2::XMLDocument>& xml);
+ XMLNode(const XMLNode& node);
+
+ /////////////
+ // Methods //
+ /////////////
+ XMLNode firstChild(void) const;
+ XMLNode findChild(const std::string& name) const;
+
+ bool isValid(void) const;
+ std::string name(void) const;
+ std::string attribute(const std::string& attribute) const;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ XMLNode& operator++(void);
+ XMLNode& operator++(int);
+ XMLNode& operator=(const XMLNode& src);
+
+ protected:
+ //////////////////
+ // Data Members //
+ //////////////////
+ const tinyxml2::XMLElement* _element;
+ std::shared_ptr<tinyxml2::XMLDocument> _xml;
+};
+
+
+#endif /* _SCENEIO_XML_H_ */
diff --git a/hw3/include/shaderProperties.h b/hw3/include/shaderProperties.h
new file mode 100644
index 0000000..859aaac
--- /dev/null
+++ b/hw3/include/shaderProperties.h
@@ -0,0 +1,38 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SHADERPROPERTIES_H_
+#define _SHADERPROPERTIES_H_
+
+class shaderProperties {
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ shaderProperties(bool diff=true, bool spec=true) : diffuse(diff), specular(spec) {}
+
+ //////////////
+ // Operator //
+ //////////////
+ bool operator==(const shaderProperties& sp) const;
+ bool operator!=(const shaderProperties& sp) const;
+
+ shaderProperties& operator&=(const shaderProperties& sp);
+ shaderProperties& operator|=(const shaderProperties& sp);
+ shaderProperties& operator~(void);
+
+ shaderProperties operator&(const shaderProperties& sp) const;
+ shaderProperties operator|(const shaderProperties& sp) const;
+
+ /////////////////////////
+ // Public data members //
+ /////////////////////////
+ bool diffuse, specular;
+};
+
+#endif /* _SHADERPROPERTIES_H_ */
diff --git a/hw3/include/shader_base.h b/hw3/include/shader_base.h
new file mode 100644
index 0000000..b96cc33
--- /dev/null
+++ b/hw3/include/shader_base.h
@@ -0,0 +1,59 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SHADER_BASE_H_
+#define _SHADER_BASE_H_
+
+#include <memory>
+#include <ostream>
+
+#include "vec2d.h"
+#include "vec3d.h"
+#include "color.h"
+#include "shaderProperties.h"
+#include "intersectionPoint.h"
+
+
+class shader_base
+{
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ shader_base(void) {}
+ shader_base(const shader_base&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ shader_base& operator=(const shader_base&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const = 0;
+
+ virtual shaderProperties properties(const intersectionPoint& ip) const = 0;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend std::ostream& operator<<(std::ostream& s, const shader_base& shader)
+ {
+ shader._print(s);
+ return s;
+ }
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _print(std::ostream& s) const = 0;
+};
+
+#endif /* _SHADER_BASE_H_ */
diff --git a/hw3/include/shadingFrameTransformation.h b/hw3/include/shadingFrameTransformation.h
new file mode 100644
index 0000000..2d8bd34
--- /dev/null
+++ b/hw3/include/shadingFrameTransformation.h
@@ -0,0 +1,57 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _SHADINGFRAMETRANSFORMATION_H_
+#define _SHADINGFRAMETRANSFORMATION_H_
+
+#include <memory>
+
+#include "vec2d.h"
+#include "shader_base.h"
+#include "transformation3d.h"
+
+class shadingFrameTransformation : public shader_base {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ shadingFrameTransformation(const std::shared_ptr<const shader_base>& shader);
+ shadingFrameTransformation(const shadingFrameTransformation&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ shadingFrameTransformation& operator=(const shadingFrameTransformation&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual color shade(const intersectionPoint& ip, const vec3d& light_dir) const final override;
+
+ virtual color reflectance(const intersectionPoint& ip, const vec3d& light_dir, const shaderProperties& properties=shaderProperties()) const final override;
+ virtual brdfSample sample(const intersectionPoint& ip, float r1, float r2, const shaderProperties& properties=shaderProperties()) const final override;
+ virtual float reflectivity(const intersectionPoint& ip, const shaderProperties& properties=shaderProperties()) const final override;
+ virtual color emittance(const intersectionPoint& ip) const final override;
+
+ virtual shaderProperties properties(const intersectionPoint& ip) const final override;
+
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual transformation3d _transformation(const vec2d& textureCoord) const = 0;
+ virtual void _print(std::ostream& s) const = 0;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::shared_ptr<const shader_base> _shader;
+};
+
+#endif /* _SHADINGFRAMETRANSFORMATION_H_ */
diff --git a/hw3/include/texture_base.h b/hw3/include/texture_base.h
new file mode 100644
index 0000000..919ab53
--- /dev/null
+++ b/hw3/include/texture_base.h
@@ -0,0 +1,67 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _TEXTURE_BASE_H_
+#define _TEXTURE_BASE_H_
+
+#include "vec2d.h"
+#include "image.h"
+
+class texture_base : public image {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ texture_base(bool repeat=true);
+ texture_base(const texture_base& src);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ texture_base& operator=(const texture_base& src);
+
+ virtual image::value_type operator()(const vec2d& textureCoord) const = 0;
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ bool repeatEdge(void) const { return _repeat; }
+ bool wrapEdge(void) const { return !_repeat; }
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(texture_base& a, texture_base& b) { a._swap(b); }
+
+ friend std::ostream& operator<<(std::ostream& s, const texture_base& t)
+ {
+ t._print(s);
+ return s;
+ }
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ virtual void _assign(const texture_base& src);
+ color& _at(signed int x, signed int y);
+ const color& _at(signed int x, signed int y) const;
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ virtual void _print(std::ostream& s) const=0;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ bool _repeat;
+};
+
+#endif /* _TEXTURE_BASE_H_ */
diff --git a/hw3/include/tinyxml2.h b/hw3/include/tinyxml2.h
new file mode 100644
index 0000000..fb7464a
--- /dev/null
+++ b/hw3/include/tinyxml2.h
@@ -0,0 +1,2102 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#ifndef TINYXML2_INCLUDED
+#define TINYXML2_INCLUDED
+
+#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
+# include <ctype.h>
+# include <limits.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# include <cctype>
+# include <climits>
+# include <cstdio>
+# include <cstdlib>
+# include <cstring>
+#endif
+
+/*
+ TODO: intern strings instead of allocation.
+*/
+/*
+ gcc:
+ g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
+
+ Formatting, Artistic Style:
+ AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
+*/
+
+#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
+# ifndef DEBUG
+# define DEBUG
+# endif
+#endif
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4251)
+#endif
+
+#ifdef _WIN32
+# ifdef TINYXML2_EXPORT
+# define TINYXML2_LIB __declspec(dllexport)
+# elif defined(TINYXML2_IMPORT)
+# define TINYXML2_LIB __declspec(dllimport)
+# else
+# define TINYXML2_LIB
+# endif
+#else
+# define TINYXML2_LIB
+#endif
+
+
+#if defined(DEBUG)
+# if defined(_MSC_VER)
+# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
+# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
+# elif defined (ANDROID_NDK)
+# include <android/log.h>
+# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
+# else
+# include <assert.h>
+# define TIXMLASSERT assert
+# endif
+#else
+# define TIXMLASSERT( x ) {}
+#endif
+
+
+/* Versioning, past 1.0.14:
+ http://semver.org/
+*/
+static const int TIXML2_MAJOR_VERSION = 3;
+static const int TIXML2_MINOR_VERSION = 0;
+static const int TIXML2_PATCH_VERSION = 0;
+
+namespace tinyxml2
+{
+class XMLDocument;
+class XMLElement;
+class XMLAttribute;
+class XMLComment;
+class XMLText;
+class XMLDeclaration;
+class XMLUnknown;
+class XMLPrinter;
+
+/*
+ A class that wraps strings. Normally stores the start and end
+ pointers into the XML file itself, and will apply normalization
+ and entity translation if actually read. Can also store (and memory
+ manage) a traditional char[]
+*/
+class StrPair
+{
+public:
+ enum {
+ NEEDS_ENTITY_PROCESSING = 0x01,
+ NEEDS_NEWLINE_NORMALIZATION = 0x02,
+ NEEDS_WHITESPACE_COLLAPSING = 0x04,
+
+ TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+ TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
+ ATTRIBUTE_NAME = 0,
+ ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+ ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
+ COMMENT = NEEDS_NEWLINE_NORMALIZATION
+ };
+
+ StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
+ ~StrPair();
+
+ void Set( char* start, char* end, int flags ) {
+ Reset();
+ _start = start;
+ _end = end;
+ _flags = flags | NEEDS_FLUSH;
+ }
+
+ const char* GetStr();
+
+ bool Empty() const {
+ return _start == _end;
+ }
+
+ void SetInternedStr( const char* str ) {
+ Reset();
+ _start = const_cast<char*>(str);
+ }
+
+ void SetStr( const char* str, int flags=0 );
+
+ char* ParseText( char* in, const char* endTag, int strFlags );
+ char* ParseName( char* in );
+
+ void TransferTo( StrPair* other );
+
+private:
+ void Reset();
+ void CollapseWhitespace();
+
+ enum {
+ NEEDS_FLUSH = 0x100,
+ NEEDS_DELETE = 0x200
+ };
+
+ int _flags;
+ char* _start;
+ char* _end;
+
+ StrPair( const StrPair& other ); // not supported
+ void operator=( StrPair& other ); // not supported, use TransferTo()
+};
+
+
+/*
+ A dynamic array of Plain Old Data. Doesn't support constructors, etc.
+ Has a small initial memory pool, so that low or no usage will not
+ cause a call to new/delete
+*/
+template <class T, int INITIAL_SIZE>
+class DynArray
+{
+public:
+ DynArray() {
+ _mem = _pool;
+ _allocated = INITIAL_SIZE;
+ _size = 0;
+ }
+
+ ~DynArray() {
+ if ( _mem != _pool ) {
+ delete [] _mem;
+ }
+ }
+
+ void Clear() {
+ _size = 0;
+ }
+
+ void Push( T t ) {
+ TIXMLASSERT( _size < INT_MAX );
+ EnsureCapacity( _size+1 );
+ _mem[_size++] = t;
+ }
+
+ T* PushArr( int count ) {
+ TIXMLASSERT( count >= 0 );
+ TIXMLASSERT( _size <= INT_MAX - count );
+ EnsureCapacity( _size+count );
+ T* ret = &_mem[_size];
+ _size += count;
+ return ret;
+ }
+
+ T Pop() {
+ TIXMLASSERT( _size > 0 );
+ return _mem[--_size];
+ }
+
+ void PopArr( int count ) {
+ TIXMLASSERT( _size >= count );
+ _size -= count;
+ }
+
+ bool Empty() const {
+ return _size == 0;
+ }
+
+ T& operator[](int i) {
+ TIXMLASSERT( i>= 0 && i < _size );
+ return _mem[i];
+ }
+
+ const T& operator[](int i) const {
+ TIXMLASSERT( i>= 0 && i < _size );
+ return _mem[i];
+ }
+
+ const T& PeekTop() const {
+ TIXMLASSERT( _size > 0 );
+ return _mem[ _size - 1];
+ }
+
+ int Size() const {
+ TIXMLASSERT( _size >= 0 );
+ return _size;
+ }
+
+ int Capacity() const {
+ TIXMLASSERT( _allocated >= INITIAL_SIZE );
+ return _allocated;
+ }
+
+ const T* Mem() const {
+ TIXMLASSERT( _mem );
+ return _mem;
+ }
+
+ T* Mem() {
+ TIXMLASSERT( _mem );
+ return _mem;
+ }
+
+private:
+ DynArray( const DynArray& ); // not supported
+ void operator=( const DynArray& ); // not supported
+
+ void EnsureCapacity( int cap ) {
+ TIXMLASSERT( cap > 0 );
+ if ( cap > _allocated ) {
+ TIXMLASSERT( cap <= INT_MAX / 2 );
+ int newAllocated = cap * 2;
+ T* newMem = new T[newAllocated];
+ memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
+ if ( _mem != _pool ) {
+ delete [] _mem;
+ }
+ _mem = newMem;
+ _allocated = newAllocated;
+ }
+ }
+
+ T* _mem;
+ T _pool[INITIAL_SIZE];
+ int _allocated; // objects allocated
+ int _size; // number objects in use
+};
+
+
+/*
+ Parent virtual class of a pool for fast allocation
+ and deallocation of objects.
+*/
+class MemPool
+{
+public:
+ MemPool() {}
+ virtual ~MemPool() {}
+
+ virtual int ItemSize() const = 0;
+ virtual void* Alloc() = 0;
+ virtual void Free( void* ) = 0;
+ virtual void SetTracked() = 0;
+ virtual void Clear() = 0;
+};
+
+
+/*
+ Template child class to create pools of the correct type.
+*/
+template< int SIZE >
+class MemPoolT : public MemPool
+{
+public:
+ MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
+ ~MemPoolT() {
+ Clear();
+ }
+
+ void Clear() {
+ // Delete the blocks.
+ while( !_blockPtrs.Empty()) {
+ Block* b = _blockPtrs.Pop();
+ delete b;
+ }
+ _root = 0;
+ _currentAllocs = 0;
+ _nAllocs = 0;
+ _maxAllocs = 0;
+ _nUntracked = 0;
+ }
+
+ virtual int ItemSize() const {
+ return SIZE;
+ }
+ int CurrentAllocs() const {
+ return _currentAllocs;
+ }
+
+ virtual void* Alloc() {
+ if ( !_root ) {
+ // Need a new block.
+ Block* block = new Block();
+ _blockPtrs.Push( block );
+
+ for( int i=0; i<COUNT-1; ++i ) {
+ block->chunk[i].next = &block->chunk[i+1];
+ }
+ block->chunk[COUNT-1].next = 0;
+ _root = block->chunk;
+ }
+ void* result = _root;
+ _root = _root->next;
+
+ ++_currentAllocs;
+ if ( _currentAllocs > _maxAllocs ) {
+ _maxAllocs = _currentAllocs;
+ }
+ _nAllocs++;
+ _nUntracked++;
+ return result;
+ }
+
+ virtual void Free( void* mem ) {
+ if ( !mem ) {
+ return;
+ }
+ --_currentAllocs;
+ Chunk* chunk = static_cast<Chunk*>( mem );
+#ifdef DEBUG
+ memset( chunk, 0xfe, sizeof(Chunk) );
+#endif
+ chunk->next = _root;
+ _root = chunk;
+ }
+ void Trace( const char* name ) {
+ printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
+ name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );
+ }
+
+ void SetTracked() {
+ _nUntracked--;
+ }
+
+ int Untracked() const {
+ return _nUntracked;
+ }
+
+ // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
+ // The test file is large, 170k.
+ // Release: VS2010 gcc(no opt)
+ // 1k: 4000
+ // 2k: 4000
+ // 4k: 3900 21000
+ // 16k: 5200
+ // 32k: 4300
+ // 64k: 4000 21000
+ enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
+
+private:
+ MemPoolT( const MemPoolT& ); // not supported
+ void operator=( const MemPoolT& ); // not supported
+
+ union Chunk {
+ Chunk* next;
+ char mem[SIZE];
+ };
+ struct Block {
+ Chunk chunk[COUNT];
+ };
+ DynArray< Block*, 10 > _blockPtrs;
+ Chunk* _root;
+
+ int _currentAllocs;
+ int _nAllocs;
+ int _maxAllocs;
+ int _nUntracked;
+};
+
+
+
+/**
+ Implements the interface to the "Visitor pattern" (see the Accept() method.)
+ If you call the Accept() method, it requires being passed a XMLVisitor
+ class to handle callbacks. For nodes that contain other nodes (Document, Element)
+ you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
+ are simply called with Visit().
+
+ If you return 'true' from a Visit method, recursive parsing will continue. If you return
+ false, <b>no children of this node or its siblings</b> will be visited.
+
+ All flavors of Visit methods have a default implementation that returns 'true' (continue
+ visiting). You need to only override methods that are interesting to you.
+
+ Generally Accept() is called on the XMLDocument, although all nodes support visiting.
+
+ You should never change the document from a callback.
+
+ @sa XMLNode::Accept()
+*/
+class TINYXML2_LIB XMLVisitor
+{
+public:
+ virtual ~XMLVisitor() {}
+
+ /// Visit a document.
+ virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
+ return true;
+ }
+ /// Visit a document.
+ virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
+ return true;
+ }
+
+ /// Visit an element.
+ virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
+ return true;
+ }
+ /// Visit an element.
+ virtual bool VisitExit( const XMLElement& /*element*/ ) {
+ return true;
+ }
+
+ /// Visit a declaration.
+ virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
+ return true;
+ }
+ /// Visit a text node.
+ virtual bool Visit( const XMLText& /*text*/ ) {
+ return true;
+ }
+ /// Visit a comment node.
+ virtual bool Visit( const XMLComment& /*comment*/ ) {
+ return true;
+ }
+ /// Visit an unknown node.
+ virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
+ return true;
+ }
+};
+
+// WARNING: must match XMLDocument::_errorNames[]
+enum XMLError {
+ XML_SUCCESS = 0,
+ XML_NO_ERROR = 0,
+ XML_NO_ATTRIBUTE,
+ XML_WRONG_ATTRIBUTE_TYPE,
+ XML_ERROR_FILE_NOT_FOUND,
+ XML_ERROR_FILE_COULD_NOT_BE_OPENED,
+ XML_ERROR_FILE_READ_ERROR,
+ XML_ERROR_ELEMENT_MISMATCH,
+ XML_ERROR_PARSING_ELEMENT,
+ XML_ERROR_PARSING_ATTRIBUTE,
+ XML_ERROR_IDENTIFYING_TAG,
+ XML_ERROR_PARSING_TEXT,
+ XML_ERROR_PARSING_CDATA,
+ XML_ERROR_PARSING_COMMENT,
+ XML_ERROR_PARSING_DECLARATION,
+ XML_ERROR_PARSING_UNKNOWN,
+ XML_ERROR_EMPTY_DOCUMENT,
+ XML_ERROR_MISMATCHED_ELEMENT,
+ XML_ERROR_PARSING,
+ XML_CAN_NOT_CONVERT_TEXT,
+ XML_NO_TEXT_NODE,
+
+ XML_ERROR_COUNT
+};
+
+
+/*
+ Utility functionality.
+*/
+class XMLUtil
+{
+public:
+ static const char* SkipWhiteSpace( const char* p ) {
+ TIXMLASSERT( p );
+ while( IsWhiteSpace(*p) ) {
+ ++p;
+ }
+ TIXMLASSERT( p );
+ return p;
+ }
+ static char* SkipWhiteSpace( char* p ) {
+ return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) );
+ }
+
+ // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
+ // correct, but simple, and usually works.
+ static bool IsWhiteSpace( char p ) {
+ return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
+ }
+
+ inline static bool IsNameStartChar( unsigned char ch ) {
+ if ( ch >= 128 ) {
+ // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
+ return true;
+ }
+ if ( isalpha( ch ) ) {
+ return true;
+ }
+ return ch == ':' || ch == '_';
+ }
+
+ inline static bool IsNameChar( unsigned char ch ) {
+ return IsNameStartChar( ch )
+ || isdigit( ch )
+ || ch == '.'
+ || ch == '-';
+ }
+
+ inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
+ if ( p == q ) {
+ return true;
+ }
+ return strncmp( p, q, nChar ) == 0;
+ }
+
+ inline static bool IsUTF8Continuation( char p ) {
+ return ( p & 0x80 ) != 0;
+ }
+
+ static const char* ReadBOM( const char* p, bool* hasBOM );
+ // p is the starting location,
+ // the UTF-8 value of the entity will be placed in value, and length filled in.
+ static const char* GetCharacterRef( const char* p, char* value, int* length );
+ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+ // converts primitive types to strings
+ static void ToStr( int v, char* buffer, int bufferSize );
+ static void ToStr( unsigned v, char* buffer, int bufferSize );
+ static void ToStr( bool v, char* buffer, int bufferSize );
+ static void ToStr( float v, char* buffer, int bufferSize );
+ static void ToStr( double v, char* buffer, int bufferSize );
+
+ // converts strings to primitive types
+ static bool ToInt( const char* str, int* value );
+ static bool ToUnsigned( const char* str, unsigned* value );
+ static bool ToBool( const char* str, bool* value );
+ static bool ToFloat( const char* str, float* value );
+ static bool ToDouble( const char* str, double* value );
+};
+
+
+/** XMLNode is a base class for every object that is in the
+ XML Document Object Model (DOM), except XMLAttributes.
+ Nodes have siblings, a parent, and children which can
+ be navigated. A node is always in a XMLDocument.
+ The type of a XMLNode can be queried, and it can
+ be cast to its more defined type.
+
+ A XMLDocument allocates memory for all its Nodes.
+ When the XMLDocument gets deleted, all its Nodes
+ will also be deleted.
+
+ @verbatim
+ A Document can contain: Element (container or leaf)
+ Comment (leaf)
+ Unknown (leaf)
+ Declaration( leaf )
+
+ An Element can contain: Element (container or leaf)
+ Text (leaf)
+ Attributes (not on tree)
+ Comment (leaf)
+ Unknown (leaf)
+
+ @endverbatim
+*/
+class TINYXML2_LIB XMLNode
+{
+ friend class XMLDocument;
+ friend class XMLElement;
+public:
+
+ /// Get the XMLDocument that owns this XMLNode.
+ const XMLDocument* GetDocument() const {
+ TIXMLASSERT( _document );
+ return _document;
+ }
+ /// Get the XMLDocument that owns this XMLNode.
+ XMLDocument* GetDocument() {
+ TIXMLASSERT( _document );
+ return _document;
+ }
+
+ /// Safely cast to an Element, or null.
+ virtual XMLElement* ToElement() {
+ return 0;
+ }
+ /// Safely cast to Text, or null.
+ virtual XMLText* ToText() {
+ return 0;
+ }
+ /// Safely cast to a Comment, or null.
+ virtual XMLComment* ToComment() {
+ return 0;
+ }
+ /// Safely cast to a Document, or null.
+ virtual XMLDocument* ToDocument() {
+ return 0;
+ }
+ /// Safely cast to a Declaration, or null.
+ virtual XMLDeclaration* ToDeclaration() {
+ return 0;
+ }
+ /// Safely cast to an Unknown, or null.
+ virtual XMLUnknown* ToUnknown() {
+ return 0;
+ }
+
+ virtual const XMLElement* ToElement() const {
+ return 0;
+ }
+ virtual const XMLText* ToText() const {
+ return 0;
+ }
+ virtual const XMLComment* ToComment() const {
+ return 0;
+ }
+ virtual const XMLDocument* ToDocument() const {
+ return 0;
+ }
+ virtual const XMLDeclaration* ToDeclaration() const {
+ return 0;
+ }
+ virtual const XMLUnknown* ToUnknown() const {
+ return 0;
+ }
+
+ /** The meaning of 'value' changes for the specific type.
+ @verbatim
+ Document: empty (NULL is returned, not an empty string)
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+ */
+ const char* Value() const;
+
+ /** Set the Value of an XML node.
+ @sa Value()
+ */
+ void SetValue( const char* val, bool staticMem=false );
+
+ /// Get the parent of this node on the DOM.
+ const XMLNode* Parent() const {
+ return _parent;
+ }
+
+ XMLNode* Parent() {
+ return _parent;
+ }
+
+ /// Returns true if this node has no children.
+ bool NoChildren() const {
+ return !_firstChild;
+ }
+
+ /// Get the first child node, or null if none exists.
+ const XMLNode* FirstChild() const {
+ return _firstChild;
+ }
+
+ XMLNode* FirstChild() {
+ return _firstChild;
+ }
+
+ /** Get the first child element, or optionally the first child
+ element with the specified name.
+ */
+ const XMLElement* FirstChildElement( const char* name = 0 ) const;
+
+ XMLElement* FirstChildElement( const char* name = 0 ) {
+ return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
+ }
+
+ /// Get the last child node, or null if none exists.
+ const XMLNode* LastChild() const {
+ return _lastChild;
+ }
+
+ XMLNode* LastChild() {
+ return _lastChild;
+ }
+
+ /** Get the last child element or optionally the last child
+ element with the specified name.
+ */
+ const XMLElement* LastChildElement( const char* name = 0 ) const;
+
+ XMLElement* LastChildElement( const char* name = 0 ) {
+ return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
+ }
+
+ /// Get the previous (left) sibling node of this node.
+ const XMLNode* PreviousSibling() const {
+ return _prev;
+ }
+
+ XMLNode* PreviousSibling() {
+ return _prev;
+ }
+
+ /// Get the previous (left) sibling element of this node, with an optionally supplied name.
+ const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
+
+ XMLElement* PreviousSiblingElement( const char* name = 0 ) {
+ return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
+ }
+
+ /// Get the next (right) sibling node of this node.
+ const XMLNode* NextSibling() const {
+ return _next;
+ }
+
+ XMLNode* NextSibling() {
+ return _next;
+ }
+
+ /// Get the next (right) sibling element of this node, with an optionally supplied name.
+ const XMLElement* NextSiblingElement( const char* name = 0 ) const;
+
+ XMLElement* NextSiblingElement( const char* name = 0 ) {
+ return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
+ }
+
+ /**
+ Add a child node as the last (right) child.
+ If the child node is already part of the document,
+ it is moved from its old location to the new location.
+ Returns the addThis argument or 0 if the node does not
+ belong to the same document.
+ */
+ XMLNode* InsertEndChild( XMLNode* addThis );
+
+ XMLNode* LinkEndChild( XMLNode* addThis ) {
+ return InsertEndChild( addThis );
+ }
+ /**
+ Add a child node as the first (left) child.
+ If the child node is already part of the document,
+ it is moved from its old location to the new location.
+ Returns the addThis argument or 0 if the node does not
+ belong to the same document.
+ */
+ XMLNode* InsertFirstChild( XMLNode* addThis );
+ /**
+ Add a node after the specified child node.
+ If the child node is already part of the document,
+ it is moved from its old location to the new location.
+ Returns the addThis argument or 0 if the afterThis node
+ is not a child of this node, or if the node does not
+ belong to the same document.
+ */
+ XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
+
+ /**
+ Delete all the children of this node.
+ */
+ void DeleteChildren();
+
+ /**
+ Delete a child of this node.
+ */
+ void DeleteChild( XMLNode* node );
+
+ /**
+ Make a copy of this node, but not its children.
+ You may pass in a Document pointer that will be
+ the owner of the new Node. If the 'document' is
+ null, then the node returned will be allocated
+ from the current Document. (this->GetDocument())
+
+ Note: if called on a XMLDocument, this will return null.
+ */
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
+
+ /**
+ Test if 2 nodes are the same, but don't test children.
+ The 2 nodes do not need to be in the same Document.
+
+ Note: if called on a XMLDocument, this will return false.
+ */
+ virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
+
+ /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
+ XML tree will be conditionally visited and the host will be called back
+ via the XMLVisitor interface.
+
+ This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
+ the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
+ interface versus any other.)
+
+ The interface has been based on ideas from:
+
+ - http://www.saxproject.org/
+ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
+
+ Which are both good references for "visiting".
+
+ An example of using Accept():
+ @verbatim
+ XMLPrinter printer;
+ tinyxmlDoc.Accept( &printer );
+ const char* xmlcstr = printer.CStr();
+ @endverbatim
+ */
+ virtual bool Accept( XMLVisitor* visitor ) const = 0;
+
+protected:
+ XMLNode( XMLDocument* );
+ virtual ~XMLNode();
+
+ virtual char* ParseDeep( char*, StrPair* );
+
+ XMLDocument* _document;
+ XMLNode* _parent;
+ mutable StrPair _value;
+
+ XMLNode* _firstChild;
+ XMLNode* _lastChild;
+
+ XMLNode* _prev;
+ XMLNode* _next;
+
+private:
+ MemPool* _memPool;
+ void Unlink( XMLNode* child );
+ static void DeleteNode( XMLNode* node );
+ void InsertChildPreamble( XMLNode* insertThis ) const;
+
+ XMLNode( const XMLNode& ); // not supported
+ XMLNode& operator=( const XMLNode& ); // not supported
+};
+
+
+/** XML text.
+
+ Note that a text node can have child element nodes, for example:
+ @verbatim
+ <root>This is <b>bold</b></root>
+ @endverbatim
+
+ A text node can have 2 ways to output the next. "normal" output
+ and CDATA. It will default to the mode it was parsed from the XML file and
+ you generally want to leave it alone, but you can change the output mode with
+ SetCData() and query it with CData().
+*/
+class TINYXML2_LIB XMLText : public XMLNode
+{
+ friend class XMLBase;
+ friend class XMLDocument;
+public:
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ virtual XMLText* ToText() {
+ return this;
+ }
+ virtual const XMLText* ToText() const {
+ return this;
+ }
+
+ /// Declare whether this should be CDATA or standard text.
+ void SetCData( bool isCData ) {
+ _isCData = isCData;
+ }
+ /// Returns true if this is a CDATA text element.
+ bool CData() const {
+ return _isCData;
+ }
+
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
+ virtual ~XMLText() {}
+
+ char* ParseDeep( char*, StrPair* endTag );
+
+private:
+ bool _isCData;
+
+ XMLText( const XMLText& ); // not supported
+ XMLText& operator=( const XMLText& ); // not supported
+};
+
+
+/** An XML Comment. */
+class TINYXML2_LIB XMLComment : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLComment* ToComment() {
+ return this;
+ }
+ virtual const XMLComment* ToComment() const {
+ return this;
+ }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLComment( XMLDocument* doc );
+ virtual ~XMLComment();
+
+ char* ParseDeep( char*, StrPair* endTag );
+
+private:
+ XMLComment( const XMLComment& ); // not supported
+ XMLComment& operator=( const XMLComment& ); // not supported
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+ @verbatim
+ <?xml version="1.0" standalone="yes"?>
+ @endverbatim
+
+ TinyXML-2 will happily read or write files without a declaration,
+ however.
+
+ The text of the declaration isn't interpreted. It is parsed
+ and written as a string.
+*/
+class TINYXML2_LIB XMLDeclaration : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLDeclaration* ToDeclaration() {
+ return this;
+ }
+ virtual const XMLDeclaration* ToDeclaration() const {
+ return this;
+ }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLDeclaration( XMLDocument* doc );
+ virtual ~XMLDeclaration();
+
+ char* ParseDeep( char*, StrPair* endTag );
+
+private:
+ XMLDeclaration( const XMLDeclaration& ); // not supported
+ XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
+};
+
+
+/** Any tag that TinyXML-2 doesn't recognize is saved as an
+ unknown. It is a tag of text, but should not be modified.
+ It will be written back to the XML, unchanged, when the file
+ is saved.
+
+ DTD tags get thrown into XMLUnknowns.
+*/
+class TINYXML2_LIB XMLUnknown : public XMLNode
+{
+ friend class XMLDocument;
+public:
+ virtual XMLUnknown* ToUnknown() {
+ return this;
+ }
+ virtual const XMLUnknown* ToUnknown() const {
+ return this;
+ }
+
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ XMLUnknown( XMLDocument* doc );
+ virtual ~XMLUnknown();
+
+ char* ParseDeep( char*, StrPair* endTag );
+
+private:
+ XMLUnknown( const XMLUnknown& ); // not supported
+ XMLUnknown& operator=( const XMLUnknown& ); // not supported
+};
+
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+ number of attributes, each with a unique name.
+
+ @note The attributes are not XMLNodes. You may only query the
+ Next() attribute in a list.
+*/
+class TINYXML2_LIB XMLAttribute
+{
+ friend class XMLElement;
+public:
+ /// The name of the attribute.
+ const char* Name() const;
+
+ /// The value of the attribute.
+ const char* Value() const;
+
+ /// The next attribute in the list.
+ const XMLAttribute* Next() const {
+ return _next;
+ }
+
+ /** IntValue interprets the attribute as an integer, and returns the value.
+ If the value isn't an integer, 0 will be returned. There is no error checking;
+ use QueryIntValue() if you need error checking.
+ */
+ int IntValue() const {
+ int i=0;
+ QueryIntValue( &i );
+ return i;
+ }
+ /// Query as an unsigned integer. See IntValue()
+ unsigned UnsignedValue() const {
+ unsigned i=0;
+ QueryUnsignedValue( &i );
+ return i;
+ }
+ /// Query as a boolean. See IntValue()
+ bool BoolValue() const {
+ bool b=false;
+ QueryBoolValue( &b );
+ return b;
+ }
+ /// Query as a double. See IntValue()
+ double DoubleValue() const {
+ double d=0;
+ QueryDoubleValue( &d );
+ return d;
+ }
+ /// Query as a float. See IntValue()
+ float FloatValue() const {
+ float f=0;
+ QueryFloatValue( &f );
+ return f;
+ }
+
+ /** QueryIntValue interprets the attribute as an integer, and returns the value
+ in the provided parameter. The function will return XML_NO_ERROR on success,
+ and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
+ */
+ XMLError QueryIntValue( int* value ) const;
+ /// See QueryIntValue
+ XMLError QueryUnsignedValue( unsigned int* value ) const;
+ /// See QueryIntValue
+ XMLError QueryBoolValue( bool* value ) const;
+ /// See QueryIntValue
+ XMLError QueryDoubleValue( double* value ) const;
+ /// See QueryIntValue
+ XMLError QueryFloatValue( float* value ) const;
+
+ /// Set the attribute to a string value.
+ void SetAttribute( const char* value );
+ /// Set the attribute to value.
+ void SetAttribute( int value );
+ /// Set the attribute to value.
+ void SetAttribute( unsigned value );
+ /// Set the attribute to value.
+ void SetAttribute( bool value );
+ /// Set the attribute to value.
+ void SetAttribute( double value );
+ /// Set the attribute to value.
+ void SetAttribute( float value );
+
+private:
+ enum { BUF_SIZE = 200 };
+
+ XMLAttribute() : _next( 0 ), _memPool( 0 ) {}
+ virtual ~XMLAttribute() {}
+
+ XMLAttribute( const XMLAttribute& ); // not supported
+ void operator=( const XMLAttribute& ); // not supported
+ void SetName( const char* name );
+
+ char* ParseDeep( char* p, bool processEntities );
+
+ mutable StrPair _name;
+ mutable StrPair _value;
+ XMLAttribute* _next;
+ MemPool* _memPool;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+ and can contain other elements, text, comments, and unknowns.
+ Elements also contain an arbitrary number of attributes.
+*/
+class TINYXML2_LIB XMLElement : public XMLNode
+{
+ friend class XMLBase;
+ friend class XMLDocument;
+public:
+ /// Get the name of an element (which is the Value() of the node.)
+ const char* Name() const {
+ return Value();
+ }
+ /// Set the name of the element.
+ void SetName( const char* str, bool staticMem=false ) {
+ SetValue( str, staticMem );
+ }
+
+ virtual XMLElement* ToElement() {
+ return this;
+ }
+ virtual const XMLElement* ToElement() const {
+ return this;
+ }
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none
+ exists. For example:
+
+ @verbatim
+ const char* value = ele->Attribute( "foo" );
+ @endverbatim
+
+ The 'value' parameter is normally null. However, if specified,
+ the attribute will only be returned if the 'name' and 'value'
+ match. This allow you to write code:
+
+ @verbatim
+ if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
+ @endverbatim
+
+ rather than:
+ @verbatim
+ if ( ele->Attribute( "foo" ) ) {
+ if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
+ }
+ @endverbatim
+ */
+ const char* Attribute( const char* name, const char* value=0 ) const;
+
+ /** Given an attribute name, IntAttribute() returns the value
+ of the attribute interpreted as an integer. 0 will be
+ returned if there is an error. For a method with error
+ checking, see QueryIntAttribute()
+ */
+ int IntAttribute( const char* name ) const {
+ int i=0;
+ QueryIntAttribute( name, &i );
+ return i;
+ }
+ /// See IntAttribute()
+ unsigned UnsignedAttribute( const char* name ) const {
+ unsigned i=0;
+ QueryUnsignedAttribute( name, &i );
+ return i;
+ }
+ /// See IntAttribute()
+ bool BoolAttribute( const char* name ) const {
+ bool b=false;
+ QueryBoolAttribute( name, &b );
+ return b;
+ }
+ /// See IntAttribute()
+ double DoubleAttribute( const char* name ) const {
+ double d=0;
+ QueryDoubleAttribute( name, &d );
+ return d;
+ }
+ /// See IntAttribute()
+ float FloatAttribute( const char* name ) const {
+ float f=0;
+ QueryFloatAttribute( name, &f );
+ return f;
+ }
+
+ /** Given an attribute name, QueryIntAttribute() returns
+ XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
+ can't be performed, or XML_NO_ATTRIBUTE if the attribute
+ doesn't exist. If successful, the result of the conversion
+ will be written to 'value'. If not successful, nothing will
+ be written to 'value'. This allows you to provide default
+ value:
+
+ @verbatim
+ int value = 10;
+ QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
+ @endverbatim
+ */
+ XMLError QueryIntAttribute( const char* name, int* value ) const {
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return XML_NO_ATTRIBUTE;
+ }
+ return a->QueryIntValue( value );
+ }
+ /// See QueryIntAttribute()
+ XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return XML_NO_ATTRIBUTE;
+ }
+ return a->QueryUnsignedValue( value );
+ }
+ /// See QueryIntAttribute()
+ XMLError QueryBoolAttribute( const char* name, bool* value ) const {
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return XML_NO_ATTRIBUTE;
+ }
+ return a->QueryBoolValue( value );
+ }
+ /// See QueryIntAttribute()
+ XMLError QueryDoubleAttribute( const char* name, double* value ) const {
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return XML_NO_ATTRIBUTE;
+ }
+ return a->QueryDoubleValue( value );
+ }
+ /// See QueryIntAttribute()
+ XMLError QueryFloatAttribute( const char* name, float* value ) const {
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return XML_NO_ATTRIBUTE;
+ }
+ return a->QueryFloatValue( value );
+ }
+
+
+ /** Given an attribute name, QueryAttribute() returns
+ XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
+ can't be performed, or XML_NO_ATTRIBUTE if the attribute
+ doesn't exist. It is overloaded for the primitive types,
+ and is a generally more convenient replacement of
+ QueryIntAttribute() and related functions.
+
+ If successful, the result of the conversion
+ will be written to 'value'. If not successful, nothing will
+ be written to 'value'. This allows you to provide default
+ value:
+
+ @verbatim
+ int value = 10;
+ QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
+ @endverbatim
+ */
+ int QueryAttribute( const char* name, int* value ) const {
+ return QueryIntAttribute( name, value );
+ }
+
+ int QueryAttribute( const char* name, unsigned int* value ) const {
+ return QueryUnsignedAttribute( name, value );
+ }
+
+ int QueryAttribute( const char* name, bool* value ) const {
+ return QueryBoolAttribute( name, value );
+ }
+
+ int QueryAttribute( const char* name, double* value ) const {
+ return QueryDoubleAttribute( name, value );
+ }
+
+ int QueryAttribute( const char* name, float* value ) const {
+ return QueryFloatAttribute( name, value );
+ }
+
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, const char* value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, int value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, unsigned value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, bool value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, double value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, float value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
+
+ /**
+ Delete an attribute.
+ */
+ void DeleteAttribute( const char* name );
+
+ /// Return the first attribute in the list.
+ const XMLAttribute* FirstAttribute() const {
+ return _rootAttribute;
+ }
+ /// Query a specific attribute in the list.
+ const XMLAttribute* FindAttribute( const char* name ) const;
+
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, GetText() is limited compared to getting the XMLText child
+ and accessing it directly.
+
+ If the first child of 'this' is a XMLText, the GetText()
+ returns the character string of the Text node, else null is returned.
+
+ This is a convenient method for getting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ const char* str = fooElement->GetText();
+ @endverbatim
+
+ 'str' will be a pointer to "This is text".
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then the value of str would be null. The first child node isn't a text node, it is
+ another element. From this XML:
+ @verbatim
+ <foo>This is <b>text</b></foo>
+ @endverbatim
+ GetText() will return "This is ".
+ */
+ const char* GetText() const;
+
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, SetText() is limited compared to creating an XMLText child
+ and mutating it directly.
+
+ If the first child of 'this' is a XMLText, SetText() sets its value to
+ the given string, otherwise it will create a first child that is an XMLText.
+
+ This is a convenient method for setting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ fooElement->SetText( "Hullaballoo!" );
+ <foo>Hullaballoo!</foo>
+ @endverbatim
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then it will not change "This is text", but rather prefix it with a text element:
+ @verbatim
+ <foo>Hullaballoo!<b>This is text</b></foo>
+ @endverbatim
+
+ For this XML:
+ @verbatim
+ <foo />
+ @endverbatim
+ SetText() will generate
+ @verbatim
+ <foo>Hullaballoo!</foo>
+ @endverbatim
+ */
+ void SetText( const char* inText );
+ /// Convenience method for setting text inside an element. See SetText() for important limitations.
+ void SetText( int value );
+ /// Convenience method for setting text inside an element. See SetText() for important limitations.
+ void SetText( unsigned value );
+ /// Convenience method for setting text inside an element. See SetText() for important limitations.
+ void SetText( bool value );
+ /// Convenience method for setting text inside an element. See SetText() for important limitations.
+ void SetText( double value );
+ /// Convenience method for setting text inside an element. See SetText() for important limitations.
+ void SetText( float value );
+
+ /**
+ Convenience method to query the value of a child text node. This is probably best
+ shown by example. Given you have a document is this form:
+ @verbatim
+ <point>
+ <x>1</x>
+ <y>1.4</y>
+ </point>
+ @endverbatim
+
+ The QueryIntText() and similar functions provide a safe and easier way to get to the
+ "value" of x and y.
+
+ @verbatim
+ int x = 0;
+ float y = 0; // types of x and y are contrived for example
+ const XMLElement* xElement = pointElement->FirstChildElement( "x" );
+ const XMLElement* yElement = pointElement->FirstChildElement( "y" );
+ xElement->QueryIntText( &x );
+ yElement->QueryFloatText( &y );
+ @endverbatim
+
+ @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
+ to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
+
+ */
+ XMLError QueryIntText( int* ival ) const;
+ /// See QueryIntText()
+ XMLError QueryUnsignedText( unsigned* uval ) const;
+ /// See QueryIntText()
+ XMLError QueryBoolText( bool* bval ) const;
+ /// See QueryIntText()
+ XMLError QueryDoubleText( double* dval ) const;
+ /// See QueryIntText()
+ XMLError QueryFloatText( float* fval ) const;
+
+ // internal:
+ enum {
+ OPEN, // <foo>
+ CLOSED, // <foo/>
+ CLOSING // </foo>
+ };
+ int ClosingType() const {
+ return _closingType;
+ }
+ virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+ virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+ char* ParseDeep( char* p, StrPair* endTag );
+
+private:
+ XMLElement( XMLDocument* doc );
+ virtual ~XMLElement();
+ XMLElement( const XMLElement& ); // not supported
+ void operator=( const XMLElement& ); // not supported
+
+ XMLAttribute* FindAttribute( const char* name ) {
+ return const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute( name ));
+ }
+ XMLAttribute* FindOrCreateAttribute( const char* name );
+ //void LinkAttribute( XMLAttribute* attrib );
+ char* ParseAttributes( char* p );
+ static void DeleteAttribute( XMLAttribute* attribute );
+
+ enum { BUF_SIZE = 200 };
+ int _closingType;
+ // The attribute list is ordered; there is no 'lastAttribute'
+ // because the list needs to be scanned for dupes before adding
+ // a new attribute.
+ XMLAttribute* _rootAttribute;
+};
+
+
+enum Whitespace {
+ PRESERVE_WHITESPACE,
+ COLLAPSE_WHITESPACE
+};
+
+
+/** A Document binds together all the functionality.
+ It can be saved, loaded, and printed to the screen.
+ All Nodes are connected and allocated to a Document.
+ If the Document is deleted, all its Nodes are also deleted.
+*/
+class TINYXML2_LIB XMLDocument : public XMLNode
+{
+ friend class XMLElement;
+public:
+ /// constructor
+ XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
+ ~XMLDocument();
+
+ virtual XMLDocument* ToDocument() {
+ TIXMLASSERT( this == _document );
+ return this;
+ }
+ virtual const XMLDocument* ToDocument() const {
+ TIXMLASSERT( this == _document );
+ return this;
+ }
+
+ /**
+ Parse an XML file from a character string.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+
+ You may optionally pass in the 'nBytes', which is
+ the number of bytes which will be parsed. If not
+ specified, TinyXML-2 will assume 'xml' points to a
+ null terminated string.
+ */
+ XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
+
+ /**
+ Load an XML file from disk.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ XMLError LoadFile( const char* filename );
+
+ /**
+ Load an XML file from disk. You are responsible
+ for providing and closing the FILE*.
+
+ NOTE: The file should be opened as binary ("rb")
+ not text in order for TinyXML-2 to correctly
+ do newline normalization.
+
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ XMLError LoadFile( FILE* );
+
+ /**
+ Save the XML file to disk.
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ XMLError SaveFile( const char* filename, bool compact = false );
+
+ /**
+ Save the XML file to disk. You are responsible
+ for providing and closing the FILE*.
+
+ Returns XML_NO_ERROR (0) on success, or
+ an errorID.
+ */
+ XMLError SaveFile( FILE* fp, bool compact = false );
+
+ bool ProcessEntities() const {
+ return _processEntities;
+ }
+ Whitespace WhitespaceMode() const {
+ return _whitespace;
+ }
+
+ /**
+ Returns true if this document has a leading Byte Order Mark of UTF8.
+ */
+ bool HasBOM() const {
+ return _writeBOM;
+ }
+ /** Sets whether to write the BOM when writing the file.
+ */
+ void SetBOM( bool useBOM ) {
+ _writeBOM = useBOM;
+ }
+
+ /** Return the root element of DOM. Equivalent to FirstChildElement().
+ To get the first node, use FirstChild().
+ */
+ XMLElement* RootElement() {
+ return FirstChildElement();
+ }
+ const XMLElement* RootElement() const {
+ return FirstChildElement();
+ }
+
+ /** Print the Document. If the Printer is not provided, it will
+ print to stdout. If you provide Printer, this can print to a file:
+ @verbatim
+ XMLPrinter printer( fp );
+ doc.Print( &printer );
+ @endverbatim
+
+ Or you can use a printer to print to memory:
+ @verbatim
+ XMLPrinter printer;
+ doc.Print( &printer );
+ // printer.CStr() has a const char* to the XML
+ @endverbatim
+ */
+ void Print( XMLPrinter* streamer=0 ) const;
+ virtual bool Accept( XMLVisitor* visitor ) const;
+
+ /**
+ Create a new Element associated with
+ this Document. The memory for the Element
+ is managed by the Document.
+ */
+ XMLElement* NewElement( const char* name );
+ /**
+ Create a new Comment associated with
+ this Document. The memory for the Comment
+ is managed by the Document.
+ */
+ XMLComment* NewComment( const char* comment );
+ /**
+ Create a new Text associated with
+ this Document. The memory for the Text
+ is managed by the Document.
+ */
+ XMLText* NewText( const char* text );
+ /**
+ Create a new Declaration associated with
+ this Document. The memory for the object
+ is managed by the Document.
+
+ If the 'text' param is null, the standard
+ declaration is used.:
+ @verbatim
+ <?xml version="1.0" encoding="UTF-8"?>
+ @endverbatim
+ */
+ XMLDeclaration* NewDeclaration( const char* text=0 );
+ /**
+ Create a new Unknown associated with
+ this Document. The memory for the object
+ is managed by the Document.
+ */
+ XMLUnknown* NewUnknown( const char* text );
+
+ /**
+ Delete a node associated with this document.
+ It will be unlinked from the DOM.
+ */
+ void DeleteNode( XMLNode* node );
+
+ void SetError( XMLError error, const char* str1, const char* str2 );
+
+ /// Return true if there was an error parsing the document.
+ bool Error() const {
+ return _errorID != XML_NO_ERROR;
+ }
+ /// Return the errorID.
+ XMLError ErrorID() const {
+ return _errorID;
+ }
+ const char* ErrorName() const;
+
+ /// Return a possibly helpful diagnostic location or string.
+ const char* GetErrorStr1() const {
+ return _errorStr1;
+ }
+ /// Return a possibly helpful secondary diagnostic location or string.
+ const char* GetErrorStr2() const {
+ return _errorStr2;
+ }
+ /// If there is an error, print it to stdout.
+ void PrintError() const;
+
+ /// Clear the document, resetting it to the initial state.
+ void Clear();
+
+ // internal
+ char* Identify( char* p, XMLNode** node );
+
+ virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
+ return 0;
+ }
+ virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
+ return false;
+ }
+
+private:
+ XMLDocument( const XMLDocument& ); // not supported
+ void operator=( const XMLDocument& ); // not supported
+
+ bool _writeBOM;
+ bool _processEntities;
+ XMLError _errorID;
+ Whitespace _whitespace;
+ const char* _errorStr1;
+ const char* _errorStr2;
+ char* _charBuffer;
+
+ MemPoolT< sizeof(XMLElement) > _elementPool;
+ MemPoolT< sizeof(XMLAttribute) > _attributePool;
+ MemPoolT< sizeof(XMLText) > _textPool;
+ MemPoolT< sizeof(XMLComment) > _commentPool;
+
+ static const char* _errorNames[XML_ERROR_COUNT];
+
+ void Parse();
+};
+
+
+/**
+ A XMLHandle is a class that wraps a node pointer with null checks; this is
+ an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
+ DOM structure. It is a separate utility class.
+
+ Take an example:
+ @verbatim
+ <Document>
+ <Element attributeA = "valueA">
+ <Child attributeB = "value1" />
+ <Child attributeB = "value2" />
+ </Element>
+ </Document>
+ @endverbatim
+
+ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+ easy to write a *lot* of code that looks like:
+
+ @verbatim
+ XMLElement* root = document.FirstChildElement( "Document" );
+ if ( root )
+ {
+ XMLElement* element = root->FirstChildElement( "Element" );
+ if ( element )
+ {
+ XMLElement* child = element->FirstChildElement( "Child" );
+ if ( child )
+ {
+ XMLElement* child2 = child->NextSiblingElement( "Child" );
+ if ( child2 )
+ {
+ // Finally do something useful.
+ @endverbatim
+
+ And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
+ of such code. A XMLHandle checks for null pointers so it is perfectly safe
+ and correct to use:
+
+ @verbatim
+ XMLHandle docHandle( &document );
+ XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
+ if ( child2 )
+ {
+ // do something useful
+ @endverbatim
+
+ Which is MUCH more concise and useful.
+
+ It is also safe to copy handles - internally they are nothing more than node pointers.
+ @verbatim
+ XMLHandle handleCopy = handle;
+ @endverbatim
+
+ See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
+*/
+class TINYXML2_LIB XMLHandle
+{
+public:
+ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+ XMLHandle( XMLNode* node ) {
+ _node = node;
+ }
+ /// Create a handle from a node.
+ XMLHandle( XMLNode& node ) {
+ _node = &node;
+ }
+ /// Copy constructor
+ XMLHandle( const XMLHandle& ref ) {
+ _node = ref._node;
+ }
+ /// Assignment
+ XMLHandle& operator=( const XMLHandle& ref ) {
+ _node = ref._node;
+ return *this;
+ }
+
+ /// Get the first child of this handle.
+ XMLHandle FirstChild() {
+ return XMLHandle( _node ? _node->FirstChild() : 0 );
+ }
+ /// Get the first child element of this handle.
+ XMLHandle FirstChildElement( const char* name = 0 ) {
+ return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
+ }
+ /// Get the last child of this handle.
+ XMLHandle LastChild() {
+ return XMLHandle( _node ? _node->LastChild() : 0 );
+ }
+ /// Get the last child element of this handle.
+ XMLHandle LastChildElement( const char* name = 0 ) {
+ return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
+ }
+ /// Get the previous sibling of this handle.
+ XMLHandle PreviousSibling() {
+ return XMLHandle( _node ? _node->PreviousSibling() : 0 );
+ }
+ /// Get the previous sibling element of this handle.
+ XMLHandle PreviousSiblingElement( const char* name = 0 ) {
+ return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
+ }
+ /// Get the next sibling of this handle.
+ XMLHandle NextSibling() {
+ return XMLHandle( _node ? _node->NextSibling() : 0 );
+ }
+ /// Get the next sibling element of this handle.
+ XMLHandle NextSiblingElement( const char* name = 0 ) {
+ return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
+ }
+
+ /// Safe cast to XMLNode. This can return null.
+ XMLNode* ToNode() {
+ return _node;
+ }
+ /// Safe cast to XMLElement. This can return null.
+ XMLElement* ToElement() {
+ return ( ( _node == 0 ) ? 0 : _node->ToElement() );
+ }
+ /// Safe cast to XMLText. This can return null.
+ XMLText* ToText() {
+ return ( ( _node == 0 ) ? 0 : _node->ToText() );
+ }
+ /// Safe cast to XMLUnknown. This can return null.
+ XMLUnknown* ToUnknown() {
+ return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );
+ }
+ /// Safe cast to XMLDeclaration. This can return null.
+ XMLDeclaration* ToDeclaration() {
+ return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );
+ }
+
+private:
+ XMLNode* _node;
+};
+
+
+/**
+ A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
+ same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
+*/
+class TINYXML2_LIB XMLConstHandle
+{
+public:
+ XMLConstHandle( const XMLNode* node ) {
+ _node = node;
+ }
+ XMLConstHandle( const XMLNode& node ) {
+ _node = &node;
+ }
+ XMLConstHandle( const XMLConstHandle& ref ) {
+ _node = ref._node;
+ }
+
+ XMLConstHandle& operator=( const XMLConstHandle& ref ) {
+ _node = ref._node;
+ return *this;
+ }
+
+ const XMLConstHandle FirstChild() const {
+ return XMLConstHandle( _node ? _node->FirstChild() : 0 );
+ }
+ const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
+ return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
+ }
+ const XMLConstHandle LastChild() const {
+ return XMLConstHandle( _node ? _node->LastChild() : 0 );
+ }
+ const XMLConstHandle LastChildElement( const char* name = 0 ) const {
+ return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
+ }
+ const XMLConstHandle PreviousSibling() const {
+ return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
+ }
+ const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
+ return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
+ }
+ const XMLConstHandle NextSibling() const {
+ return XMLConstHandle( _node ? _node->NextSibling() : 0 );
+ }
+ const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
+ return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
+ }
+
+
+ const XMLNode* ToNode() const {
+ return _node;
+ }
+ const XMLElement* ToElement() const {
+ return ( ( _node == 0 ) ? 0 : _node->ToElement() );
+ }
+ const XMLText* ToText() const {
+ return ( ( _node == 0 ) ? 0 : _node->ToText() );
+ }
+ const XMLUnknown* ToUnknown() const {
+ return ( ( _node == 0 ) ? 0 : _node->ToUnknown() );
+ }
+ const XMLDeclaration* ToDeclaration() const {
+ return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() );
+ }
+
+private:
+ const XMLNode* _node;
+};
+
+
+/**
+ Printing functionality. The XMLPrinter gives you more
+ options than the XMLDocument::Print() method.
+
+ It can:
+ -# Print to memory.
+ -# Print to a file you provide.
+ -# Print XML without a XMLDocument.
+
+ Print to Memory
+
+ @verbatim
+ XMLPrinter printer;
+ doc.Print( &printer );
+ SomeFunction( printer.CStr() );
+ @endverbatim
+
+ Print to a File
+
+ You provide the file pointer.
+ @verbatim
+ XMLPrinter printer( fp );
+ doc.Print( &printer );
+ @endverbatim
+
+ Print without a XMLDocument
+
+ When loading, an XML parser is very useful. However, sometimes
+ when saving, it just gets in the way. The code is often set up
+ for streaming, and constructing the DOM is just overhead.
+
+ The Printer supports the streaming case. The following code
+ prints out a trivially simple XML file without ever creating
+ an XML document.
+
+ @verbatim
+ XMLPrinter printer( fp );
+ printer.OpenElement( "foo" );
+ printer.PushAttribute( "foo", "bar" );
+ printer.CloseElement();
+ @endverbatim
+*/
+class TINYXML2_LIB XMLPrinter : public XMLVisitor
+{
+public:
+ /** Construct the printer. If the FILE* is specified,
+ this will print to the FILE. Else it will print
+ to memory, and the result is available in CStr().
+ If 'compact' is set to true, then output is created
+ with only required whitespace and newlines.
+ */
+ XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
+ virtual ~XMLPrinter() {}
+
+ /** If streaming, write the BOM and declaration. */
+ void PushHeader( bool writeBOM, bool writeDeclaration );
+ /** If streaming, start writing an element.
+ The element must be closed with CloseElement()
+ */
+ void OpenElement( const char* name, bool compactMode=false );
+ /// If streaming, add an attribute to an open element.
+ void PushAttribute( const char* name, const char* value );
+ void PushAttribute( const char* name, int value );
+ void PushAttribute( const char* name, unsigned value );
+ void PushAttribute( const char* name, bool value );
+ void PushAttribute( const char* name, double value );
+ /// If streaming, close the Element.
+ virtual void CloseElement( bool compactMode=false );
+
+ /// Add a text node.
+ void PushText( const char* text, bool cdata=false );
+ /// Add a text node from an integer.
+ void PushText( int value );
+ /// Add a text node from an unsigned.
+ void PushText( unsigned value );
+ /// Add a text node from a bool.
+ void PushText( bool value );
+ /// Add a text node from a float.
+ void PushText( float value );
+ /// Add a text node from a double.
+ void PushText( double value );
+
+ /// Add a comment
+ void PushComment( const char* comment );
+
+ void PushDeclaration( const char* value );
+ void PushUnknown( const char* value );
+
+ virtual bool VisitEnter( const XMLDocument& /*doc*/ );
+ virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
+ return true;
+ }
+
+ virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
+ virtual bool VisitExit( const XMLElement& element );
+
+ virtual bool Visit( const XMLText& text );
+ virtual bool Visit( const XMLComment& comment );
+ virtual bool Visit( const XMLDeclaration& declaration );
+ virtual bool Visit( const XMLUnknown& unknown );
+
+ /**
+ If in print to memory mode, return a pointer to
+ the XML file in memory.
+ */
+ const char* CStr() const {
+ return _buffer.Mem();
+ }
+ /**
+ If in print to memory mode, return the size
+ of the XML file in memory. (Note the size returned
+ includes the terminating null.)
+ */
+ int CStrSize() const {
+ return _buffer.Size();
+ }
+ /**
+ If in print to memory mode, reset the buffer to the
+ beginning.
+ */
+ void ClearBuffer() {
+ _buffer.Clear();
+ _buffer.Push(0);
+ }
+
+protected:
+ virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
+
+ /** Prints out the space before an element. You may override to change
+ the space and tabs used. A PrintSpace() override should call Print().
+ */
+ virtual void PrintSpace( int depth );
+ void Print( const char* format, ... );
+
+ void SealElementIfJustOpened();
+ bool _elementJustOpened;
+ DynArray< const char*, 10 > _stack;
+
+private:
+ void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
+
+ bool _firstElement;
+ FILE* _fp;
+ int _depth;
+ int _textDepth;
+ bool _processEntities;
+ bool _compactMode;
+
+ enum {
+ ENTITY_RANGE = 64,
+ BUF_SIZE = 200
+ };
+ bool _entityFlag[ENTITY_RANGE];
+ bool _restrictedEntityFlag[ENTITY_RANGE];
+
+ DynArray< char, 20 > _buffer;
+};
+
+
+} // tinyxml2
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+#endif // TINYXML2_INCLUDED
diff --git a/hw3/include/transformation3d.h b/hw3/include/transformation3d.h
new file mode 100644
index 0000000..7b61ecc
--- /dev/null
+++ b/hw3/include/transformation3d.h
@@ -0,0 +1,77 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _TRANSFORMATION3D_H_
+#define _TRANSFORMATION3D_H_
+
+#include "vec3d.h"
+#include "mat3d.h"
+
+class transformation3d {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ transformation3d(void);
+ transformation3d(const vec3d& translation, const mat3d& transformation, const mat3d& inverseTransform);
+ transformation3d(const transformation3d& t);
+
+ //////////////
+ // Operator //
+ //////////////
+ transformation3d& operator=(const transformation3d& t);
+
+ transformation3d operator*(const transformation3d& t) const;
+ transformation3d& operator*=(const transformation3d& t);
+
+ //////////////
+ // Mutators //
+ //////////////
+ transformation3d& invert(void);
+
+ /////////////
+ // Methods //
+ /////////////
+ vec3d transformPoint(const vec3d& p) const;
+ vec3d transformDirection(const vec3d& d) const;
+ vec3d transformNormal(const vec3d& n) const;
+
+ vec3d inverseTransformPoint(const vec3d& p) const;
+ vec3d inverseTransformDirection(const vec3d& d) const;
+ vec3d inverseTransformNormal(const vec3d& n) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(transformation3d& a, transformation3d& b) { a._swap(b); }
+
+ friend transformation3d inverse(const transformation3d& t) { transformation3d i(t); return i.invert(); }
+
+ friend std::ostream& operator<<(std::ostream& s, const transformation3d& t)
+ {
+ t._print(s);
+ return s;
+ }
+
+ protected:
+ ///////////////////////
+ // Protected Methods //
+ ///////////////////////
+ void _swap(transformation3d& t);
+ void _assign(const transformation3d& t);
+ virtual void _print(std::ostream& s) const;
+
+ ////////////////////////////
+ // Protected Data Members //
+ ////////////////////////////
+ vec3d _translation;
+ mat3d _transformation;
+ mat3d _inverseTransformation;
+};
+
+#endif /* _TRANSFORMATION3D_H_ */
diff --git a/hw3/include/triangle.h b/hw3/include/triangle.h
new file mode 100644
index 0000000..f7d85bf
--- /dev/null
+++ b/hw3/include/triangle.h
@@ -0,0 +1,115 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _TRIANGLE_H_
+#define _TRIANGLE_H_
+
+#include <array>
+#include <vector>
+#include <memory>
+#include <ostream>
+
+#include "ray.h"
+#include "vec2d.h"
+#include "vec3d.h"
+#include "boundingBox.h"
+
+class triangle {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ triangle(void);
+ triangle(const triangle& t);
+ triangle(triangle&& t);
+
+ triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3);
+ triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list);
+
+ triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3);
+ triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list);
+
+ triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3);
+ triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list);
+
+ triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3);
+ triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ const vec3d& vertex(size_t index) const;
+ const vec3d& normal(size_t index) const;
+ const vec2d& textureCoordinate(size_t index) const;
+
+ bool hasPerVertexNormals(void) const;
+ bool hasPerVertexTextureCoordinates(void) const;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ triangle& operator=(const triangle& t);
+ triangle& operator=(triangle&& t);
+
+ /////////////
+ // Methods //
+ /////////////
+ bool intersect(const ray& r, vec3d& barycentricCoord, float& t) const;
+
+ boundingBox boundingbox(void) const;
+ vec3d vertex(const vec3d& barycentricCoord) const;
+ vec3d normal(void) const;
+ vec3d shadingAxis(void) const;
+ vec3d normal(const vec3d& barycentricCoord) const;
+ vec2d textureCoordinate(const vec3d& barycentricCoord) const;
+
+ vec3d sample(float r1, float r2, vec3d& barycentricCoord, float& pdf) const;
+ float area(void) const;
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(triangle& a, triangle& b) { a._swap(b); }
+
+ friend std::ostream& operator<<(std::ostream& s, const triangle& t)
+ {
+ s << "Triangle: v=(" << t.vertex(0) << "," << t.vertex(1) << "," << t.vertex(2) << ")";
+ if(t._normal_list)
+ s << ", n=(" << t.normal(0) << "," << t.normal(1) << "," << t.normal(2) << ")";
+ if(t._textureCoord_list)
+ s << ", t=(" << t.textureCoordinate(0) << "," << t.textureCoordinate(1) << "," << t.textureCoordinate(2) << ")";
+ return s;
+ }
+
+private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const triangle& t);
+ void _swap(triangle& t);
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::array<size_t, 3> _vertex_idx;
+ std::array<size_t, 3> _normal_idx;
+ std::array<size_t,3 > _textureCoord_idx;
+ std::shared_ptr<const std::vector<vec3d>> _vertex_list;
+ std::shared_ptr<const std::vector<vec3d>> _normal_list;
+ std::shared_ptr<const std::vector<vec2d>> _textureCoord_list;
+};
+
+#endif /* _TRIANGLE_H_ */
diff --git a/hw3/include/triangleMesh.h b/hw3/include/triangleMesh.h
new file mode 100644
index 0000000..9558602
--- /dev/null
+++ b/hw3/include/triangleMesh.h
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _TRIANGLEMESH_H_
+#define _TRIANGLEMESH_H_
+
+#include "vec2d.h"
+#include "vec3d.h"
+#include "shader_base.h"
+#include "boundedTriangle.h"
+#include "boundedCompound.h"
+
+class triangleMesh : public boundedCompound {
+ public:
+ //////////////////
+ // Constructors //
+ //////////////////
+ triangleMesh(void);
+ triangleMesh(const std::vector<triangle>& triangle_list, const std::shared_ptr<const shader_base>& shader, const transformation3d& transform=transformation3d());
+ triangleMesh(const triangleMesh&) = delete;
+
+ ///////////////
+ // Operators //
+ ///////////////
+ triangleMesh& operator=(const triangleMesh&) = delete;
+
+ /////////////
+ // Methods //
+ /////////////
+ virtual const std::vector<std::shared_ptr<const boundedPrimitive>>& compounds(void) const final override;
+
+ virtual bool hasShader(void) const override;
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ virtual void _print(std::ostream& s) const override;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ std::vector<std::shared_ptr<const boundedPrimitive>> _triangles;
+};
+
+#endif /* _TRIANGLEMESH_H_ */
diff --git a/hw3/include/util.h b/hw3/include/util.h
new file mode 100644
index 0000000..2146464
--- /dev/null
+++ b/hw3/include/util.h
@@ -0,0 +1,19 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <string>
+
+std::string getFilename(const std::string& path);
+std::string getExtension(const std::string& path);
+std::string getDirectory(const std::string& path);
+
+#endif /* _UTIL_H_ */
diff --git a/hw3/include/vec2d.h b/hw3/include/vec2d.h
new file mode 100644
index 0000000..36e0e5c
--- /dev/null
+++ b/hw3/include/vec2d.h
@@ -0,0 +1,117 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _VEC2D_H_
+#define _VEC2D_H_
+
+#include <ostream>
+#include <cmath>
+
+class vec2d {
+ public:
+ /////////////
+ // Typedef //
+ /////////////
+ typedef float value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ union {
+ struct { value_type x, y; };
+ struct { value_type u, v; };
+ value_type data[2];
+ };
+
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ explicit vec2d(const_reference value=0.0f);
+ vec2d(const_reference x, const_reference y);
+ vec2d(const vec2d& v);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ static size_t size(void) { return 2; }
+
+ iterator begin(void);
+ const_iterator begin(void) const;
+ iterator end(void);
+ const_iterator end(void) const;
+
+ const_reference operator[](size_t index) const;
+ reference operator[](size_t index);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ vec2d& operator=(const vec2d& v);
+
+ bool operator==(const vec2d& v) const;
+ bool operator!=(const vec2d& v) const;
+
+ vec2d operator-(void) const;
+
+ vec2d operator+(const vec2d& v) const;
+ vec2d operator-(const vec2d& v) const;
+ vec2d operator*(const vec2d& v) const;
+ vec2d operator*(const_reference scale) const;
+ vec2d operator/(const vec2d& v) const;
+ vec2d operator/(const_reference scale) const;
+
+ vec2d& operator+=(const vec2d& v);
+ vec2d& operator-=(const vec2d& v);
+ vec2d& operator*=(const vec2d& v);
+ vec2d& operator*=(const_reference scale);
+ vec2d& operator/=(const vec2d& v);
+ vec2d& operator/=(const_reference scale);
+
+ /////////////
+ // Methods //
+ /////////////
+ value_type dot(const vec2d& v) const;
+ value_type squared_length(void) const;
+ value_type length(void) const;
+ value_type squared_distance(const vec2d& v) const;
+ value_type distance(const vec2d& v) const;
+
+ ///////////////
+ // Modifiers //
+ ///////////////
+ vec2d& abs(void);
+ vec2d& normalize(void);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(vec2d& a, vec2d& b) { return a._swap(b); }
+ friend vec2d normalize(const vec2d& v) { return vec2d(v).normalize(); }
+ friend vec2d abs(const vec2d& v) { return vec2d(v).abs(); }
+ friend vec2d operator*(const_reference scale, const vec2d& v) { return (v*scale); }
+
+ friend std::ostream& operator<<(std::ostream& s, const vec2d& v)
+ {
+ s << "[" << v.x << "," << v.y << "]";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const vec2d& v);
+ void _swap(vec2d& v);
+};
+
+#endif /* _VEC2D_H_ */
diff --git a/hw3/include/vec3d.h b/hw3/include/vec3d.h
new file mode 100644
index 0000000..50d918f
--- /dev/null
+++ b/hw3/include/vec3d.h
@@ -0,0 +1,120 @@
+/******************************************************************/
+/* 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. */
+/******************************************************************/
+#ifndef _VEC3D_H_
+#define _VEC3D_H_
+
+#include <ostream>
+#include <cmath>
+
+class vec3d {
+ public:
+ /////////////
+ // Typedef //
+ /////////////
+ typedef float value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+
+ //////////////////
+ // Data Members //
+ //////////////////
+ union {
+ struct { value_type x, y, z; };
+ value_type data[3];
+ };
+
+ public:
+ /////////////////
+ // Constructor //
+ /////////////////
+ explicit vec3d(const_reference value=0.0f);
+ vec3d(const_reference x, const_reference y, const_reference z);
+ vec3d(const vec3d& v);
+
+ ////////////////
+ // Inspectors //
+ ////////////////
+ static size_t size(void) { return 3; }
+
+ iterator begin(void);
+ const_iterator begin(void) const;
+ iterator end(void);
+ const_iterator end(void) const;
+
+ const_reference operator[](size_t index) const;
+ reference operator[](size_t index);
+
+ ///////////////
+ // Operators //
+ ///////////////
+ vec3d& operator=(const vec3d& v);
+
+ bool operator==(const vec3d& v) const;
+ bool operator!=(const vec3d& v) const;
+
+ vec3d operator-(void) const;
+
+ vec3d operator+(const vec3d& v) const;
+ vec3d operator-(const vec3d& v) const;
+ vec3d operator*(const vec3d& v) const;
+ vec3d operator*(const_reference scale) const;
+ vec3d operator/(const vec3d& v) const;
+ vec3d operator/(const_reference scale) const;
+
+ vec3d& operator+=(const vec3d& v);
+ vec3d& operator-=(const vec3d& v);
+ vec3d& operator*=(const vec3d& v);
+ vec3d& operator*=(const_reference scale);
+ vec3d& operator/=(const vec3d& v);
+ vec3d& operator/=(const_reference scale);
+
+ /////////////
+ // Methods //
+ /////////////
+ value_type dot(const vec3d& v) const;
+ value_type squared_length(void) const;
+ value_type length(void) const;
+ value_type squared_distance(const vec3d& v) const;
+ value_type distance(const vec3d& v) const;
+
+ vec3d cross(const vec3d& v) const;
+
+ ///////////////
+ // Modifiers //
+ ///////////////
+ vec3d& abs(void);
+ vec3d& clamp(value_type lower=0.0f, value_type upper=1.0f);
+ vec3d& normalize(void);
+
+ /////////////
+ // Friends //
+ /////////////
+ friend void swap(vec3d& a, vec3d& b) { return a._swap(b); }
+ friend vec3d normalize(const vec3d& v) { return vec3d(v).normalize(); }
+ friend vec3d abs(const vec3d& v) { return vec3d(v).abs(); }
+ friend vec3d clamp(const vec3d& v, value_type lower=0.0f, value_type upper=1.0f) { return vec3d(v).clamp(lower, upper); }
+ friend vec3d operator*(const_reference scale, const vec3d& v) { return (v*scale); }
+
+ friend std::ostream& operator<<(std::ostream& s, const vec3d& v)
+ {
+ s << "[" << v.x << "," << v.y << "," << v.z << "]";
+ return s;
+ }
+
+ private:
+ /////////////////////
+ // Private Methods //
+ /////////////////////
+ void _assign(const vec3d& v);
+ void _swap(vec3d& v);
+};
+
+#endif /* _VEC3D_H_ */
diff --git a/hw3/src/.directory b/hw3/src/.directory
new file mode 100644
index 0000000..dbba490
--- /dev/null
+++ b/hw3/src/.directory
@@ -0,0 +1,4 @@
+[Dolphin]
+Timestamp=2016,2,3,13,46,28
+Version=3
+ViewMode=1
diff --git a/hw3/src/boundedCompound.cpp b/hw3/src/boundedCompound.cpp
new file mode 100644
index 0000000..1f43a82
--- /dev/null
+++ b/hw3/src/boundedCompound.cpp
@@ -0,0 +1,93 @@
+/******************************************************************/
+/* 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 <algorithm>
+
+#include "boundedCompound.h"
+#include "intersector_factory_base.h"
+
+/////////////////
+// Constructor //
+/////////////////
+boundedCompound::boundedCompound(void)
+ : boundedPrimitive()
+{
+ _transform = transformation3d();
+ _intersector = nullptr;
+}
+
+
+boundedCompound::boundedCompound(const transformation3d& transform, const std::shared_ptr<const shader_base>& shader)
+
+ : boundedPrimitive(boundingBox(), shader)
+{
+ _transform = transform;
+ _intersector = nullptr;
+}
+
+
+/////////////
+// Methods //
+/////////////
+intersectionPoint boundedCompound::intersect(const ray& r) const
+{
+ // sanity check
+ assert(_intersector);
+
+ // HW5: Implement this
+ // Incorporate _transformation in the intersection computation.
+ // Returns: intersectionPoint
+ // Modifies: nothing.
+
+ // pass intersection computation to _intersector
+ intersectionPoint ip = _intersector->intersect(r);
+
+ // Done.
+ return ip;
+}
+
+
+void boundedCompound::initialize(const intersector_factory_base& ifb)
+{
+ // create the _intersector
+ _intersector = ifb(*this);
+}
+
+
+void boundedCompound::initializeBoundingBox(void)
+{
+ // compute the bounding box in world coordinates
+ _bb = boundingBox();
+ for_each(compounds().begin(), compounds().end(), [&](const std::shared_ptr<const boundedPrimitive>& prim)
+ {
+ _bb += transform(prim->boundingbox(), _transform);
+ });
+}
+
+
+bool boundedCompound::hasShader(void) const
+{
+ // check if this has a shader
+ if(boundedPrimitive::hasShader()) return true;
+
+ // check if each child has a shader
+ for(auto itr = compounds().begin(); itr != compounds().end(); itr++)
+ {
+ if(!(*itr)->hasShader()) return false;
+ }
+
+ // Done.
+ return true;
+}
+
+
+void boundedCompound::_print(std::ostream& s) const
+{
+ s << "boundedCompound (" << _bb << ", " << compounds().size() << " compounds)";
+}
diff --git a/hw3/src/boundedPrimitive.cpp b/hw3/src/boundedPrimitive.cpp
new file mode 100644
index 0000000..d328b16
--- /dev/null
+++ b/hw3/src/boundedPrimitive.cpp
@@ -0,0 +1,50 @@
+/******************************************************************/
+/* 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 "boundedPrimitive.h"
+
+/////////////////
+// Constructor //
+/////////////////
+boundedPrimitive::boundedPrimitive(void)
+{
+ _bb = boundingBox();
+ _shader = nullptr;
+}
+
+boundedPrimitive::boundedPrimitive(const boundingBox& bb, const std::shared_ptr<const shader_base>& shader)
+{
+ _bb = bb;
+ _shader = shader;
+}
+
+
+/////////////
+// Methods //
+/////////////
+const boundingBox& boundedPrimitive::boundingbox(void) const
+{
+ return _bb;
+}
+
+
+bool boundedPrimitive::hitBoundingBox(const ray& r) const
+{
+ return _bb.isHit(r);
+}
+
+
+bool boundedPrimitive::hasShader(void) const
+{
+ return (_shader != nullptr);
+}
+
+void boundedPrimitive::_print(std::ostream& s) const
+{
+ s << "boundedPrimitive (" << _bb << ")";
+}
diff --git a/hw3/src/boundedTriangle.cpp b/hw3/src/boundedTriangle.cpp
new file mode 100644
index 0000000..bf8a367
--- /dev/null
+++ b/hw3/src/boundedTriangle.cpp
@@ -0,0 +1,53 @@
+/******************************************************************/
+/* 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 "boundedTriangle.h"
+
+
+//////////////////
+// Constructors //
+//////////////////
+boundedTriangle::boundedTriangle(void)
+ : boundedPrimitive()
+{
+ // Nothing
+}
+
+boundedTriangle::boundedTriangle(const triangle& tri, const std::shared_ptr<const shader_base>& shader)
+ : boundedPrimitive(tri.boundingbox(), shader)
+{
+ _triangle = tri;
+}
+
+
+/////////////
+// Methods //
+/////////////
+intersectionPoint boundedTriangle::intersect(const ray& r) const
+{
+ // intersect triangle
+ float t;
+ vec3d bc;
+ bool hit = _triangle.intersect(r, bc, t);
+
+ // empty ip if not hit
+ if(!hit) return intersectionPoint();
+
+ // if hit, create intersectionPoint record.
+ else return intersectionPoint(r, t, _shader,
+ _triangle.normal(bc),
+ _triangle.shadingAxis(),
+ _triangle.textureCoordinate(bc));
+}
+
+
+void boundedTriangle::_print(std::ostream& s) const
+{
+ s << "boundedTriangle (" << _bb << ", " << _triangle << ")";
+}
diff --git a/hw3/src/boundingBox.cpp b/hw3/src/boundingBox.cpp
new file mode 100644
index 0000000..9708093
--- /dev/null
+++ b/hw3/src/boundingBox.cpp
@@ -0,0 +1,185 @@
+/******************************************************************/
+/* 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 "interval.h"
+#include "constants.h"
+#include "boundingBox.h"
+
+
+/////////////////
+// Constructor //
+/////////////////
+boundingBox::boundingBox(void)
+{
+ // create an empty box (i.e., 'left' lies right of 'right')
+ _lfb = vec3d(+LARGE);
+ _rbt = vec3d(-LARGE);
+}
+
+
+boundingBox::boundingBox(const vec3d& lfb, const vec3d& rbt)
+{
+ _lfb = lfb;
+ _rbt = rbt;
+
+ // Make sure each component in _lfb is smaller than _rbt
+ for(unsigned int i=0; i < vec3d::size(); i++)
+ if(_rbt[i] < _lfb[i]) std::swap(_rbt[i], _lfb[i]);
+
+ // Done.
+}
+
+
+boundingBox::boundingBox(const boundingBox& bb)
+{
+ _lfb = bb._lfb;
+ _rbt = bb._rbt;
+}
+
+
+//////////////
+// Operator //
+//////////////
+boundingBox& boundingBox::operator=(const boundingBox& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+boundingBox& boundingBox::operator+=(const boundingBox& bb)
+{
+ // compute the union of two bounding boxes
+ for(unsigned int i=0; i < vec3d::size(); i++)
+ {
+ if(_lfb[i] > bb._lfb[i]) _lfb[i] = bb._lfb[i];
+ if(_rbt[i] < bb._rbt[i]) _rbt[i] = bb._rbt[i];
+ }
+
+ return *this;
+}
+
+
+boundingBox boundingBox::operator+(const boundingBox& bb) const
+{
+ boundingBox result(*this);
+ result += bb;
+ return result;
+}
+
+
+boundingBox& boundingBox::operator+=(const vec3d& point)
+{
+ // expand the bounding box to include 'point' (+ a small epsilon)
+ for(unsigned int i=0; i < vec3d::size(); i++)
+ {
+ if(_lfb[i] > point[i]-EPSILON) _lfb[i] = point[i]-EPSILON;
+ if(_rbt[i] < point[i]+EPSILON) _rbt[i] = point[i]+EPSILON;
+ }
+}
+
+
+/////////////
+// Methods //
+/////////////
+bool boundingBox::isHit(const ray& r) const
+{
+ // init
+ interval boxInterval(0, +LARGE);
+
+ // for every slab
+ for(unsigned int i=0; i != vec3d::size(); i++)
+ {
+ // compute the slab
+ interval slab(_lfb[i], _rbt[i]);
+ slab -= r.origin()[i];
+
+ // check for the case where the ray is parallel to the slab
+ if(fabs(r.direction()[i]) < EPSILON)
+ {
+ // if identical signs => no hit
+ if((slab.lower() < 0.0f) == (slab.upper() < 0.0f))
+ return false;
+
+ // skip remainder to this iteration
+ continue;
+ }
+ else
+ slab /= r.direction()[i];
+
+ // intersect
+ boxInterval.intersect(slab);
+ if(boxInterval.empty())
+ return false;
+ }
+
+ // Done.
+ return true;
+}
+
+
+vec3d boundingBox::center(void) const
+{
+ return 0.5f * (_lfb + _rbt);
+}
+
+
+vec3d boundingBox::corner(bool left, bool front, bool bottom) const
+{
+ return vec3d( left ? _lfb.x : _rbt.x,
+ front ? _lfb.y : _rbt.y,
+ bottom ? _lfb.z : _rbt.z );
+}
+
+
+//////////////
+// Mutators //
+//////////////
+boundingBox& boundingBox::transform(const transformation3d& t)
+{
+ boundingBox result;
+ for(unsigned int i=0; i <= 1; i++)
+ for(unsigned int j=0; j <= 1; j++)
+ for(unsigned int k=0; k <= 1; k++)
+ result += t.transformPoint(corner(i,j,k));
+
+ // Done.
+ _swap(result);
+ return *this;
+}
+
+
+boundingBox& boundingBox::inverseTransform(const transformation3d& t)
+{
+ boundingBox result;
+ for(unsigned int i=0; i <= 1; i++)
+ for(unsigned int j=0; j <= 1; j++)
+ for(unsigned int k=0; k <= 1; k++)
+ result += t.inverseTransformPoint(corner(i,j,k));
+
+ // Done.
+ _swap(result);
+ return *this;
+}
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void boundingBox::_swap(boundingBox& bb)
+{
+ swap(_lfb, bb._lfb);
+ swap(_rbt, bb._rbt);
+}
+
+
+void boundingBox::_assign(const boundingBox& bb)
+{
+ _lfb = bb._lfb;
+ _rbt = bb._rbt;
+}
diff --git a/hw3/src/camera.cpp b/hw3/src/camera.cpp
new file mode 100644
index 0000000..3393dc9
--- /dev/null
+++ b/hw3/src/camera.cpp
@@ -0,0 +1,150 @@
+/******************************************************************/
+/* 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 <cmath>
+
+#include "constants.h"
+#include "camera.h"
+
+/////////////////
+// Constructor //
+/////////////////
+camera::camera(void)
+{
+ _eye = vec3d();
+ _view = vec3d(0.0f, 0.0f, -1.0f);
+ _up = vec3d(0.0f, 1.0f, 0.0f);
+ _fov = 60.0f;
+ _width = _height = 256;
+}
+
+
+camera::camera(const vec3d& eye, const vec3d& viewDirection, const vec3d& up, float fov, size_t xres, size_t yres)
+{
+ _eye = eye;
+ _view = normalize(viewDirection);
+ _up = normalize(up);
+ _fov = fov;
+ _width = xres;
+ _height = yres;
+
+ // fix up if needed
+ vec3d right = _view.cross(up).normalize();
+ _up = right.cross(_view).normalize();
+}
+
+
+camera::camera(const camera& cam)
+{
+ _eye = cam._eye;
+ _view = cam._view;
+ _up = cam._up;
+ _fov = cam._fov;
+ _width = cam._width;
+ _height = cam._height;
+}
+
+
+///////////////
+// Operators //
+///////////////
+camera& camera::operator=(const camera& cam)
+{
+ _assign(cam);
+ return *this;
+}
+
+
+ray camera::operator()(float x, float y) const
+{
+ vec3d right = _view.cross(_up).normalize();
+
+ // aspect ratio
+ float aspect = (float)(_height) / (float)(_width);
+ float tanFov = tan(_fov / 180.0f * PI);
+
+ // compute view plane center, and U and V unnormalized axes.
+ vec3d center = _eye + _view;
+ vec3d U = 2.0f * tanFov * right;
+ vec3d V = -2.0f * tanFov * aspect * _up; // y runs from top to bottom (opposite direction of up)
+
+ // get point on view plane
+ vec3d p = center + (x / (float)(_width) - 0.5f) * U + (y / (float)(_height) - 0.5f) * V;
+
+ // Done.
+ return ray(_eye, p - _eye);
+}
+
+
+//////////////
+// Mutators //
+//////////////
+void camera::frameBoundingBox(const boundingBox& bb)
+{
+ // determine the best eye location, given the other parameters and a bounding box such that the bounding box maximally occupies the view
+ vec3d right = _view.cross(_up).normalize();
+ _eye = 0.5f * (bb.corner(true,true,true) + bb.corner(false,false,false));
+
+ // => find max projection in up and right direction.
+ float maxRight=-LARGE, maxUp=-LARGE, maxDepth=-LARGE;
+ for(unsigned int i=0; i < 8; i++)
+ {
+ vec3d c = bb.corner( (i&1)==1, (i&2)==2, (i&4)==4 ) - _eye;
+
+ float r = fabs(c.dot(right));
+ float u = fabs(c.dot(_up));
+ float d = fabs(c.dot(_view));
+
+ maxRight = std::max(maxRight, r);
+ maxUp = std::max(maxUp, u);
+ maxDepth = std::max(maxDepth, d);
+ }
+
+ // => compute optimal distance for up and right
+ float aspect = (float)(_height) / (float)(_width);
+ float tanFov = tan(_fov / 180.0f * PI);
+ float optDistUp = fabs(maxUp / tanFov);
+ float optDistRight = fabs(maxRight / (tanFov * aspect));
+
+ // => move _eye back based on (max) optimal distance
+ _eye -= _view * (std::max(optDistUp, optDistRight) + maxDepth);
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void camera::_swap(camera& cam)
+{
+ // sanity check
+ if(&cam == this) return;
+
+ // swap
+ swap(_eye, cam._eye);
+ swap(_view, cam._view);
+ swap(_up, cam._up);
+ std::swap(_fov, cam._fov);
+ std::swap(_width, cam._width);
+ std::swap(_height, cam._height);
+}
+
+
+void camera::_assign(const camera& cam)
+{
+ // sanity check
+ if(&cam == this) return;
+
+ // copy
+ _eye = cam._eye;
+ _view = cam._view;
+ _up = cam._up;
+ _fov = cam._fov;
+ _width = cam._width;
+ _height = cam._height;
+}
diff --git a/hw3/src/color.cpp b/hw3/src/color.cpp
new file mode 100644
index 0000000..b2b720f
--- /dev/null
+++ b/hw3/src/color.cpp
@@ -0,0 +1,233 @@
+/******************************************************************/
+/* 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 <cmath>
+#include <cassert>
+#include <algorithm>
+#include "color.h"
+
+//////////////////
+// Constructors //
+//////////////////
+color::color(color::const_reference value)
+{
+ r = g = b = value;
+}
+
+
+color::color(color::const_reference r, color::const_reference g, color::const_reference b)
+{
+ this->r = r;
+ this->g = g;
+ this->b = b;
+}
+
+
+color::color(const color& col)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+color::const_reference color::operator[](size_t index) const
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+color::reference color::operator[](size_t index)
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+color::iterator color::begin(void)
+{
+ return data;
+}
+
+
+color::const_iterator color::begin(void) const
+{
+ return data;
+}
+
+
+color::iterator color::end(void)
+{
+ return begin() + size();
+}
+
+
+color::const_iterator color::end(void) const
+{
+ return begin() + size();
+}
+
+
+///////////////
+// Operators //
+///////////////
+color& color::operator=(const color& col)
+{
+ _assign(col);
+ return *this;
+}
+
+
+bool color::operator==(const color& col) const
+{
+ return (r == col.r) && (g == col.g) && (b == col.b);
+}
+
+
+bool color::operator!=(const color& col) const
+{
+ return (r != col.r) || (g != col.g) || (b != col.b);
+}
+
+
+color color::operator+(const color& col) const
+{
+ return color(r + col.r, g + col.g, b + col.b);
+}
+
+
+color color::operator-(const color& col) const
+{
+ return color(r - col.r, g - col.g, b - col.b);
+}
+
+
+color color::operator*(const color& col) const
+{
+ return color(r * col.r, g * col.g, b * col.b);
+}
+
+
+color color::operator*(color::const_reference scale) const
+{
+ return color(r * scale, g * scale, b * scale);
+}
+
+
+color color::operator/(const color& col) const
+{
+ return color(r / col.r, g / col.g, b / col.b);
+}
+
+
+color color::operator/(color::const_reference scale) const
+{
+ return color(r / scale, g / scale, b / scale);
+}
+
+
+color& color::operator+=(const color& col)
+{
+ r += col.r;
+ g += col.g;
+ b += col.b;
+ return *this;
+}
+
+
+color& color::operator-=(const color& col)
+{
+ r -= col.r;
+ g -= col.g;
+ b -= col.b;
+ return *this;
+}
+
+
+color& color::operator*=(const color& col)
+{
+ r *= col.r;
+ g *= col.g;
+ b *= col.b;
+ return *this;
+}
+
+
+color& color::operator*=(color::const_reference scale)
+{
+ r *= scale;
+ g *= scale;
+ b *= scale;
+ return *this;
+}
+
+
+color& color::operator/=(const color& col)
+{
+ r /= col.r;
+ g /= col.g;
+ b /= col.b;
+ return *this;
+}
+
+
+color& color::operator/=(color::const_reference scale)
+{
+ r /= scale;
+ g /= scale;
+ b /= scale;
+ return *this;
+}
+
+
+
+///////////////
+// Modifiers //
+///////////////
+color& color::abs(void)
+{
+ std::for_each(begin(), end(), [](reference val)
+ {
+ if(val<0) val = -val;
+ });
+ return *this;
+}
+
+
+color& color::clamp(const_reference lowerBound, const_reference upperBound)
+{
+ std::for_each(begin(), end(), [&](reference val)
+ {
+ if(val < lowerBound) val = lowerBound;
+ else if(val > upperBound) val = upperBound;
+ });
+ return *this;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void color::_assign(const color& col)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
+
+
+void color::_swap(color& col)
+{
+ std::swap(r, col.r);
+ std::swap(g, col.g);
+ std::swap(b, col.b);
+}
diff --git a/hw3/src/compoundShader.cpp b/hw3/src/compoundShader.cpp
new file mode 100644
index 0000000..5e19f1f
--- /dev/null
+++ b/hw3/src/compoundShader.cpp
@@ -0,0 +1,60 @@
+/******************************************************************/
+/* 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 <algorithm>
+#include "compoundShader.h"
+
+//////////////////
+// Constructors //
+//////////////////
+compoundShader::compoundShader(const std::vector<std::shared_ptr<const shader_base>>& shader_list)
+ : shader_base()
+{
+ _compound = shader_list;
+}
+
+
+/////////////
+// Methods //
+/////////////
+color compoundShader::shade(const intersectionPoint& ip, const vec3d& light_dir) const
+{
+ color result(0.0f, 0.0f, 0.0f);
+ for_each(_compound.begin(), _compound.end(), [&](const std::shared_ptr<const shader_base>& shader)
+ {
+ result += shader->shade(ip, light_dir);
+ });
+
+ // Done.
+ return result;
+}
+
+
+shaderProperties compoundShader::properties(const intersectionPoint& ip) const
+{
+ // if any component has a property set, then set it for the compound
+ shaderProperties result(false, false);
+ for(unsigned int i=0; i < _compound.size(); i++)
+ result |= _compound[i]->properties(ip);
+
+ // Done.
+ return result;
+}
+
+
+void compoundShader::_print(std::ostream& s) const
+{
+ s << "Compound Shader (" << _compound.size() << " components): {";
+ for(unsigned int i=0; i < _compound.size(); i++)
+ {
+ s << *_compound[i];
+ if(i != _compound.size()-1) s << ", ";
+ }
+ s << "}";
+}
diff --git a/hw3/src/coordinateTransform.cpp b/hw3/src/coordinateTransform.cpp
new file mode 100644
index 0000000..29e19f4
--- /dev/null
+++ b/hw3/src/coordinateTransform.cpp
@@ -0,0 +1,67 @@
+/******************************************************************/
+/* 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 "coordinateTransform.h"
+
+//////////////////
+// Constructors //
+//////////////////
+coordinateTransformation::coordinateTransformation(void)
+{
+ // do nothing
+}
+
+
+coordinateTransformation::coordinateTransformation(const vec3d& normal)
+{
+ // normal == Z axis
+ vec3d X, Y, Z = normalize(normal);
+
+ // select Y axis
+ if(fabs(Z.x) < fabs(Z.y) && fabs(Z.x) < fabs(Z.z))
+ Y = normalize(vec3d(0.0f, Z.z, -Z.y));
+ else if(fabs(Z.y) < fabs(Z.z))
+ Y = normalize(vec3d(Z.z, 0.0f, -Z.x));
+ else
+ Y = normalize(vec3d(Z.y, -Z.x, 0.0f));
+
+ // create other axis
+ X = Y.cross(Z).normalize();
+
+ // copy
+ _transformation = mat3d(X, Y, Z);
+ _inverseTransformation = transpose(_transformation);
+
+ // Done.
+}
+
+
+coordinateTransformation::coordinateTransformation(const vec3d& normal, const vec3d& axis)
+{
+ // normal == Z axis
+ vec3d Z = normalize(normal);
+
+ // create other axis
+ vec3d axis_normalized = normalize(axis);
+ vec3d Y = Z.cross(axis_normalized).normalize();
+ vec3d X = Y.cross(Z).normalize();
+
+ // copy
+ _transformation = mat3d(X, Y, Z);
+ _inverseTransformation = transpose(_transformation);
+
+ // Done.
+}
+
+
+coordinateTransformation::coordinateTransformation(const vec3d& X, const vec3d& Y, const vec3d& Z)
+{
+ // trust user to provide an orthogonal set of vectors.
+ _transformation = mat3d(X, Y, Z);
+ _inverseTransformation = transpose(_transformation);
+}
diff --git a/hw3/src/diffuseBrdf.cpp b/hw3/src/diffuseBrdf.cpp
new file mode 100644
index 0000000..849e341
--- /dev/null
+++ b/hw3/src/diffuseBrdf.cpp
@@ -0,0 +1,88 @@
+/******************************************************************/
+/* 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 <cmath>
+#include "constants.h"
+#include "diffuseBrdf.h"
+
+//////////////////
+// Constructors //
+//////////////////
+diffuseBrdf::diffuseBrdf(const color& albedo)
+{
+ _albedo = albedo;
+}
+
+
+diffuseBrdf::diffuseBrdf(const diffuseBrdf& src)
+{
+ _albedo = src._albedo;
+}
+
+
+///////////////
+// Operators //
+///////////////
+diffuseBrdf& diffuseBrdf::operator=(const diffuseBrdf& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+/////////////
+// Methods //
+/////////////
+color diffuseBrdf::shade(const vec3d& in, const vec3d& out) const
+{
+ // HW3: Implement this.
+ // Returns the shaded color from a diffuse surface for an
+ // incident lighting direction of 'in'. The surface normal = (0,0,1).
+ // Returns: shaded color
+ // Modifies: nothing.
+ if (out.z < EPSILON) { return color(0.0f); }
+
+ vec3d normal;
+ float normal_dot_in;
+
+ normal = vec3d(0, 0, 1);
+ normal_dot_in = normal.dot(in);
+ return color(_albedo * normal_dot_in);
+}
+
+
+bool diffuseBrdf::isSpecular(void) const
+{
+ return false;
+}
+
+
+bool diffuseBrdf::isDiffuse(void) const
+{
+ return true;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void diffuseBrdf::_assign(const diffuseBrdf& src)
+{
+ _albedo = src._albedo;
+}
+
+
+void diffuseBrdf::_swap(diffuseBrdf& src)
+{
+ swap(_albedo, src._albedo);
+}
+
+void diffuseBrdf::_print(std::ostream& s) const
+{
+ s << "Diffuse BRDF: albedo=" << _albedo;
+}
diff --git a/hw3/src/diffuseReflectanceShader.cpp b/hw3/src/diffuseReflectanceShader.cpp
new file mode 100644
index 0000000..3fc9d99
--- /dev/null
+++ b/hw3/src/diffuseReflectanceShader.cpp
@@ -0,0 +1,35 @@
+/******************************************************************/
+/* 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 "diffuseReflectanceShader.h"
+
+
+/////////////////
+// Constructor //
+/////////////////
+diffuseReflectanceShader::diffuseReflectanceShader(const colorReflectanceParameter& albedo)
+ : reflectanceShader_base()
+{
+ _albedo = albedo;
+}
+
+
+///////////////////////
+// Protected Methods //
+///////////////////////
+std::unique_ptr<const brdf_base> diffuseReflectanceShader::make_brdf(const vec2d& textureCoord) const
+{
+ return std::unique_ptr<const brdf_base>(new diffuseBrdf( _albedo(textureCoord) ));
+}
+
+
+void diffuseReflectanceShader::_print(std::ostream& s) const
+{
+ s << "Diffuse Reflectance: albedo=" << _albedo;
+}
diff --git a/hw3/src/directionalLightsource.cpp b/hw3/src/directionalLightsource.cpp
new file mode 100644
index 0000000..4c53895
--- /dev/null
+++ b/hw3/src/directionalLightsource.cpp
@@ -0,0 +1,38 @@
+/******************************************************************/
+/* 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 "constants.h"
+#include "directionalLightsource.h"
+
+//////////////////
+// Constructors //
+//////////////////
+directionalLightsource::directionalLightsource(const vec3d& direction, const color& power)
+{
+ _direction = normalize(direction);
+ _power = power;
+}
+
+
+/////////////
+// Methods //
+/////////////
+lightSample directionalLightsource::intensityAt(const vec3d& point) const
+{
+ return lightSample(_direction, _power, +LARGE);
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void directionalLightsource::_print(std::ostream& s) const
+{
+ s << "Directional Lightsource: direction=" << _direction << ", power=" << _power;
+}
diff --git a/hw3/src/errorMessage.cpp b/hw3/src/errorMessage.cpp
new file mode 100644
index 0000000..3eddb6a
--- /dev/null
+++ b/hw3/src/errorMessage.cpp
@@ -0,0 +1,34 @@
+/******************************************************************/
+/* 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 "errorMessage.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+void errorMessage(const char* msg, ...)
+{
+ printf("ERROR: ");
+ va_list args;
+ va_start(args, msg);
+ vprintf(msg, args);
+ va_end(args);
+ printf("\r\n");
+ exit(-1);
+}
+
+
+void warningMessage(const char* msg, ...)
+{
+ printf("WARNING: ");
+ va_list args;
+ va_start(args, msg);
+ vprintf(msg, args);
+ va_end(args);
+ printf("\r\n");
+}
diff --git a/hw3/src/image.cpp b/hw3/src/image.cpp
new file mode 100644
index 0000000..59434cc
--- /dev/null
+++ b/hw3/src/image.cpp
@@ -0,0 +1,122 @@
+/******************************************************************/
+/* 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 "image.h"
+
+#include <algorithm>
+#include <cassert>
+
+//////////////////
+// Constructors //
+//////////////////
+image::image(image::size_type width, image::size_type height) : _width(width), _height(height), _data()
+{
+ if(width != 0 && height != 0)
+ _data.reset(new value_type[width*height]);
+}
+
+
+image::image(image::size_type width, image::size_type height, const_reference col) : image(width, height)
+{
+ std::fill(begin(), end(), col);
+}
+
+
+image::image(const image& src) : image(src.width(), src.height())
+{
+ std::copy(src.begin(), src.end(), begin());
+}
+
+
+image::image(image&& src)
+{
+ _swap(src);
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+image::iterator image::begin(void)
+{
+ return _data.get();
+}
+
+
+image::const_iterator image::begin(void) const
+{
+ return _data.get();
+}
+
+
+image::iterator image::end(void)
+{
+ return begin() + size();
+}
+
+
+image::const_iterator image::end(void) const
+{
+ return begin() + size();
+}
+
+
+///////////////
+// Operators //
+///////////////
+image& image::operator=(const image& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+image& image::operator=(image&& src)
+{
+ _swap(src);
+ return *this;
+}
+
+image::reference image::operator()(image::size_type x, image::size_type y)
+{
+ assert(x >= 0 && x < width());
+ assert(y >= 0 && y < height());
+ return begin()[y*width() + x];
+}
+
+
+image::const_reference image::operator()(image::size_type x, image::size_type y) const
+{
+ assert(x >= 0 && x < width());
+ assert(y >= 0 && y < height());
+ return begin()[y*width() + x];
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void image::_swap(image& img)
+{
+ std::swap(_width, img._width);
+ std::swap(_height, img._height);
+ std::swap(_data, img._data);
+}
+
+
+void image::_assign(const image& src)
+{
+ // sanity check
+ if(&src == this) return;
+
+ // make copy
+ image temp(src);
+ _swap(temp);
+
+ // Done
+}
diff --git a/hw3/src/imageIO.cpp b/hw3/src/imageIO.cpp
new file mode 100644
index 0000000..cee716b
--- /dev/null
+++ b/hw3/src/imageIO.cpp
@@ -0,0 +1,46 @@
+/******************************************************************/
+/* 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 "util.h"
+#include "imageIO.h"
+#include "imageIO.ppm.h"
+#include "imageIO.pfm.h"
+#include "errorMessage.h"
+
+
+////////////
+// Import //
+////////////
+void importImage(const std::string& name, image& img)
+{
+ // get extension
+ std::string ext = getExtension(name);
+ if(ext == "") errorMessage("Unable to determine extension in '%s'.", name.c_str());
+
+ // call image format handler based on extension
+ if(ext == "PPM" || ext == "ppm") importPPM(name, img);
+ else if(ext == "PFM" || ext == "pfm") importPFM(name, img);
+ else errorMessage("Unknown image format: '%s'.", ext.c_str());
+}
+
+
+////////////
+// Export //
+////////////
+void exportImage(const std::string& name, const image& img)
+{
+ // get extension
+ std::string ext = getExtension(name);
+ if(ext == "") errorMessage("Unable to determine extension in '%s'.", name.c_str());
+
+ // call image format handler based on extension
+ if(ext == "PPM" || ext == "ppm") exportPPM(name, img);
+ else if(ext == "PFM" || ext == "pfm") exportPFM(name, img);
+ else errorMessage("Unknown image format: '%s'.", ext.c_str());
+}
+
diff --git a/hw3/src/imageIO.pfm.cpp b/hw3/src/imageIO.pfm.cpp
new file mode 100644
index 0000000..85604a0
--- /dev/null
+++ b/hw3/src/imageIO.pfm.cpp
@@ -0,0 +1,87 @@
+/******************************************************************/
+/* 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 "imageIO.pfm.h"
+#include "errorMessage.h"
+
+#include <memory>
+#include <cassert>
+#include <fstream>
+
+//////////////////////
+// Helper functions //
+//////////////////////
+static void skipToNewline(std::ifstream& ifs)
+{
+ while(ifs.get() != '\n' && ifs.good());
+}
+
+static void skipComments(std::ifstream& ifs)
+{
+ while(!ifs.eof() && ifs.peek() == '#') skipToNewline(ifs);
+}
+
+
+////////////////
+// Import PFM //
+////////////////
+void importPFM(const std::string& name, image& img)
+{
+ // open file
+ std::ifstream ifs(name.c_str());
+ if(!ifs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str());
+
+ // read header
+ std::string magicMark;
+ ifs >> magicMark;
+ skipToNewline(ifs);
+ if(magicMark != "PF") errorMessage("Unsupported PFM format (%s).", magicMark.c_str());
+
+ // read width and height
+ image::size_type width, height;
+ skipComments(ifs);
+ ifs >> width >> height;
+ skipToNewline(ifs);
+
+ // allocate
+ img = image(width, height);
+
+ // check magic number (again)
+ skipComments(ifs);
+ ifs >> magicMark;
+ skipToNewline(ifs);
+ if(magicMark != "-1.000000") errorMessage("Unsupported byte-order in PFM.");
+
+ // read directly in float image
+ ifs.read((char *)(img.begin()), img.size() * sizeof(color));
+
+ // Done.
+}
+
+
+////////////////
+// Export PFM //
+////////////////
+void exportPFM(const std::string& name, const image& img)
+{
+ // sanity check
+ assert(img.width() != 0 && img.height() != 0);
+
+ // open file
+ std::ofstream ofs(name.c_str(), std::ofstream::binary);
+ if(!ofs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str());
+
+ // write header
+ ofs << "PF\n" << img.width() << " " << img.height() << "\n-1.000000\n";
+
+ // write float buffer
+ ofs.write((const char*)(img.begin()), img.size() * sizeof(color));
+
+ // Done.
+}
+
diff --git a/hw3/src/imageIO.ppm.cpp b/hw3/src/imageIO.ppm.cpp
new file mode 100644
index 0000000..8a92acb
--- /dev/null
+++ b/hw3/src/imageIO.ppm.cpp
@@ -0,0 +1,106 @@
+/******************************************************************/
+/* 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 "imageIO.ppm.h"
+#include "errorMessage.h"
+
+#include <memory>
+#include <cassert>
+#include <cstdint>
+#include <fstream>
+#include <algorithm>
+
+//////////////////////
+// Helper functions //
+//////////////////////
+static void skipToNewline(std::ifstream& ifs)
+{
+ while(ifs.get() != '\n' && ifs.good());
+}
+
+static void skipComments(std::ifstream& ifs)
+{
+ while(!ifs.eof() && ifs.peek() == '#') skipToNewline(ifs);
+}
+
+
+////////////////
+// Import PPM //
+////////////////
+void importPPM(const std::string& name, image& img)
+{
+ // open file
+ std::ifstream ifs(name.c_str());
+ if(!ifs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str());
+
+ // read header
+ std::string magicMark;
+ ifs >> magicMark;
+ skipToNewline(ifs);
+ if(magicMark != "P6") errorMessage("Unsupported PPM format (%s).", magicMark.c_str());
+
+ // read width & height
+ image::size_type width, height;
+ skipComments(ifs);
+ ifs >> width >> height;
+ skipToNewline(ifs);
+
+ // allocate
+ img = image(width, height);
+
+ // check magic number (again)
+ skipComments(ifs);
+ ifs >> magicMark;
+ skipToNewline(ifs);
+ if(magicMark != "255") errorMessage("Unsupported bit-depth in PPM file (%s).", magicMark.c_str());
+
+ // read char buffer
+ std::unique_ptr<uint8_t[]> tempBuffer(new uint8_t[img.size() * 3]);
+ ifs.read((char *)(tempBuffer.get()), img.size() * 3);
+
+ // convert to image
+ std::transform(tempBuffer.get(), tempBuffer.get() + (img.size()*3), img.begin()->begin(), [](uint8_t val)
+ {
+ return (float)(val) / 255.0f;
+ });
+
+ // Done.
+}
+
+
+////////////////
+// Export PPM //
+////////////////
+void exportPPM(const std::string& name, const image& img)
+{
+ // sanity check
+ assert(img.width() != 0 && img.height() != 0);
+
+ // open file
+ std::ofstream ofs(name.c_str(), std::ofstream::binary);
+ if(!ofs.is_open()) errorMessage("Unable to open file: '%s'.", name.c_str());
+
+ // write header
+ ofs << "P6\n" << img.width() << " " << img.height() << "\n" << "255\n";
+
+ // convert to char buffer
+ std::unique_ptr<uint8_t[]> tempBuffer(new uint8_t[img.size() * 3]);
+ std::transform(img.begin()->begin(), img.end()->begin(), tempBuffer.get(), [](float val)
+ {
+ return (val < 0.0f) ? 0 :
+ (val > 1.0f) ? 255 :
+ uint8_t(val*255);
+ });
+
+ // write body
+ ofs.write((const char*)(tempBuffer.get()), img.size() * 3);
+
+ // Done.
+}
+
+
diff --git a/hw3/src/importOBJ.cpp b/hw3/src/importOBJ.cpp
new file mode 100644
index 0000000..31df7a1
--- /dev/null
+++ b/hw3/src/importOBJ.cpp
@@ -0,0 +1,152 @@
+/******************************************************************/
+/* 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 <memory>
+#include <string>
+#include <cassert>
+#include <fstream>
+
+#include "vec3d.h"
+#include "vec2d.h"
+#include "importOBJ.h"
+#include "errorMessage.h"
+
+void importOBJ(const std::string filename, std::vector<triangle>& triangle_list)
+{
+ // define buffers
+ auto vertex_list = std::make_shared<std::vector<vec3d>>();
+ auto normal_list = std::make_shared<std::vector<vec3d>>();
+ auto textureCoord_list = std::make_shared<std::vector<vec2d>>();
+
+ // open obj file
+ std::ifstream ifs(filename);
+ if(!ifs.is_open())
+ errorMessage("Unable to import OBJ (%s).", filename.c_str());
+
+ // read line by line
+ unsigned char key;
+ while(ifs.good())
+ {
+ // get key
+ key = ifs.get();
+
+ // COMMENTS:
+ if(key == '#' || key == ' ')
+ {
+ std::string comment;
+ ifs >> comment; // comment: skip line
+ }
+
+ // VERTEX DATA:
+ else if(key == 'v')
+ {
+ // get vertex data
+ key = ifs.get();
+
+ // Vertex Coordinate
+ if(key == ' ')
+ {
+ vec3d v;
+ ifs >> v.x >> v.y >> v.z;
+ vertex_list->push_back(v);
+ }
+
+ // Texture Coordinate
+ else if(key == 't')
+ {
+ vec2d t;
+ ifs >> t.u >> t.v;
+ textureCoord_list->push_back(t);
+ }
+
+ // Normal
+ else if(key == 'n')
+ {
+ vec3d n;
+ ifs >> n.x >> n.y >> n.z;
+ normal_list->push_back(n);
+ }
+
+ // Unknown => ERROR
+ else errorMessage("Unknown OBJ vertex-key: v%c.", key);
+ }
+
+ // POLYGON:
+ else if(key == 'f')
+ {
+ // temp data structures
+ std::vector<unsigned int> vidx;
+ std::vector<unsigned int> nidx;
+ std::vector<unsigned int> tidx;
+
+
+ // get polygon data
+ // can be either:
+ // 1) v0 v1 .. vn
+ // 2) v0//n0 v1//n1 .. vn//nn
+ // 3) v0/t0 v1/t1 ... vn/tn
+ // 4) v0/t0/n0 ... vn/tn/nn
+ bool done=false;
+ while(!done)
+ {
+ // read entry
+ signed int vi, vt=-1, vn=-1;
+ ifs >> vi;
+ unsigned char c = ifs.get();
+
+ if(c == '/')
+ {
+ c = ifs.get();
+ if(c != '/') { ifs.unget(); ifs >> vt; c = ifs.get(); }
+ if(c == '/') { ifs >> vn; }
+ }
+
+ // store in polygon
+ if(vt != -1) tidx.push_back(vt-1);
+ if(vn != -1) nidx.push_back(vn-1);
+ if(vi != -1) vidx.push_back(vi-1);
+
+ // check if we did not eat the end-of-line chararters
+ ifs.unget();
+ c = ifs.get();
+ if(c == '\r' || c == '\n') done = true;
+
+ // eat remaining spaces
+ c = ifs.get();
+ while(c == ' ')
+ c = ifs.get();
+
+ // check again for end
+ if(c == '\r' || c == '\n') done = true;
+ ifs.unget();
+
+ // sanity check
+ assert(tidx.empty() || tidx.size() == vidx.size());
+ assert(nidx.empty() || nidx.size() == vidx.size());
+
+ // store triangle
+ if(vidx.size() >= 3)
+ {
+ size_t m=vidx.size() - 2;
+ size_t l=vidx.size() - 1;
+ if(tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list) );
+ if(tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
+ nidx[0], nidx[m], nidx[l], normal_list) );
+ if(!tidx.empty() && nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
+ tidx[0], tidx[m], tidx[l], textureCoord_list) );
+ if(!tidx.empty() && !nidx.empty()) triangle_list.push_back( triangle(vidx[0], vidx[m], vidx[l], vertex_list,
+ nidx[0], nidx[m], nidx[l], normal_list,
+ tidx[0], tidx[m], tidx[l], textureCoord_list) );
+ }
+ }
+ }
+ }
+
+ // Done.
+}
diff --git a/hw3/src/intersectionPoint.cpp b/hw3/src/intersectionPoint.cpp
new file mode 100644
index 0000000..5cec67a
--- /dev/null
+++ b/hw3/src/intersectionPoint.cpp
@@ -0,0 +1,309 @@
+/******************************************************************/
+/* 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 "shader_base.h"
+#include "intersectionPoint.h"
+
+/////////////////
+// Constructor //
+/////////////////
+intersectionPoint::intersectionPoint(void)
+{
+ _hit = false;
+}
+
+
+intersectionPoint::intersectionPoint(const ray& r, float rayParameter, const std::shared_ptr<const shader_base>& shader, const vec3d& normal, const vec3d& U, const vec2d& textureCoordinate)
+{
+ // copy
+ _ray = r;
+ _rayParameter = rayParameter;
+ _hit = true;
+ _shader = shader;
+ _normal = normalize(normal);
+ _U = normalize(U);
+ _textureCoordinate = textureCoordinate;
+
+ // compute position
+ _position = _ray(_rayParameter);
+}
+
+
+intersectionPoint::intersectionPoint(const intersectionPoint& ip)
+{
+ _hit = ip._hit;
+
+ // copy remainder if hit
+ if(_hit)
+ {
+ _ray = ip._ray;
+ _rayParameter = ip._rayParameter;
+ _shader = ip._shader;
+ _normal = ip._normal;
+ _position = ip._position;
+ _U = ip._U;
+ _textureCoordinate = ip._textureCoordinate;
+ }
+ else _shader = nullptr;
+}
+
+///////////////
+// Operators //
+///////////////
+intersectionPoint& intersectionPoint::operator=(const intersectionPoint& ip)
+{
+ _assign(ip);
+ return *this;
+}
+
+
+bool intersectionPoint::operator<(const intersectionPoint& ip) const
+{
+ // handle case where either one of the intersectionPoints is not a hit
+ // => assume no-hit equals a hit at infinity
+ if(!_hit) return false;
+ if(!ip._hit) return true;
+
+ // decide based on rayParameter
+ return _rayParameter < ip._rayParameter;
+}
+
+
+bool intersectionPoint::operator>(const intersectionPoint& ip) const
+{
+ // handle case where either one of the intersectionPoints is not a hit
+ // => assume no-hit equals a hit at infinity
+ if(!_hit) return true;
+ if(!ip._hit) return false;
+
+ // decide based on rayParameter
+ return _rayParameter > ip._rayParameter;
+}
+
+
+bool intersectionPoint::operator<(const lightSample& ls) const
+{
+ // handle case where this is not a hit
+ if(!_hit) return false;
+
+ // decide based on rayParameter
+ return _rayParameter < ls.distance();
+}
+
+
+bool intersectionPoint::operator>(const lightSample& ls) const
+{
+ // handle case where this is not a hit
+ if(!_hit) return true;
+
+ // decide based on rayParameter
+ return _rayParameter > ls.distance();
+}
+
+////////////////
+// Inspectors //
+////////////////
+bool intersectionPoint::isHit(void) const
+{
+ return _hit;
+}
+
+
+shaderProperties intersectionPoint::getShaderProperties(void) const
+{
+ assert(hasShader());
+ return _shader->properties(*this);
+}
+
+
+bool intersectionPoint::hasShader(void) const
+{
+ return (_shader != nullptr);
+}
+
+
+float intersectionPoint::distance(const intersectionPoint& ip) const
+{
+ // set distance to infinity of one of the two points is not a hit
+ if(!_hit || !ip._hit) return +LARGE;
+
+ // compute distance
+ return _position.distance(ip._position);
+}
+
+
+const vec3d& intersectionPoint::position(void) const
+{
+ return _position;
+}
+
+
+const vec3d& intersectionPoint::direction(void) const
+{
+ return _ray.direction();
+}
+
+
+const vec2d& intersectionPoint::textureCoordinate(void) const
+{
+ return _textureCoordinate;
+}
+
+
+const vec3d& intersectionPoint::normal(void) const
+{
+ return _normal;
+}
+
+
+coordinateTransformation intersectionPoint::shadingFrame(void) const
+{
+ // transform => to global shading frame
+ // inverseTransform => to local shading frame
+ return coordinateTransformation(_normal, _U);
+}
+
+
+//////////////
+// Mutators //
+//////////////
+void intersectionPoint::transform(const transformation3d& t)
+{
+ // sanity check
+ if(!_hit) return;
+
+ /// transform
+ _ray.transform(t);
+ _position = t.transformPoint(_position);
+ _normal = t.transformNormal(_normal);
+ _U = t.transformNormal(_U);
+
+ // recompute the ray parameter (to account for potential scaling)
+ _rayParameter = _ray(_position);
+}
+
+
+void intersectionPoint::inverseTransform(const transformation3d& t)
+{
+ // sanity check
+ if(!_hit) return;
+
+ // inverse transform
+ _ray.inverseTransform(t);
+ _position = t.inverseTransformPoint(_position);
+ _normal = t.inverseTransformNormal(_normal);
+ _U = t.inverseTransformNormal(_U);
+
+ // recompute the ray parameter (to account for potential scaling)
+ _rayParameter = _ray(_position);
+}
+
+
+void intersectionPoint::transformShadingFrame(const transformation3d& sft)
+{
+ // sanity check
+ if(!_hit) return;
+
+ // Note: shading frame transformation are defined
+ // with respect to the local shading frame (i.e., N=Z, U=X)
+ transformation3d t = shadingFrame();
+
+ // transform
+ _normal = t.transformNormal( sft.transformNormal(vec3d(0.0f, 0.0f, 1.0f)) );
+ _U = t.transformNormal( sft.transformNormal(vec3d(1.0f, 0.0f, 0.0f)) );
+
+ // Done.
+}
+
+
+void intersectionPoint::inverseTransformShadingFrame(const transformation3d& sft)
+{
+ // sanity check
+ if(!_hit) return;
+
+ // Note: shading frame transformation are defined
+ // with respect to the local shading frame (i.e., N=Z, U=X)
+ // Note: this transformation will not undo the effects of
+ // transformShadingFrame since the local shading frame
+ // is altered by the transformation (and thus the frame
+ // with respect to which the inverseTransformation is
+ // applied)
+ transformation3d t = shadingFrame();
+
+ // transform
+ _normal = t.transformNormal( sft.inverseTransformNormal(vec3d(0.0f, 0.0f, 1.0f)) );
+ _U = t.transformNormal( sft.inverseTransformNormal(vec3d(1.0f, 0.0f, 0.0f)) );
+
+ // Done.
+}
+
+
+void intersectionPoint::setShader(const std::shared_ptr<const class shader_base>& shader)
+{
+ _shader = shader;
+}
+
+
+/////////////
+// Methods //
+/////////////
+color intersectionPoint::shade(const vec3d& out) const
+{
+ assert(hasShader());
+ if(!_hit) return color(0.0f);
+ return _shader->shade(*this, out);
+}
+
+color intersectionPoint::shade(const lightSample& ls) const
+{
+ // HW3: Implement this.
+ // Returns the color of shading the intersectionPoint with the light source ls.
+ // Returns: shaded color
+ // Modifies: nothing.
+ assert(_shader);
+ if (!_hit) { return color(0.0f); }
+ return _shader->shade(*this, ls.directionToLight()) * ls.emittance();
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void intersectionPoint::_assign(const intersectionPoint& ip)
+{
+ // sanity check
+ if(&ip == this) return;
+
+ // copy if hit
+ _hit = ip._hit;
+ if(_hit)
+ {
+ _ray = ip._ray;
+ _rayParameter = ip._rayParameter;
+ _position = ip._position;
+ _normal = ip._normal;
+ _U = ip._U;
+ _textureCoordinate = ip._textureCoordinate;
+ _shader = ip._shader;
+ }
+ else _shader = nullptr;
+}
+
+
+void intersectionPoint::_swap(intersectionPoint& ip)
+{
+ swap(_ray, ip._ray);
+ std::swap(_hit, ip._hit);
+ std::swap(_rayParameter, ip._rayParameter);
+ swap(_position, ip._position);
+ swap(_normal, ip._normal);
+ swap(_U, ip._U);
+ swap(_textureCoordinate, ip._textureCoordinate);
+ std::swap(_shader, ip._shader);
+}
diff --git a/hw3/src/interval.cpp b/hw3/src/interval.cpp
new file mode 100644
index 0000000..4323cbd
--- /dev/null
+++ b/hw3/src/interval.cpp
@@ -0,0 +1,154 @@
+/******************************************************************/
+/* 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 "interval.h"
+#include "constants.h"
+
+//////////////////
+// Constrructor //
+//////////////////
+interval::interval(float lower, float upper)
+{
+ _lower = lower;
+ _upper = upper;
+
+ // ensure that _lower < _upper
+ if(_upper < _lower) std::swap(_upper, _lower);
+}
+
+
+interval::interval(const interval& i)
+{
+ _lower = i._lower;
+ _upper = i._upper;
+}
+
+
+
+///////////////
+// Operators //
+///////////////
+interval& interval::operator=(const interval& i)
+{
+ _assign(i);
+ return *this;
+}
+
+
+interval interval::operator+(float v) const
+{
+ return interval(_lower + v, _upper + v);
+}
+
+
+interval interval::operator-(float v) const
+{
+ return interval(_lower - v, _upper - v);
+}
+
+
+interval interval::operator*(float v) const
+{
+ return interval(_lower * v, _upper * v);
+}
+
+
+interval interval::operator/(float v) const
+{
+ return interval(_lower / v, _upper / v);
+}
+
+
+interval& interval::operator+=(float v)
+{
+ _lower += v;
+ _upper += v;
+ return *this;
+}
+
+interval& interval::operator-=(float v)
+{
+ _lower -= v;
+ _upper -= v;
+ return *this;
+}
+
+
+interval& interval::operator*=(float v)
+{
+ _lower *= v;
+ _upper *= v;
+
+ // ensure that _lower < _upper
+ if(_upper < _lower) std::swap(_upper, _lower);
+
+ // Done.
+ return *this;
+}
+
+interval& interval::operator/=(float v)
+{
+ _lower /= v;
+ _upper /= v;
+
+ // ensure that _lower < _upper
+ if(_upper < _lower) std::swap(_upper, _lower);
+
+ // Done.
+ return *this;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+float interval::lower(void) const
+{
+ return _lower;
+}
+
+
+float interval::upper(void) const
+{
+ return _upper;
+}
+
+
+bool interval::empty(void) const
+{
+ return (_upper - _lower < EPSILON);
+}
+
+
+
+//////////////
+// Mutators //
+//////////////
+void interval::intersect(const interval& i)
+{
+ _lower = std::max(_lower, i._lower);
+ _upper = std::min(_upper, i._upper);
+}
+
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void interval::_assign(const interval& i)
+{
+ _lower = i._lower;
+ _upper = i._upper;
+}
+
+
+void interval::_swap(interval& i)
+{
+ std::swap(_lower, i._lower);
+ std::swap(_upper, i._upper);
+}
diff --git a/hw3/src/lightSample.cpp b/hw3/src/lightSample.cpp
new file mode 100644
index 0000000..5304a9d
--- /dev/null
+++ b/hw3/src/lightSample.cpp
@@ -0,0 +1,121 @@
+/******************************************************************/
+/* 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 <cmath>
+#include "lightSample.h"
+
+
+//////////////////
+// Constructors //
+//////////////////
+lightSample::lightSample(const vec3d& direction,
+ const color& emittance,
+ float distance,
+ float pdf,
+ float foreshortening)
+{
+ float length = direction.length();
+ _direction = (length < EPSILON) ? vec3d(0.0f, 0.0f, 0.0f) : direction / length;
+ _emittance = emittance;
+ _distance = distance;
+ _pdf = std::max(pdf, 0.0f);
+ _foreshortening = std::max(foreshortening, 0.0f);
+}
+
+
+lightSample::lightSample(const lightSample& ls)
+{
+ _direction = ls._direction;
+ _emittance = ls._emittance;
+ _distance = ls._distance;
+ _pdf = ls._pdf;
+ _foreshortening = ls._foreshortening;
+}
+
+
+///////////////
+// Operators //
+///////////////
+lightSample& lightSample::operator=(const lightSample& ls)
+{
+ _assign(ls);
+ return(*this);
+}
+
+
+const color& lightSample::operator()(void) const
+{
+ return _emittance;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+const vec3d& lightSample::directionToPoint(void) const
+{
+ return _direction;
+}
+
+
+vec3d lightSample::directionToLight(void) const
+{
+ return -_direction;
+}
+
+
+const color& lightSample::emittance(void) const
+{
+ return _emittance;
+}
+
+
+float lightSample::distance(void) const
+{
+ return _distance;
+}
+
+
+float lightSample::pdf(void) const
+{
+ return _pdf;
+}
+
+
+float lightSample::foreshortening(void) const
+{
+ return _foreshortening;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void lightSample::_assign(const lightSample& ls)
+{
+ // sanity check
+ if(&ls == this) return;
+
+ // copy
+ _direction = ls._direction;
+ _emittance = ls._emittance;
+ _distance = ls._distance;
+ _pdf = ls._pdf;
+ _foreshortening = ls._foreshortening;
+}
+
+
+void lightSample::_swap(lightSample& ls)
+{
+ swap(_direction, ls._direction);
+ swap(_emittance, ls._emittance);
+ std::swap(_distance, ls._distance);
+ std::swap(_pdf, ls._pdf);
+ std::swap(_foreshortening, ls._foreshortening);
+}
+
diff --git a/hw3/src/linear_intersector.cpp b/hw3/src/linear_intersector.cpp
new file mode 100644
index 0000000..aa0d767
--- /dev/null
+++ b/hw3/src/linear_intersector.cpp
@@ -0,0 +1,49 @@
+/******************************************************************/
+/* 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 "linear_intersector.h"
+
+//////////////////
+// Constructors //
+//////////////////
+linear_intersector::linear_intersector(void)
+ : intersector_base()
+{
+ // Do nothing
+}
+
+
+linear_intersector::linear_intersector(const std::vector<std::shared_ptr<const boundedPrimitive>>& compounds)
+ : intersector_base()
+{
+ _compounds = compounds;
+}
+
+
+/////////////
+// Methods //
+/////////////
+intersectionPoint linear_intersector::intersect(const ray& r) const
+{
+ // HW3: Implement this.
+ // Returns the nearest intersections point of the ray 'r' with the primitives in '_compounds'.
+ // Returns: intersection point
+ // Modifies: nothing
+ intersectionPoint ip, current;
+
+ for (auto itr = _compounds.begin(); itr != _compounds.end(); itr++) {
+
+ if ((*itr)->hasShader()) {
+ current = (*itr)->intersect(r);
+ if (current < ip) { ip = current; }
+ }
+
+ }
+
+ return ip;
+}
diff --git a/hw3/src/mat3d.cpp b/hw3/src/mat3d.cpp
new file mode 100644
index 0000000..7674777
--- /dev/null
+++ b/hw3/src/mat3d.cpp
@@ -0,0 +1,260 @@
+/******************************************************************/
+/* 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 <algorithm>
+
+#include "mat3d.h"
+
+
+/////////////////
+// Constructor //
+/////////////////
+mat3d::mat3d(void)
+{
+ clear(0.0f);
+}
+
+
+mat3d::mat3d(mat3d::value_type diag)
+ : mat3d()
+{
+ setDiagonal(diag);
+}
+
+
+mat3d::mat3d(const vec3d& X, const vec3d& Y, const vec3d& Z)
+{
+ for(size_type i=0; i < 3; i++)
+ {
+ this->operator()(i,0) = X[i];
+ this->operator()(i,1) = Y[i];
+ this->operator()(i,2) = Z[i];
+ }
+}
+
+
+mat3d::mat3d(const mat3d& m)
+{
+ _data = m._data;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+mat3d::iterator mat3d::begin(void)
+{
+ return _data.begin();
+}
+
+
+mat3d::const_iterator mat3d::begin(void) const
+{
+ return _data.begin();
+}
+
+
+mat3d::iterator mat3d::end(void)
+{
+ return _data.end();
+}
+
+
+mat3d::const_iterator mat3d::end(void) const
+{
+ return _data.end();
+}
+
+
+//////////////
+// Mutators //
+//////////////
+void mat3d::clear(mat3d::value_type value)
+{
+ std::fill(begin(), end(), value);
+}
+
+
+void mat3d::setDiagonal(mat3d::value_type value)
+{
+ (*this)(0,0) = (*this)(1,1) = (*this)(2,2) = value;
+}
+
+
+mat3d& mat3d::transpose(void)
+{
+ for(size_type row=0; row < height(); row++)
+ for(size_type column=row+1; column < width(); column++)
+ std::swap( (*this)(row,column), (*this)(column,row) );
+ return *this;
+}
+
+
+
+///////////////
+// Operators //
+///////////////
+mat3d& mat3d::operator=(const mat3d& m)
+{
+ _assign(m);
+ return *this;
+}
+
+
+mat3d::reference mat3d::operator()(mat3d::size_type row, mat3d::size_type col)
+{
+ assert(row < height() && col < width());
+ return _data[ row*width() + col];
+}
+
+
+mat3d::const_reference mat3d::operator()(mat3d::size_type row, mat3d::size_type col) const
+{
+ assert(row < height() && col < width());
+ return _data[ row*width() + col];
+}
+
+
+mat3d mat3d::operator+(const mat3d& m) const
+{
+ mat3d result;
+ std::transform(begin(), end(), m.begin(), result.begin(), [](const_reference a, const_reference b)
+ {
+ return a+b;
+ });
+ return result;
+}
+
+
+mat3d mat3d::operator-(const mat3d& m) const
+{
+ mat3d result;
+ std::transform(begin(), end(), m.begin(), result.begin(), [](const_reference a, const_reference b)
+ {
+ return a-b;
+ });
+ return result;
+}
+
+
+mat3d mat3d::operator*(const mat3d& m) const
+{
+ mat3d result;
+ for(size_type i=0; i < result.height(); i++)
+ for(size_type j=0; j < result.width(); j++)
+ for(size_type k=0; k < width(); k++)
+ result(i,j) += (*this)(i,k) * m(k, j);
+ return result;
+}
+
+
+vec3d mat3d::operator*(const vec3d& v) const
+{
+ vec3d result;
+ for(size_type i=0; i < height(); i++)
+ for(size_type j=0; j < width(); j++)
+ result[i] += v[j] * (*this)(i,j);
+ return result;
+}
+
+
+mat3d mat3d::operator*(mat3d::value_type scale) const
+{
+ mat3d result;
+ std::transform(begin(), end(), result.begin(), [&](const_reference v)
+ {
+ return v * scale;
+ });
+ return result;
+}
+
+mat3d mat3d::operator/(mat3d::value_type scale) const
+{
+ mat3d result;
+ std::transform(begin(), end(), result.begin(), [&](const_reference v)
+ {
+ return v / scale;
+ });
+ return result;
+}
+
+
+mat3d& mat3d::operator+=(const mat3d& m)
+{
+ std::transform(begin(), end(), m.begin(), begin(), [](const_reference a, const_reference b)
+ {
+ return a+b;
+ });
+ return *this;
+}
+
+
+mat3d& mat3d::operator-=(const mat3d& m)
+{
+ std::transform(begin(), end(), m.begin(), begin(), [](const_reference a, const_reference b)
+ {
+ return a-b;
+ });
+ return *this;
+}
+
+
+mat3d& mat3d::operator*=(const mat3d& m)
+{
+ *this = *this * m;
+ return *this;
+}
+
+
+mat3d& mat3d::operator*=(mat3d::value_type scale)
+{
+ std::for_each(begin(), end(), [&](reference v)
+ {
+ v *= scale;
+ });
+ return *this;
+}
+
+
+mat3d& mat3d::operator/=(mat3d::value_type scale)
+{
+ std::for_each(begin(), end(), [&](reference v)
+ {
+ v /= scale;
+ });
+ return *this;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void mat3d::_swap(mat3d& m)
+{
+ if(&m == this) return;
+ std::swap(_data, m._data);
+}
+
+
+void mat3d::_assign(const mat3d& m)
+{
+ if(&m == this) return;
+ _data = m._data;
+}
+
+
+vec3d mat3d::_premultiply(const vec3d& v) const
+{
+ // result = v * *this
+ vec3d result;
+ for(size_type i=0; i < height(); i++)
+ for(size_type j=0; j < width(); j++)
+ result[j] += v[i] * (*this)(i,j);
+ return result;
+}
diff --git a/hw3/src/phongBrdf.cpp b/hw3/src/phongBrdf.cpp
new file mode 100644
index 0000000..40f730a
--- /dev/null
+++ b/hw3/src/phongBrdf.cpp
@@ -0,0 +1,99 @@
+/******************************************************************/
+/* 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 <cmath>
+#include "constants.h"
+#include "phongBrdf.h"
+
+//////////////////
+// Constructors //
+//////////////////
+phongBrdf::phongBrdf(const color& albedo, float sharpness)
+{
+ _albedo = albedo;
+ _sharpness = sharpness;
+}
+
+
+phongBrdf::phongBrdf(const phongBrdf& src)
+{
+ _albedo = src._albedo;
+ _sharpness = src._sharpness;
+}
+
+
+///////////////
+// Operators //
+///////////////
+phongBrdf& phongBrdf::operator=(const phongBrdf& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+/////////////
+// Methods //
+/////////////
+color phongBrdf::shade(const vec3d& in, const vec3d& out) const
+{
+ // HW3: Implement this.
+ // Returns the phong shaded color from a specular surface for an
+ // incident lighting direction of 'in', and view direction of 'out'.
+ // The surface normal = (0,0,1).
+ // Returns: shaded color
+ // Modifies: nothing.
+ if (out.z < EPSILON) { return color(0.0f); }
+
+ vec3d normal, r;
+ float r_dot_out;
+
+ normal = vec3d(0, 0, 1);
+ r = (2 * normal.dot(in) * normal) - in;
+ r_dot_out = r.dot(out);
+ if (r_dot_out < EPSILON) { return color(0.0f); }
+ else if (r_dot_out > EPSILON + 1) { r_dot_out = 1; }
+ return color(_albedo * pow(r_dot_out, _sharpness));
+}
+
+
+bool phongBrdf::isSpecular(void) const
+{
+ // Consider low roughness to be diffuse.
+ // Use 5.0f as an arbitrary threshold.
+ return (_sharpness > 5.0f);
+}
+
+
+bool phongBrdf::isDiffuse(void) const
+{
+ return !isSpecular();
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void phongBrdf::_assign(const phongBrdf& src)
+{
+ _albedo = src._albedo;
+ _sharpness = src._sharpness;
+}
+
+
+void phongBrdf::_swap(phongBrdf& src)
+{
+ swap(_albedo, src._albedo);
+ std::swap(_sharpness, src._sharpness);
+}
+
+
+void phongBrdf::_print(std::ostream& s) const
+{
+ s << "Phong BRDF: albedo=" << _albedo << ", sharpness=" << _sharpness;
+}
diff --git a/hw3/src/phongReflectanceShader.cpp b/hw3/src/phongReflectanceShader.cpp
new file mode 100644
index 0000000..c5ac57c
--- /dev/null
+++ b/hw3/src/phongReflectanceShader.cpp
@@ -0,0 +1,36 @@
+/******************************************************************/
+/* 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 "phongReflectanceShader.h"
+
+
+/////////////////
+// Constructor //
+/////////////////
+phongReflectanceShader::phongReflectanceShader(const colorReflectanceParameter& albedo, const scalarReflectanceParameter& sharpness)
+ : reflectanceShader_base()
+{
+ _albedo = albedo;
+ _sharpness = sharpness;
+}
+
+
+///////////////////////
+// Protected Methods //
+///////////////////////
+std::unique_ptr<const brdf_base> phongReflectanceShader::make_brdf(const vec2d& textureCoord) const
+{
+ return std::unique_ptr<const brdf_base>(new phongBrdf( _albedo(textureCoord), _sharpness(textureCoord) ));
+}
+
+
+void phongReflectanceShader::_print(std::ostream& s) const
+{
+ s << "Phong Reflectance: albedo=" << _albedo << ", sharpness=" << _sharpness;
+}
diff --git a/hw3/src/ray.cpp b/hw3/src/ray.cpp
new file mode 100644
index 0000000..18c839d
--- /dev/null
+++ b/hw3/src/ray.cpp
@@ -0,0 +1,83 @@
+/******************************************************************/
+/* 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 "ray.h"
+
+//////////////////
+// Constructors //
+//////////////////
+ray::ray(const vec3d& origin, const vec3d& direction)
+{
+ _origin = origin;
+ _direction = normalize(direction);
+}
+
+ray::ray(const ray& r)
+{
+ _origin = r._origin;
+ _direction = r._direction;
+}
+
+
+///////////////
+// Operators //
+///////////////
+ray& ray::operator=(const ray& r)
+{
+ _assign(r);
+ return *this;
+}
+
+
+vec3d ray::operator()(float t) const
+{
+ return _origin + t*_direction;
+}
+
+
+float ray::operator()(const vec3d& point) const
+{
+ return _direction.dot(point - _origin);
+}
+
+
+//////////////
+// Mutators //
+//////////////
+ray& ray::transform(const transformation3d& t)
+{
+ _origin = t.transformPoint(_origin);
+ _direction = t.transformDirection(_direction);
+ return *this;
+}
+
+
+ray& ray::inverseTransform(const transformation3d& t)
+{
+ _origin = t.inverseTransformPoint(_origin);
+ _direction = t.inverseTransformDirection(_direction);
+ return *this;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void ray::_swap(ray& r)
+{
+ swap(_origin, r._origin);
+ swap(_direction, r._direction);
+}
+
+
+void ray::_assign(const ray& r)
+{
+ _origin = r._origin;
+ _direction = r._direction;
+}
diff --git a/hw3/src/reflectanceParameter.cpp b/hw3/src/reflectanceParameter.cpp
new file mode 100644
index 0000000..5b918fb
--- /dev/null
+++ b/hw3/src/reflectanceParameter.cpp
@@ -0,0 +1,140 @@
+/******************************************************************/
+/* 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 "reflectanceParameter.h"
+
+/******************************/
+/* scalarReflectanceParameter */
+/******************************/
+
+/////////////////
+// Constructor //
+/////////////////
+scalarReflectanceParameter::scalarReflectanceParameter(float value)
+{
+ _value = value;
+ _texture = nullptr;
+ _channel = 0.0f;
+}
+
+
+scalarReflectanceParameter::scalarReflectanceParameter(const std::shared_ptr<const texture_base>& texture, unsigned int channel)
+{
+ _value = 0.0f;
+ _texture = texture;
+ _channel = channel;
+}
+
+
+scalarReflectanceParameter::scalarReflectanceParameter(const scalarReflectanceParameter& src)
+{
+ _value = src._value;
+ _texture = src._texture;
+ _channel = src._channel;
+}
+
+
+//////////////
+// Operator //
+//////////////
+scalarReflectanceParameter& scalarReflectanceParameter::operator=(const scalarReflectanceParameter& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+float scalarReflectanceParameter::operator()(const vec2d& textureCoord) const
+{
+ if(_texture) return (*_texture)(textureCoord)[_channel];
+ else return _value;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void scalarReflectanceParameter::_assign(const scalarReflectanceParameter& src)
+{
+ _value = src._value;
+ _texture = src._texture;
+ _channel = src._channel;
+}
+
+
+void scalarReflectanceParameter::_swap(scalarReflectanceParameter& swp)
+{
+ std::swap(_value, swp._value);
+ std::swap(_texture, swp._texture);
+ std::swap(_channel, swp._channel);
+}
+
+
+
+/*****************************/
+/* colorReflectanceParameter */
+/*****************************/
+
+/////////////////
+// Constructor //
+/////////////////
+colorReflectanceParameter::colorReflectanceParameter(color value)
+{
+ _value = value;
+ _texture = nullptr;
+}
+
+
+colorReflectanceParameter::colorReflectanceParameter(const std::shared_ptr<const texture_base>& texture)
+{
+ _value = color(0.0f);
+ _texture = texture;
+}
+
+
+colorReflectanceParameter::colorReflectanceParameter(const colorReflectanceParameter& src)
+{
+ _value = src._value;
+ _texture = src._texture;
+}
+
+
+//////////////
+// Operator //
+//////////////
+colorReflectanceParameter& colorReflectanceParameter::operator=(const colorReflectanceParameter& src)
+{
+ _assign(src);
+ return *this;
+}
+
+
+color colorReflectanceParameter::operator()(const vec2d& textureCoord) const
+{
+ if(_texture) return (*_texture)(textureCoord);
+ else return _value;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void colorReflectanceParameter::_assign(const colorReflectanceParameter& src)
+{
+ _value = src._value;
+ _texture = src._texture;
+}
+
+
+void colorReflectanceParameter::_swap(colorReflectanceParameter& swp)
+{
+ std::swap(_value, swp._value);
+ std::swap(_texture, swp._texture);
+}
+
+
diff --git a/hw3/src/reflectanceShader_base.cpp b/hw3/src/reflectanceShader_base.cpp
new file mode 100644
index 0000000..8ff81fc
--- /dev/null
+++ b/hw3/src/reflectanceShader_base.cpp
@@ -0,0 +1,39 @@
+/******************************************************************/
+/* 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 "reflectanceShader_base.h"
+#include "coordinateTransform.h"
+
+/////////////
+// Methods //
+/////////////
+color reflectanceShader_base::shade(const intersectionPoint& ip, const vec3d& light_dir) const
+{
+ // create shading frame (note: in and out point away!)
+ coordinateTransformation ct = ip.shadingFrame();
+ vec3d local_out = ct.inverseTransformDirection(-ip.direction());
+ vec3d local_in = ct.inverseTransformDirection(light_dir);
+
+ // get brdf
+ std::unique_ptr<const brdf_base> brdf = make_brdf(ip.textureCoordinate());
+
+ // eval
+ return brdf->shade(local_in, local_out);
+}
+
+
+shaderProperties reflectanceShader_base::properties(const intersectionPoint& ip) const
+{
+ // get brdf
+ std::unique_ptr<const brdf_base> brdf = make_brdf(ip.textureCoordinate());
+
+ // get properties
+ return shaderProperties(brdf->isDiffuse(), brdf->isSpecular());
+}
+
+
diff --git a/hw3/src/scene.cpp b/hw3/src/scene.cpp
new file mode 100644
index 0000000..4491c03
--- /dev/null
+++ b/hw3/src/scene.cpp
@@ -0,0 +1,42 @@
+/******************************************************************/
+/* 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 "scene.h"
+
+////////////////
+// Inspectors //
+////////////////
+const camera& scene::getCamera(void) const
+{
+ return _camera;
+}
+
+
+const lightsource_base& scene::getLightsource(size_t idx) const
+{
+ assert(idx < _lightsources.size());
+ return *(_lightsources[idx]);
+}
+
+
+size_t scene::numberOfLightsources(void) const
+{
+ return _lightsources.size();
+}
+
+
+/////////////
+// Methods //
+/////////////
+intersectionPoint scene::intersect(const ray& r) const
+{
+ return _sceneGraphRoot->intersect(r);
+}
+
+
diff --git a/hw3/src/sceneGraphNode.cpp b/hw3/src/sceneGraphNode.cpp
new file mode 100644
index 0000000..1a0f600
--- /dev/null
+++ b/hw3/src/sceneGraphNode.cpp
@@ -0,0 +1,39 @@
+/******************************************************************/
+/* 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 <algorithm>
+#include "sceneGraphNode.h"
+
+//////////////////
+// Constructors //
+//////////////////
+sceneGraphNode::sceneGraphNode(void)
+ : boundedCompound()
+{
+ // Do nothing
+}
+
+sceneGraphNode::sceneGraphNode(const std::vector<std::shared_ptr<const boundedPrimitive>>& nodes, const transformation3d& transform, const std::shared_ptr<const shader_base>& shader)
+ : boundedCompound(transform, shader)
+{
+ // copy nodes
+ _nodes = nodes;
+
+ // init bounding box
+ initializeBoundingBox();
+}
+
+
+/////////////
+// Methods //
+/////////////
+const std::vector<std::shared_ptr<const boundedPrimitive>>& sceneGraphNode::compounds(void) const
+{
+ return _nodes;
+}
+
diff --git a/hw3/src/sceneIO.cpp b/hw3/src/sceneIO.cpp
new file mode 100644
index 0000000..bffff8e
--- /dev/null
+++ b/hw3/src/sceneIO.cpp
@@ -0,0 +1,87 @@
+/******************************************************************/
+/* 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 "util.h"
+#include "scene.h"
+#include "sceneGraphNode.h"
+#include "linear_intersector.h"
+
+#include "sceneIO_xml.h"
+#include "sceneIO_core.h"
+#include "sceneIO_cache.h"
+#include "sceneIO_basis.h"
+#include "sceneIO_light.h"
+#include "sceneIO_geometry.h"
+#include "sceneIO_material.h"
+
+
+void importScene(const std::string& filename, scene& s)
+{
+ // get root
+ std::string rootDir = getDirectory(filename);
+
+ // open xml
+ XMLNode sceneNode(filename);
+
+ // check if valid scene node
+ if(!sceneNode.isValid())
+ errorMessage("Failed to find 'scene' in %s.", filename.c_str());
+
+ // create sceneGraphNode, texture, and shader cache
+ nodeCache<boundedPrimitive> shape_cache;
+ nodeCache<shader_base> shader_cache;
+ nodeCache<texture_base> texture_cache;
+
+ // init scene data
+ bool autoTuneCamera = false;
+ std::unique_ptr<const intersector_factory_base> intersector(new linear_intersector_factory());
+
+ // process sceneNode
+ for(XMLNode node = sceneNode.firstChild(); node.isValid(); node++)
+ {
+ // check for general node-types
+ if(importMaterial(node, shader_cache, texture_cache, rootDir)) continue;
+ if(importGeometry(node, shape_cache, shader_cache, texture_cache, rootDir)) continue;
+
+ // check for scene-root specific nodes
+ std::string nodeName = node.name();
+ if(nodeName == "camera") autoTuneCamera = importCamera(node, s._camera);
+ else if(nodeName == "light") s._lightsources.push_back( importLight(node, shape_cache, shader_cache, texture_cache, rootDir) );
+ else if(nodeName == "intersector") importIntersector(node, intersector);
+ else errorMessage("Unknown node in scene xml: '%s'", nodeName.c_str());
+ }
+
+ // initialize all node's intersectors
+ auto nodeList = shape_cache.allNodes();
+ for(auto itr=nodeList.begin(); itr != nodeList.end(); itr++)
+ static_cast<boundedCompound*>(itr->get())->initialize(*intersector);
+ nodeList.clear();
+
+ // add all unreferences nodes to the _sceneGraphRoot.
+ // Note: remove any node without a shader
+ decltype(nodeList) unusedNodes;
+ nodeList = shape_cache.unusedNodes();
+ while(!nodeList.empty())
+ {
+ auto bck = nodeList.back();
+ if(bck->hasShader()) unusedNodes.push_back(bck);
+ nodeList.pop_back();
+ }
+
+ // -> init + add
+ std::unique_ptr<boundedCompound> root(new sceneGraphNode( *(reinterpret_cast< std::vector<std::shared_ptr<const boundedPrimitive>>* >(&unusedNodes)) ));
+ root->initialize(*intersector);
+ s._sceneGraphRoot = std::unique_ptr<const boundedCompound>(root.release());
+
+ // Auto Tune Camera is requested
+ if(autoTuneCamera)
+ s._camera.frameBoundingBox( s._sceneGraphRoot->boundingbox() );
+
+ // Done.
+}
+
diff --git a/hw3/src/sceneIO_basis.cpp b/hw3/src/sceneIO_basis.cpp
new file mode 100644
index 0000000..9149ba2
--- /dev/null
+++ b/hw3/src/sceneIO_basis.cpp
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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 "errorMessage.h"
+#include "sceneIO_core.h"
+#include "sceneIO_basis.h"
+#include "sceneIO_cache.h"
+
+#include "linear_intersector.h"
+
+bool importCamera(const XMLNode& node, camera& cam)
+{
+ // sanity check
+ assert(node.name() == "camera");
+
+ // import camera
+ cam = camera( getVec3d(node, "eye", vec3d(0.0f, 0.0f, 0.0f)),
+ getVec3d(node, "view", vec3d(0.0f, 0.0f, -1.0f)),
+ getVec3d(node, "up", vec3d(0.0f, 1.0f, 0.0f)),
+ getFloat(node, "fov", 60),
+ getInteger(node, "width", 256),
+ getInteger(node, "height", 256) );
+
+ // Done.
+ return( getString(node, "auto", "false") == "true");
+}
+
+
+void importIntersector(const XMLNode& node, std::unique_ptr<const intersector_factory_base>& intersector)
+{
+ // sanity check
+ assert(node.name() == "intersector");
+
+ // get intersector type
+ std::string type = getString(node, "type", "linear");
+
+ // create intersector
+ if(type == "linear") intersector = std::unique_ptr<const intersector_factory_base>( new linear_intersector_factory());
+ else errorMessage("Unknown intersector type (%s)", type.c_str());
+
+ // Done.
+}
+
+
diff --git a/hw3/src/sceneIO_core.cpp b/hw3/src/sceneIO_core.cpp
new file mode 100644
index 0000000..123287e
--- /dev/null
+++ b/hw3/src/sceneIO_core.cpp
@@ -0,0 +1,99 @@
+/******************************************************************/
+/* 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 <string>
+#include <cstdlib>
+
+#include "sceneIO_core.h"
+#include "errorMessage.h"
+
+color getColor(const XMLNode& node, const std::string& name, const color& default_value)
+{
+ std::string value = node.attribute(name);
+
+ // if defined, process..
+ if(value != "")
+ {
+ color result;
+ int s = sscanf(value.c_str(), "%f %f %f", &result.r, &result.g, &result.b);
+
+ // check if only 1 value is given or 3.
+ if(s == 1) return color(result.r, result.r, result.r);
+ else if(s == 3) return result;
+ else errorMessage("Failed to parse color value (%s)", value.c_str());
+ }
+
+ // else return default
+ return default_value;
+}
+
+
+vec3d getVec3d(const XMLNode& node, const std::string& name, const vec3d& default_value)
+{
+ std::string value = node.attribute(name);
+
+ // if defined, process..
+ if(value != "")
+ {
+ vec3d result;
+ int s = sscanf(value.c_str(), "%f %f %f", &result.x, &result.y, &result.z);
+
+ // check if only 1 value is given or 3.
+ if(s == 1) return vec3d(result.x, result.x, result.x);
+ else if(s == 3) return result;
+ else errorMessage("Failed to parse vec3d value (%s)", value.c_str());
+ }
+
+ // else return default
+ return default_value;
+}
+
+
+vec2d getVec2d(const XMLNode& node, const std::string& name, const vec2d& default_value)
+{
+ std::string value = node.attribute(name);
+
+ // if defined, process..
+ if(value != "")
+ {
+ vec2d result;
+ int s = sscanf(value.c_str(), "%f %f", &result.x, &result.y);
+
+ // check if only 1 value is given or 2.
+ if(s == 1) return vec2d(result.x, result.x);
+ else if(s == 2) return result;
+ else errorMessage("Failed to parse vec2d value (%s)", value.c_str());
+ }
+
+ // else returnd default
+ return default_value;
+}
+
+
+std::string getString(const XMLNode& node, const std::string& name, const std::string& default_value)
+{
+ std::string value = node.attribute(name);
+ if(value != "") return std::string(value);
+ else return default_value;
+}
+
+
+float getFloat(const XMLNode& node, const std::string& name, float default_value)
+{
+ std::string value = node.attribute(name);
+if(value != "") return atof(value.c_str());
+ else return default_value;
+}
+
+
+unsigned int getInteger(const XMLNode& node, const std::string& name, unsigned int default_value)
+{
+ std::string value = node.attribute(name);
+if(value != "") return atoi(value.c_str());
+ else return default_value;
+}
diff --git a/hw3/src/sceneIO_geometry.cpp b/hw3/src/sceneIO_geometry.cpp
new file mode 100644
index 0000000..dd15ddb
--- /dev/null
+++ b/hw3/src/sceneIO_geometry.cpp
@@ -0,0 +1,153 @@
+/******************************************************************/
+/* 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 <vector>
+#include <memory>
+#include <string>
+#include <cstdio>
+#include <cassert>
+
+#include "sceneIO_xml.h"
+#include "sceneIO_core.h"
+#include "sceneIO_cache.h"
+#include "sceneIO_geometry.h"
+#include "sceneIO_material.h"
+
+#include "util.h"
+#include "vec2d.h"
+#include "vec3d.h"
+#include "triangle.h"
+#include "constants.h"
+#include "importOBJ.h"
+#include "errorMessage.h"
+#include "triangleMesh.h"
+#include "random_number.h"
+#include "sceneGraphNode.h"
+
+static void importTriangle(const XMLNode& node, std::vector<triangle>& triangle_list)
+{
+ // sanity check
+ assert(node.name() == "triangle" || node.name() == "polygon");
+
+ // allocate temp data
+ unsigned int idx=0;
+ vec3d v[3], n[3];
+ vec2d t[3];
+
+ // for each child node, parse all vertices
+ for(XMLNode child = node.firstChild(); child.isValid(); child++)
+ {
+ std::string name = child.name();
+ if(name == "vertex")
+ {
+ v[idx] = getVec3d(child, "v", vec3d(+LARGE));
+ n[idx] = getVec3d(child, "n", vec3d(0.0f));
+ t[idx] = getVec2d(child, "t", vec2d(+LARGE));
+
+ // check if valid vertex
+ if(v[idx].x >= +LARGE || v[idx].y >= +LARGE || v[idx].z >= +LARGE)
+ errorMessage("Invalid vertex in %s definition.", node.name().c_str());
+
+ // create triangle
+ if(idx == 2)
+ {
+ // determine which attributes are defined on the triangle
+ bool hasNormals = (n[0].squared_length() > +EPSILON) && (n[0].squared_length() > +EPSILON) && (n[0].squared_length() > +EPSILON);
+ bool hasTextureCoord = (fabs(t[0].x) < +LARGE && fabs(t[0].y) < +LARGE) && (fabs(t[1].x) < +LARGE && fabs(t[1].y) < +LARGE) && (fabs(t[2].x) < +LARGE && fabs(t[2].y) < +LARGE);
+
+ if(!hasNormals && !hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2]));
+ else if(hasNormals && !hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2], n[1], n[2], n[3]));
+ else if(!hasNormals && hasTextureCoord) triangle_list.push_back(triangle(v[0], v[1], v[2], t[0], t[1], t[2]));
+ else triangle_list.push_back(triangle(v[0], v[1], v[2], n[1], n[2], n[3], t[0], t[1], t[2]));
+
+ // cycle (to support polygons)
+ v[1] = v[2];
+ n[1] = v[2];
+ t[1] = t[2];
+ }
+ else idx++;
+ }
+ else errorMessage("Unknown child element in %s node (%s).", node.name().c_str(), name.c_str());
+ }
+
+ // check if at least one full triangle was found
+ if(idx != 2)
+ errorMessage("%s requires at least 3 vertices.", node.name().c_str());
+
+ // Done.
+ }
+
+
+/////////////////////////////////////////////////////////////////
+static std::shared_ptr<boundedPrimitive> importTriangleMesh(const XMLNode& node, nodeCache<boundedPrimitive>& shape_cache, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir)
+{
+ // sanity check
+ assert(node.name() == "triangleMesh");
+
+ // allocate node properties
+ transformation3d transform;
+ std::shared_ptr<const shader_base> material;
+ std::vector<triangle> triangle_list;
+
+ // import OBJ triangles
+ std::string objname = getString(node, "filename");
+ if(objname != "")
+ {
+ std::string path = getDirectory(objname);
+ if(path == "") objname = rootDir + objname;
+ importOBJ(objname, triangle_list);
+ }
+
+ // check child nodes
+ for(XMLNode child = node.firstChild(); child.isValid(); child++)
+ {
+ std::string name = child.name();
+
+ // general child nodes
+ auto tempmat = importMaterial(child, shader_cache, texture_cache, rootDir);
+ if(tempmat) material = tempmat;
+
+ // specialized child nodes
+ else if(name == "triangle" || name == "polygon") importTriangle(child, triangle_list);
+ else errorMessage("Unknown child-node in triangleMesh (%s).", name.c_str());
+ }
+
+ // Done.
+ return std::shared_ptr<boundedPrimitive>(new triangleMesh(triangle_list, material, transform));
+}
+
+/////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////
+std::shared_ptr<boundedPrimitive> importGeometry(const XMLNode& node, nodeCache<boundedPrimitive>& shape_cache, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir)
+{
+ // check if geometry type
+ if(node.name() != "sceneGraphNode" && node.name() != "triangleMesh") return std::shared_ptr<boundedPrimitive>(nullptr);
+
+ // check if reference
+ std::string ref = getString(node, "ref");
+ std::shared_ptr<boundedPrimitive> shape = shape_cache.get(ref);
+ if(shape) return shape;
+ else if(ref != "") errorMessage("Unknown %s name (%s).", node.name().c_str(), ref.c_str());
+
+ // generate default name & get id
+ char defaultname[32]; sprintf(defaultname, "noname-%u", random_int());
+ std::string id = getString(node, "id", defaultname);
+
+ if(shape_cache.get(id))
+ errorMessage("%s-node id is not unique (%s).", node.name().c_str(), id.c_str());
+
+ // process primitive based on type
+ else if(node.name() == "triangleMesh") shape = importTriangleMesh(node, shape_cache, shader_cache, texture_cache, rootDir);
+
+ // update cache
+ if(id != "") shape_cache.add(id, shape);
+
+ // Done.
+ return shape;
+}
diff --git a/hw3/src/sceneIO_light.cpp b/hw3/src/sceneIO_light.cpp
new file mode 100644
index 0000000..bb9e399
--- /dev/null
+++ b/hw3/src/sceneIO_light.cpp
@@ -0,0 +1,51 @@
+/******************************************************************/
+/* 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 "errorMessage.h"
+#include "random_number.h"
+
+#include "sceneIO_core.h"
+#include "sceneIO_basis.h"
+#include "sceneIO_light.h"
+#include "sceneIO_material.h"
+#include "sceneIO_geometry.h"
+
+#include "directionalLightsource.h"
+
+static std::shared_ptr<const lightsource_base> importDirectionalLight(const XMLNode& node)
+{
+ // get properties
+ vec3d direction = getVec3d(node, "direction", vec3d(0.0f, 0.0f, 1.0f));
+ color power = getColor(node, "power", color(1.0f, 1.0f, 1.0f));
+
+ // Done.
+ return std::shared_ptr<const lightsource_base>( new directionalLightsource( direction, power));
+}
+
+
+std::shared_ptr<const lightsource_base> importLight(const XMLNode& node, nodeCache<boundedPrimitive>& shape_cache, nodeCache<shader_base>& shader_cache, nodeCache<texture_base>& texture_cache, const std::string& rootDir)
+{
+ // sanity check
+ assert(node.name() == "light");
+
+ // get light source type
+ std::string type = getString(node, "type", "directional");
+
+ // create light source
+ std::shared_ptr<const lightsource_base> ls;
+ if(type == "directional") ls = importDirectionalLight(node);
+ else errorMessage("Unknown light source type (%s)", type.c_str());
+
+ // Done.
+ return ls;
+}
+
+
+
diff --git a/hw3/src/sceneIO_material.cpp b/hw3/src/sceneIO_material.cpp
new file mode 100644
index 0000000..018e913
--- /dev/null
+++ b/hw3/src/sceneIO_material.cpp
@@ -0,0 +1,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;
+}
+
diff --git a/hw3/src/sceneIO_xml.cpp b/hw3/src/sceneIO_xml.cpp
new file mode 100644
index 0000000..6f96480
--- /dev/null
+++ b/hw3/src/sceneIO_xml.cpp
@@ -0,0 +1,109 @@
+/******************************************************************/
+/* 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 "errorMessage.h"
+
+/////////////////
+// Constructor //
+/////////////////
+XMLNode::XMLNode(const std::string& filename)
+{
+ // open xml
+ _xml = std::make_shared<tinyxml2::XMLDocument>();
+ _xml->LoadFile(filename.c_str());
+
+ // check if open successful
+ if(_xml->ErrorID() != tinyxml2::XML_SUCCESS)
+ errorMessage("Failed to open scene file: '%s'.", filename.c_str());
+
+ // set first node.
+ _element = _xml->FirstChildElement("scene");
+}
+
+
+XMLNode::XMLNode(const XMLNode& node)
+{
+ _element = node._element;
+ _xml = node._xml;
+}
+
+XMLNode::XMLNode(const tinyxml2::XMLElement* element, const std::shared_ptr<tinyxml2::XMLDocument>& xml)
+{
+ _element = element;
+ _xml = xml;
+}
+
+
+/////////////
+// Methods //
+/////////////
+XMLNode XMLNode::firstChild(void) const
+{
+ assert(isValid());
+ return XMLNode(_element->FirstChildElement(), _xml);
+}
+
+
+XMLNode XMLNode::findChild(const std::string& name) const
+{
+ assert(isValid());
+ return XMLNode(_element->FirstChildElement(name.c_str()), _xml);
+}
+
+
+bool XMLNode::isValid(void) const
+{
+ return (_element != NULL);
+}
+
+
+std::string XMLNode::name(void) const
+{
+ assert(isValid());
+ return std::string(_element->Name());
+}
+
+
+std::string XMLNode::attribute(const std::string& attribute) const
+{
+ assert(isValid());
+
+ const char* str = _element->Attribute(attribute.c_str());
+ if(str == NULL) return std::string("");
+
+ // Done.
+ return std::string(str);
+}
+
+
+///////////////
+// Operators //
+///////////////
+XMLNode& XMLNode::operator=(const XMLNode& src)
+{
+ _element = src._element;
+ _xml = src._xml;
+}
+
+
+XMLNode& XMLNode::operator++(int)
+{
+ assert(_element != NULL);
+ _element = _element->NextSiblingElement();
+}
+
+
+XMLNode& XMLNode::operator++(void)
+{
+ assert(_element != NULL);
+ _element = _element->NextSiblingElement();
+}
+
+
diff --git a/hw3/src/shaderProperties.cpp b/hw3/src/shaderProperties.cpp
new file mode 100644
index 0000000..aad680b
--- /dev/null
+++ b/hw3/src/shaderProperties.cpp
@@ -0,0 +1,59 @@
+/******************************************************************/
+/* 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 "shaderProperties.h"
+
+
+//////////////
+// Operator //
+//////////////
+bool shaderProperties::operator==(const shaderProperties& sp) const
+{
+ return (diffuse == sp.diffuse) && (specular == sp.specular);
+}
+
+
+bool shaderProperties::operator!=(const shaderProperties& sp) const
+{
+ return !(*this == sp);
+}
+
+
+shaderProperties& shaderProperties::operator&=(const shaderProperties& sp)
+{
+ diffuse &= sp.diffuse;
+ specular &= sp.specular;
+}
+
+
+shaderProperties& shaderProperties::operator|=(const shaderProperties& sp)
+{
+ diffuse |= sp.diffuse;
+ specular |= sp.specular;
+}
+
+
+shaderProperties& shaderProperties::operator~(void)
+{
+ diffuse = ~diffuse;
+ specular = ~specular;
+}
+
+
+shaderProperties shaderProperties::operator&(const shaderProperties& sp) const
+{
+ return shaderProperties(diffuse & sp.diffuse,
+ specular & sp.specular);
+}
+
+
+shaderProperties shaderProperties::operator|(const shaderProperties& sp) const
+{
+ return shaderProperties(diffuse | sp.diffuse,
+ specular | sp.specular);
+}
diff --git a/hw3/src/tinyxml2.cpp b/hw3/src/tinyxml2.cpp
new file mode 100644
index 0000000..c4ea7cd
--- /dev/null
+++ b/hw3/src/tinyxml2.cpp
@@ -0,0 +1,2466 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "tinyxml2.h"
+
+#include <new> // yes, this one new style header, is in the Android SDK.
+#if defined(ANDROID_NDK) || defined(__QNXNTO__)
+# include <stddef.h>
+# include <stdarg.h>
+#else
+# include <cstddef>
+# include <cstdarg>
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
+ // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
+ /*int _snprintf_s(
+ char *buffer,
+ size_t sizeOfBuffer,
+ size_t count,
+ const char *format [,
+ argument] ...
+ );*/
+ static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
+ {
+ va_list va;
+ va_start( va, format );
+ int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+ va_end( va );
+ return result;
+ }
+
+ static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
+ {
+ int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+ return result;
+ }
+
+ #define TIXML_VSCPRINTF _vscprintf
+ #define TIXML_SSCANF sscanf_s
+#elif defined _MSC_VER
+ // Microsoft Visual Studio 2003 and earlier or WinCE
+ #define TIXML_SNPRINTF _snprintf
+ #define TIXML_VSNPRINTF _vsnprintf
+ #define TIXML_SSCANF sscanf
+ #if (_MSC_VER < 1400 ) && (!defined WINCE)
+ // Microsoft Visual Studio 2003 and not WinCE.
+ #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
+ #else
+ // Microsoft Visual Studio 2003 and earlier or WinCE.
+ static inline int TIXML_VSCPRINTF( const char* format, va_list va )
+ {
+ int len = 512;
+ for (;;) {
+ len = len*2;
+ char* str = new char[len]();
+ const int required = _vsnprintf(str, len, format, va);
+ delete[] str;
+ if ( required != -1 ) {
+ TIXMLASSERT( required >= 0 );
+ len = required;
+ break;
+ }
+ }
+ TIXMLASSERT( len >= 0 );
+ return len;
+ }
+ #endif
+#else
+ // GCC version 3 and higher
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_VSNPRINTF vsnprintf
+ static inline int TIXML_VSCPRINTF( const char* format, va_list va )
+ {
+ int len = vsnprintf( 0, 0, format, va );
+ TIXMLASSERT( len >= 0 );
+ return len;
+ }
+ #define TIXML_SSCANF sscanf
+#endif
+
+
+static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
+static const char LF = LINE_FEED;
+static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
+static const char CR = CARRIAGE_RETURN;
+static const char SINGLE_QUOTE = '\'';
+static const char DOUBLE_QUOTE = '\"';
+
+// Bunch of unicode info at:
+// http://www.unicode.org/faq/utf_bom.html
+// ef bb bf (Microsoft "lead bytes") - designates UTF-8
+
+static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+namespace tinyxml2
+{
+
+struct Entity {
+ const char* pattern;
+ int length;
+ char value;
+};
+
+static const int NUM_ENTITIES = 5;
+static const Entity entities[NUM_ENTITIES] = {
+ { "quot", 4, DOUBLE_QUOTE },
+ { "amp", 3, '&' },
+ { "apos", 4, SINGLE_QUOTE },
+ { "lt", 2, '<' },
+ { "gt", 2, '>' }
+};
+
+
+StrPair::~StrPair()
+{
+ Reset();
+}
+
+
+void StrPair::TransferTo( StrPair* other )
+{
+ if ( this == other ) {
+ return;
+ }
+ // This in effect implements the assignment operator by "moving"
+ // ownership (as in auto_ptr).
+
+ TIXMLASSERT( other->_flags == 0 );
+ TIXMLASSERT( other->_start == 0 );
+ TIXMLASSERT( other->_end == 0 );
+
+ other->Reset();
+
+ other->_flags = _flags;
+ other->_start = _start;
+ other->_end = _end;
+
+ _flags = 0;
+ _start = 0;
+ _end = 0;
+}
+
+void StrPair::Reset()
+{
+ if ( _flags & NEEDS_DELETE ) {
+ delete [] _start;
+ }
+ _flags = 0;
+ _start = 0;
+ _end = 0;
+}
+
+
+void StrPair::SetStr( const char* str, int flags )
+{
+ TIXMLASSERT( str );
+ Reset();
+ size_t len = strlen( str );
+ TIXMLASSERT( _start == 0 );
+ _start = new char[ len+1 ];
+ memcpy( _start, str, len+1 );
+ _end = _start + len;
+ _flags = flags | NEEDS_DELETE;
+}
+
+
+char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
+{
+ TIXMLASSERT( endTag && *endTag );
+
+ char* start = p;
+ char endChar = *endTag;
+ size_t length = strlen( endTag );
+
+ // Inner loop of text parsing.
+ while ( *p ) {
+ if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
+ Set( start, p, strFlags );
+ return p + length;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+
+char* StrPair::ParseName( char* p )
+{
+ if ( !p || !(*p) ) {
+ return 0;
+ }
+ if ( !XMLUtil::IsNameStartChar( *p ) ) {
+ return 0;
+ }
+
+ char* const start = p;
+ ++p;
+ while ( *p && XMLUtil::IsNameChar( *p ) ) {
+ ++p;
+ }
+
+ Set( start, p, 0 );
+ return p;
+}
+
+
+void StrPair::CollapseWhitespace()
+{
+ // Adjusting _start would cause undefined behavior on delete[]
+ TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
+ // Trim leading space.
+ _start = XMLUtil::SkipWhiteSpace( _start );
+
+ if ( *_start ) {
+ char* p = _start; // the read pointer
+ char* q = _start; // the write pointer
+
+ while( *p ) {
+ if ( XMLUtil::IsWhiteSpace( *p )) {
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( *p == 0 ) {
+ break; // don't write to q; this trims the trailing space.
+ }
+ *q = ' ';
+ ++q;
+ }
+ *q = *p;
+ ++q;
+ ++p;
+ }
+ *q = 0;
+ }
+}
+
+
+const char* StrPair::GetStr()
+{
+ TIXMLASSERT( _start );
+ TIXMLASSERT( _end );
+ if ( _flags & NEEDS_FLUSH ) {
+ *_end = 0;
+ _flags ^= NEEDS_FLUSH;
+
+ if ( _flags ) {
+ char* p = _start; // the read pointer
+ char* q = _start; // the write pointer
+
+ while( p < _end ) {
+ if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
+ // CR-LF pair becomes LF
+ // CR alone becomes LF
+ // LF-CR becomes LF
+ if ( *(p+1) == LF ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q++ = LF;
+ }
+ else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
+ if ( *(p+1) == CR ) {
+ p += 2;
+ }
+ else {
+ ++p;
+ }
+ *q++ = LF;
+ }
+ else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
+ // Entities handled by tinyXML2:
+ // - special entities in the entity table [in/out]
+ // - numeric character reference [in]
+ // &#20013; or &#x4e2d;
+
+ if ( *(p+1) == '#' ) {
+ const int buflen = 10;
+ char buf[buflen] = { 0 };
+ int len = 0;
+ char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
+ if ( adjusted == 0 ) {
+ *q = *p;
+ ++p;
+ ++q;
+ }
+ else {
+ TIXMLASSERT( 0 <= len && len <= buflen );
+ TIXMLASSERT( q + len <= adjusted );
+ p = adjusted;
+ memcpy( q, buf, len );
+ q += len;
+ }
+ }
+ else {
+ bool entityFound = false;
+ for( int i = 0; i < NUM_ENTITIES; ++i ) {
+ const Entity& entity = entities[i];
+ if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
+ && *( p + entity.length + 1 ) == ';' ) {
+ // Found an entity - convert.
+ *q = entity.value;
+ ++q;
+ p += entity.length + 2;
+ entityFound = true;
+ break;
+ }
+ }
+ if ( !entityFound ) {
+ // fixme: treat as error?
+ ++p;
+ ++q;
+ }
+ }
+ }
+ else {
+ *q = *p;
+ ++p;
+ ++q;
+ }
+ }
+ *q = 0;
+ }
+ // The loop below has plenty going on, and this
+ // is a less useful mode. Break it out.
+ if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
+ CollapseWhitespace();
+ }
+ _flags = (_flags & NEEDS_DELETE);
+ }
+ TIXMLASSERT( _start );
+ return _start;
+}
+
+
+
+
+// --------- XMLUtil ----------- //
+
+const char* XMLUtil::ReadBOM( const char* p, bool* bom )
+{
+ TIXMLASSERT( p );
+ TIXMLASSERT( bom );
+ *bom = false;
+ const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
+ // Check for BOM:
+ if ( *(pu+0) == TIXML_UTF_LEAD_0
+ && *(pu+1) == TIXML_UTF_LEAD_1
+ && *(pu+2) == TIXML_UTF_LEAD_2 ) {
+ *bom = true;
+ p += 3;
+ }
+ TIXMLASSERT( p );
+ return p;
+}
+
+
+void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+ const unsigned long BYTE_MASK = 0xBF;
+ const unsigned long BYTE_MARK = 0x80;
+ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ if (input < 0x80) {
+ *length = 1;
+ }
+ else if ( input < 0x800 ) {
+ *length = 2;
+ }
+ else if ( input < 0x10000 ) {
+ *length = 3;
+ }
+ else if ( input < 0x200000 ) {
+ *length = 4;
+ }
+ else {
+ *length = 0; // This code won't convert this correctly anyway.
+ return;
+ }
+
+ output += *length;
+
+ // Scary scary fall throughs.
+ switch (*length) {
+ case 4:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 3:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 2:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 1:
+ --output;
+ *output = (char)(input | FIRST_BYTE_MARK[*length]);
+ break;
+ default:
+ TIXMLASSERT( false );
+ }
+}
+
+
+const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
+{
+ // Presume an entity, and pull it out.
+ *length = 0;
+
+ if ( *(p+1) == '#' && *(p+2) ) {
+ unsigned long ucs = 0;
+ TIXMLASSERT( sizeof( ucs ) >= 4 );
+ ptrdiff_t delta = 0;
+ unsigned mult = 1;
+ static const char SEMICOLON = ';';
+
+ if ( *(p+2) == 'x' ) {
+ // Hexadecimal.
+ const char* q = p+3;
+ if ( !(*q) ) {
+ return 0;
+ }
+
+ q = strchr( q, SEMICOLON );
+
+ if ( !q ) {
+ return 0;
+ }
+ TIXMLASSERT( *q == SEMICOLON );
+
+ delta = q-p;
+ --q;
+
+ while ( *q != 'x' ) {
+ unsigned int digit = 0;
+
+ if ( *q >= '0' && *q <= '9' ) {
+ digit = *q - '0';
+ }
+ else if ( *q >= 'a' && *q <= 'f' ) {
+ digit = *q - 'a' + 10;
+ }
+ else if ( *q >= 'A' && *q <= 'F' ) {
+ digit = *q - 'A' + 10;
+ }
+ else {
+ return 0;
+ }
+ TIXMLASSERT( digit >= 0 && digit < 16);
+ TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
+ const unsigned int digitScaled = mult * digit;
+ TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
+ ucs += digitScaled;
+ TIXMLASSERT( mult <= UINT_MAX / 16 );
+ mult *= 16;
+ --q;
+ }
+ }
+ else {
+ // Decimal.
+ const char* q = p+2;
+ if ( !(*q) ) {
+ return 0;
+ }
+
+ q = strchr( q, SEMICOLON );
+
+ if ( !q ) {
+ return 0;
+ }
+ TIXMLASSERT( *q == SEMICOLON );
+
+ delta = q-p;
+ --q;
+
+ while ( *q != '#' ) {
+ if ( *q >= '0' && *q <= '9' ) {
+ const unsigned int digit = *q - '0';
+ TIXMLASSERT( digit >= 0 && digit < 10);
+ TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
+ const unsigned int digitScaled = mult * digit;
+ TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
+ ucs += digitScaled;
+ }
+ else {
+ return 0;
+ }
+ TIXMLASSERT( mult <= UINT_MAX / 10 );
+ mult *= 10;
+ --q;
+ }
+ }
+ // convert the UCS to UTF-8
+ ConvertUTF32ToUTF8( ucs, value, length );
+ return p + delta + 1;
+ }
+ return p+1;
+}
+
+
+void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
+}
+
+
+void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
+}
+
+
+void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
+}
+
+/*
+ ToStr() of a number is a very tricky topic.
+ https://github.com/leethomason/tinyxml2/issues/106
+*/
+void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
+}
+
+
+void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
+{
+ TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
+}
+
+
+bool XMLUtil::ToInt( const char* str, int* value )
+{
+ if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
+{
+ if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToBool( const char* str, bool* value )
+{
+ int ival = 0;
+ if ( ToInt( str, &ival )) {
+ *value = (ival==0) ? false : true;
+ return true;
+ }
+ if ( StringEqual( str, "true" ) ) {
+ *value = true;
+ return true;
+ }
+ else if ( StringEqual( str, "false" ) ) {
+ *value = false;
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLUtil::ToFloat( const char* str, float* value )
+{
+ if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+bool XMLUtil::ToDouble( const char* str, double* value )
+{
+ if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
+ return true;
+ }
+ return false;
+}
+
+
+char* XMLDocument::Identify( char* p, XMLNode** node )
+{
+ TIXMLASSERT( node );
+ TIXMLASSERT( p );
+ char* const start = p;
+ p = XMLUtil::SkipWhiteSpace( p );
+ if( !*p ) {
+ *node = 0;
+ TIXMLASSERT( p );
+ return p;
+ }
+
+ // These strings define the matching patterns:
+ static const char* xmlHeader = { "<?" };
+ static const char* commentHeader = { "<!--" };
+ static const char* cdataHeader = { "<![CDATA[" };
+ static const char* dtdHeader = { "<!" };
+ static const char* elementHeader = { "<" }; // and a header for everything else; check last.
+
+ static const int xmlHeaderLen = 2;
+ static const int commentHeaderLen = 4;
+ static const int cdataHeaderLen = 9;
+ static const int dtdHeaderLen = 2;
+ static const int elementHeaderLen = 1;
+
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
+ TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
+ XMLNode* returnNode = 0;
+ if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
+ TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
+ returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
+ returnNode->_memPool = &_commentPool;
+ p += xmlHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
+ TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
+ returnNode = new (_commentPool.Alloc()) XMLComment( this );
+ returnNode->_memPool = &_commentPool;
+ p += commentHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
+ TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
+ XMLText* text = new (_textPool.Alloc()) XMLText( this );
+ returnNode = text;
+ returnNode->_memPool = &_textPool;
+ p += cdataHeaderLen;
+ text->SetCData( true );
+ }
+ else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
+ TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
+ returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
+ returnNode->_memPool = &_commentPool;
+ p += dtdHeaderLen;
+ }
+ else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
+ TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
+ returnNode = new (_elementPool.Alloc()) XMLElement( this );
+ returnNode->_memPool = &_elementPool;
+ p += elementHeaderLen;
+ }
+ else {
+ TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
+ returnNode = new (_textPool.Alloc()) XMLText( this );
+ returnNode->_memPool = &_textPool;
+ p = start; // Back it up, all the text counts.
+ }
+
+ TIXMLASSERT( returnNode );
+ TIXMLASSERT( p );
+ *node = returnNode;
+ return p;
+}
+
+
+bool XMLDocument::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ if ( visitor->VisitEnter( *this ) ) {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+ if ( !node->Accept( visitor ) ) {
+ break;
+ }
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLNode ----------- //
+
+XMLNode::XMLNode( XMLDocument* doc ) :
+ _document( doc ),
+ _parent( 0 ),
+ _firstChild( 0 ), _lastChild( 0 ),
+ _prev( 0 ), _next( 0 ),
+ _memPool( 0 )
+{
+}
+
+
+XMLNode::~XMLNode()
+{
+ DeleteChildren();
+ if ( _parent ) {
+ _parent->Unlink( this );
+ }
+}
+
+const char* XMLNode::Value() const
+{
+ // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
+ if ( this->ToDocument() )
+ return 0;
+ return _value.GetStr();
+}
+
+void XMLNode::SetValue( const char* str, bool staticMem )
+{
+ if ( staticMem ) {
+ _value.SetInternedStr( str );
+ }
+ else {
+ _value.SetStr( str );
+ }
+}
+
+
+void XMLNode::DeleteChildren()
+{
+ while( _firstChild ) {
+ TIXMLASSERT( _lastChild );
+ TIXMLASSERT( _firstChild->_document == _document );
+ XMLNode* node = _firstChild;
+ Unlink( node );
+
+ DeleteNode( node );
+ }
+ _firstChild = _lastChild = 0;
+}
+
+
+void XMLNode::Unlink( XMLNode* child )
+{
+ TIXMLASSERT( child );
+ TIXMLASSERT( child->_document == _document );
+ TIXMLASSERT( child->_parent == this );
+ if ( child == _firstChild ) {
+ _firstChild = _firstChild->_next;
+ }
+ if ( child == _lastChild ) {
+ _lastChild = _lastChild->_prev;
+ }
+
+ if ( child->_prev ) {
+ child->_prev->_next = child->_next;
+ }
+ if ( child->_next ) {
+ child->_next->_prev = child->_prev;
+ }
+ child->_parent = 0;
+}
+
+
+void XMLNode::DeleteChild( XMLNode* node )
+{
+ TIXMLASSERT( node );
+ TIXMLASSERT( node->_document == _document );
+ TIXMLASSERT( node->_parent == this );
+ Unlink( node );
+ DeleteNode( node );
+}
+
+
+XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+ InsertChildPreamble( addThis );
+
+ if ( _lastChild ) {
+ TIXMLASSERT( _firstChild );
+ TIXMLASSERT( _lastChild->_next == 0 );
+ _lastChild->_next = addThis;
+ addThis->_prev = _lastChild;
+ _lastChild = addThis;
+
+ addThis->_next = 0;
+ }
+ else {
+ TIXMLASSERT( _firstChild == 0 );
+ _firstChild = _lastChild = addThis;
+
+ addThis->_prev = 0;
+ addThis->_next = 0;
+ }
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+ InsertChildPreamble( addThis );
+
+ if ( _firstChild ) {
+ TIXMLASSERT( _lastChild );
+ TIXMLASSERT( _firstChild->_prev == 0 );
+
+ _firstChild->_prev = addThis;
+ addThis->_next = _firstChild;
+ _firstChild = addThis;
+
+ addThis->_prev = 0;
+ }
+ else {
+ TIXMLASSERT( _lastChild == 0 );
+ _firstChild = _lastChild = addThis;
+
+ addThis->_prev = 0;
+ addThis->_next = 0;
+ }
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
+{
+ TIXMLASSERT( addThis );
+ if ( addThis->_document != _document ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+
+ TIXMLASSERT( afterThis );
+
+ if ( afterThis->_parent != this ) {
+ TIXMLASSERT( false );
+ return 0;
+ }
+
+ if ( afterThis->_next == 0 ) {
+ // The last node or the only node.
+ return InsertEndChild( addThis );
+ }
+ InsertChildPreamble( addThis );
+ addThis->_prev = afterThis;
+ addThis->_next = afterThis->_next;
+ afterThis->_next->_prev = addThis;
+ afterThis->_next = addThis;
+ addThis->_parent = this;
+ return addThis;
+}
+
+
+
+
+const XMLElement* XMLNode::FirstChildElement( const char* name ) const
+{
+ for( const XMLNode* node = _firstChild; node; node = node->_next ) {
+ const XMLElement* element = node->ToElement();
+ if ( element ) {
+ if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
+ return element;
+ }
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::LastChildElement( const char* name ) const
+{
+ for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
+ const XMLElement* element = node->ToElement();
+ if ( element ) {
+ if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
+ return element;
+ }
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
+{
+ for( const XMLNode* node = _next; node; node = node->_next ) {
+ const XMLElement* element = node->ToElement();
+ if ( element
+ && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
+{
+ for( const XMLNode* node = _prev; node; node = node->_prev ) {
+ const XMLElement* element = node->ToElement();
+ if ( element
+ && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
+ return element;
+ }
+ }
+ return 0;
+}
+
+
+char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
+{
+ // This is a recursive method, but thinking about it "at the current level"
+ // it is a pretty simple flat list:
+ // <foo/>
+ // <!-- comment -->
+ //
+ // With a special case:
+ // <foo>
+ // </foo>
+ // <!-- comment -->
+ //
+ // Where the closing element (/foo) *must* be the next thing after the opening
+ // element, and the names must match. BUT the tricky bit is that the closing
+ // element will be read by the child.
+ //
+ // 'endTag' is the end tag for this node, it is returned by a call to a child.
+ // 'parentEnd' is the end tag for the parent, which is filled in and returned.
+
+ while( p && *p ) {
+ XMLNode* node = 0;
+
+ p = _document->Identify( p, &node );
+ if ( node == 0 ) {
+ break;
+ }
+
+ StrPair endTag;
+ p = node->ParseDeep( p, &endTag );
+ if ( !p ) {
+ DeleteNode( node );
+ if ( !_document->Error() ) {
+ _document->SetError( XML_ERROR_PARSING, 0, 0 );
+ }
+ break;
+ }
+
+ XMLDeclaration* decl = node->ToDeclaration();
+ if ( decl ) {
+ // A declaration can only be the first child of a document.
+ // Set error, if document already has children.
+ if ( !_document->NoChildren() ) {
+ _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
+ DeleteNode( decl );
+ break;
+ }
+ }
+
+ XMLElement* ele = node->ToElement();
+ if ( ele ) {
+ // We read the end tag. Return it to the parent.
+ if ( ele->ClosingType() == XMLElement::CLOSING ) {
+ if ( parentEnd ) {
+ ele->_value.TransferTo( parentEnd );
+ }
+ node->_memPool->SetTracked(); // created and then immediately deleted.
+ DeleteNode( node );
+ return p;
+ }
+
+ // Handle an end tag returned to this level.
+ // And handle a bunch of annoying errors.
+ bool mismatch = false;
+ if ( endTag.Empty() ) {
+ if ( ele->ClosingType() == XMLElement::OPEN ) {
+ mismatch = true;
+ }
+ }
+ else {
+ if ( ele->ClosingType() != XMLElement::OPEN ) {
+ mismatch = true;
+ }
+ else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
+ mismatch = true;
+ }
+ }
+ if ( mismatch ) {
+ _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
+ DeleteNode( node );
+ break;
+ }
+ }
+ InsertEndChild( node );
+ }
+ return 0;
+}
+
+void XMLNode::DeleteNode( XMLNode* node )
+{
+ if ( node == 0 ) {
+ return;
+ }
+ MemPool* pool = node->_memPool;
+ node->~XMLNode();
+ pool->Free( node );
+}
+
+void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
+{
+ TIXMLASSERT( insertThis );
+ TIXMLASSERT( insertThis->_document == _document );
+
+ if ( insertThis->_parent )
+ insertThis->_parent->Unlink( insertThis );
+ else
+ insertThis->_memPool->SetTracked();
+}
+
+// --------- XMLText ---------- //
+char* XMLText::ParseDeep( char* p, StrPair* )
+{
+ const char* start = p;
+ if ( this->CData() ) {
+ p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
+ }
+ return p;
+ }
+ else {
+ int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
+ if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
+ flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
+ }
+
+ p = _value.ParseText( p, "<", flags );
+ if ( p && *p ) {
+ return p-1;
+ }
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
+ }
+ }
+ return 0;
+}
+
+
+XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
+ text->SetCData( this->CData() );
+ return text;
+}
+
+
+bool XMLText::ShallowEqual( const XMLNode* compare ) const
+{
+ const XMLText* text = compare->ToText();
+ return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
+}
+
+
+bool XMLText::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLComment ---------- //
+
+XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLComment::~XMLComment()
+{
+}
+
+
+char* XMLComment::ParseDeep( char* p, StrPair* )
+{
+ // Comment parses as text.
+ const char* start = p;
+ p = _value.ParseText( p, "-->", StrPair::COMMENT );
+ if ( p == 0 ) {
+ _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
+ return comment;
+}
+
+
+bool XMLComment::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLComment* comment = compare->ToComment();
+ return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
+}
+
+
+bool XMLComment::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+
+// --------- XMLDeclaration ---------- //
+
+XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLDeclaration::~XMLDeclaration()
+{
+ //printf( "~XMLDeclaration\n" );
+}
+
+
+char* XMLDeclaration::ParseDeep( char* p, StrPair* )
+{
+ // Declaration parses as text.
+ const char* start = p;
+ p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( p == 0 ) {
+ _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
+ return dec;
+}
+
+
+bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLDeclaration* declaration = compare->ToDeclaration();
+ return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
+}
+
+
+
+bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+// --------- XMLUnknown ---------- //
+
+XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLUnknown::~XMLUnknown()
+{
+}
+
+
+char* XMLUnknown::ParseDeep( char* p, StrPair* )
+{
+ // Unknown parses as text.
+ const char* start = p;
+
+ p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+ if ( !p ) {
+ _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
+ }
+ return p;
+}
+
+
+XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
+ return text;
+}
+
+
+bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLUnknown* unknown = compare->ToUnknown();
+ return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
+}
+
+
+bool XMLUnknown::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ return visitor->Visit( *this );
+}
+
+// --------- XMLAttribute ---------- //
+
+const char* XMLAttribute::Name() const
+{
+ return _name.GetStr();
+}
+
+const char* XMLAttribute::Value() const
+{
+ return _value.GetStr();
+}
+
+char* XMLAttribute::ParseDeep( char* p, bool processEntities )
+{
+ // Parse using the name rules: bug fix, was using ParseText before
+ p = _name.ParseName( p );
+ if ( !p || !*p ) {
+ return 0;
+ }
+
+ // Skip white space before =
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( *p != '=' ) {
+ return 0;
+ }
+
+ ++p; // move up to opening quote
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( *p != '\"' && *p != '\'' ) {
+ return 0;
+ }
+
+ char endTag[2] = { *p, 0 };
+ ++p; // move past opening quote
+
+ p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
+ return p;
+}
+
+
+void XMLAttribute::SetName( const char* n )
+{
+ _name.SetStr( n );
+}
+
+
+XMLError XMLAttribute::QueryIntValue( int* value ) const
+{
+ if ( XMLUtil::ToInt( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
+{
+ if ( XMLUtil::ToUnsigned( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryBoolValue( bool* value ) const
+{
+ if ( XMLUtil::ToBool( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryFloatValue( float* value ) const
+{
+ if ( XMLUtil::ToFloat( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryDoubleValue( double* value ) const
+{
+ if ( XMLUtil::ToDouble( Value(), value )) {
+ return XML_NO_ERROR;
+ }
+ return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+void XMLAttribute::SetAttribute( const char* v )
+{
+ _value.SetStr( v );
+}
+
+
+void XMLAttribute::SetAttribute( int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( float v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ _value.SetStr( buf );
+}
+
+
+// --------- XMLElement ---------- //
+XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
+ _closingType( 0 ),
+ _rootAttribute( 0 )
+{
+}
+
+
+XMLElement::~XMLElement()
+{
+ while( _rootAttribute ) {
+ XMLAttribute* next = _rootAttribute->_next;
+ DeleteAttribute( _rootAttribute );
+ _rootAttribute = next;
+ }
+}
+
+
+const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
+{
+ for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
+ if ( XMLUtil::StringEqual( a->Name(), name ) ) {
+ return a;
+ }
+ }
+ return 0;
+}
+
+
+const char* XMLElement::Attribute( const char* name, const char* value ) const
+{
+ const XMLAttribute* a = FindAttribute( name );
+ if ( !a ) {
+ return 0;
+ }
+ if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
+ return a->Value();
+ }
+ return 0;
+}
+
+
+const char* XMLElement::GetText() const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ return FirstChild()->Value();
+ }
+ return 0;
+}
+
+
+void XMLElement::SetText( const char* inText )
+{
+ if ( FirstChild() && FirstChild()->ToText() )
+ FirstChild()->SetValue( inText );
+ else {
+ XMLText* theText = GetDocument()->NewText( inText );
+ InsertFirstChild( theText );
+ }
+}
+
+
+void XMLElement::SetText( int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( float v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+XMLError XMLElement::QueryIntText( int* ival ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToInt( t, ival ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToUnsigned( t, uval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryBoolText( bool* bval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToBool( t, bval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryDoubleText( double* dval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToDouble( t, dval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryFloatText( float* fval ) const
+{
+ if ( FirstChild() && FirstChild()->ToText() ) {
+ const char* t = FirstChild()->Value();
+ if ( XMLUtil::ToFloat( t, fval ) ) {
+ return XML_SUCCESS;
+ }
+ return XML_CAN_NOT_CONVERT_TEXT;
+ }
+ return XML_NO_TEXT_NODE;
+}
+
+
+
+XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
+{
+ XMLAttribute* last = 0;
+ XMLAttribute* attrib = 0;
+ for( attrib = _rootAttribute;
+ attrib;
+ last = attrib, attrib = attrib->_next ) {
+ if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
+ break;
+ }
+ }
+ if ( !attrib ) {
+ TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
+ attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
+ attrib->_memPool = &_document->_attributePool;
+ if ( last ) {
+ last->_next = attrib;
+ }
+ else {
+ _rootAttribute = attrib;
+ }
+ attrib->SetName( name );
+ attrib->_memPool->SetTracked(); // always created and linked.
+ }
+ return attrib;
+}
+
+
+void XMLElement::DeleteAttribute( const char* name )
+{
+ XMLAttribute* prev = 0;
+ for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
+ if ( XMLUtil::StringEqual( name, a->Name() ) ) {
+ if ( prev ) {
+ prev->_next = a->_next;
+ }
+ else {
+ _rootAttribute = a->_next;
+ }
+ DeleteAttribute( a );
+ break;
+ }
+ prev = a;
+ }
+}
+
+
+char* XMLElement::ParseAttributes( char* p )
+{
+ const char* start = p;
+ XMLAttribute* prevAttribute = 0;
+
+ // Read the attributes.
+ while( p ) {
+ p = XMLUtil::SkipWhiteSpace( p );
+ if ( !(*p) ) {
+ _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
+ return 0;
+ }
+
+ // attribute.
+ if (XMLUtil::IsNameStartChar( *p ) ) {
+ TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
+ XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
+ attrib->_memPool = &_document->_attributePool;
+ attrib->_memPool->SetTracked();
+
+ p = attrib->ParseDeep( p, _document->ProcessEntities() );
+ if ( !p || Attribute( attrib->Name() ) ) {
+ DeleteAttribute( attrib );
+ _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
+ return 0;
+ }
+ // There is a minor bug here: if the attribute in the source xml
+ // document is duplicated, it will not be detected and the
+ // attribute will be doubly added. However, tracking the 'prevAttribute'
+ // avoids re-scanning the attribute list. Preferring performance for
+ // now, may reconsider in the future.
+ if ( prevAttribute ) {
+ prevAttribute->_next = attrib;
+ }
+ else {
+ _rootAttribute = attrib;
+ }
+ prevAttribute = attrib;
+ }
+ // end of the tag
+ else if ( *p == '>' ) {
+ ++p;
+ break;
+ }
+ // end of the tag
+ else if ( *p == '/' && *(p+1) == '>' ) {
+ _closingType = CLOSED;
+ return p+2; // done; sealed element.
+ }
+ else {
+ _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
+ return 0;
+ }
+ }
+ return p;
+}
+
+void XMLElement::DeleteAttribute( XMLAttribute* attribute )
+{
+ if ( attribute == 0 ) {
+ return;
+ }
+ MemPool* pool = attribute->_memPool;
+ attribute->~XMLAttribute();
+ pool->Free( attribute );
+}
+
+//
+// <ele></ele>
+// <ele>foo<b>bar</b></ele>
+//
+char* XMLElement::ParseDeep( char* p, StrPair* strPair )
+{
+ // Read the element name.
+ p = XMLUtil::SkipWhiteSpace( p );
+
+ // The closing element is the </element> form. It is
+ // parsed just like a regular element then deleted from
+ // the DOM.
+ if ( *p == '/' ) {
+ _closingType = CLOSING;
+ ++p;
+ }
+
+ p = _value.ParseName( p );
+ if ( _value.Empty() ) {
+ return 0;
+ }
+
+ p = ParseAttributes( p );
+ if ( !p || !*p || _closingType ) {
+ return p;
+ }
+
+ p = XMLNode::ParseDeep( p, strPair );
+ return p;
+}
+
+
+
+XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
+{
+ if ( !doc ) {
+ doc = _document;
+ }
+ XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
+ for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
+ element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
+ }
+ return element;
+}
+
+
+bool XMLElement::ShallowEqual( const XMLNode* compare ) const
+{
+ TIXMLASSERT( compare );
+ const XMLElement* other = compare->ToElement();
+ if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
+
+ const XMLAttribute* a=FirstAttribute();
+ const XMLAttribute* b=other->FirstAttribute();
+
+ while ( a && b ) {
+ if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
+ return false;
+ }
+ a = a->Next();
+ b = b->Next();
+ }
+ if ( a || b ) {
+ // different count
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool XMLElement::Accept( XMLVisitor* visitor ) const
+{
+ TIXMLASSERT( visitor );
+ if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
+ for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+ if ( !node->Accept( visitor ) ) {
+ break;
+ }
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLDocument ----------- //
+
+// Warning: List must match 'enum XMLError'
+const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
+ "XML_SUCCESS",
+ "XML_NO_ATTRIBUTE",
+ "XML_WRONG_ATTRIBUTE_TYPE",
+ "XML_ERROR_FILE_NOT_FOUND",
+ "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
+ "XML_ERROR_FILE_READ_ERROR",
+ "XML_ERROR_ELEMENT_MISMATCH",
+ "XML_ERROR_PARSING_ELEMENT",
+ "XML_ERROR_PARSING_ATTRIBUTE",
+ "XML_ERROR_IDENTIFYING_TAG",
+ "XML_ERROR_PARSING_TEXT",
+ "XML_ERROR_PARSING_CDATA",
+ "XML_ERROR_PARSING_COMMENT",
+ "XML_ERROR_PARSING_DECLARATION",
+ "XML_ERROR_PARSING_UNKNOWN",
+ "XML_ERROR_EMPTY_DOCUMENT",
+ "XML_ERROR_MISMATCHED_ELEMENT",
+ "XML_ERROR_PARSING",
+ "XML_CAN_NOT_CONVERT_TEXT",
+ "XML_NO_TEXT_NODE"
+};
+
+
+XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
+ XMLNode( 0 ),
+ _writeBOM( false ),
+ _processEntities( processEntities ),
+ _errorID( XML_NO_ERROR ),
+ _whitespace( whitespace ),
+ _errorStr1( 0 ),
+ _errorStr2( 0 ),
+ _charBuffer( 0 )
+{
+ // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
+ _document = this;
+}
+
+
+XMLDocument::~XMLDocument()
+{
+ Clear();
+}
+
+
+void XMLDocument::Clear()
+{
+ DeleteChildren();
+
+#ifdef DEBUG
+ const bool hadError = Error();
+#endif
+ _errorID = XML_NO_ERROR;
+ _errorStr1 = 0;
+ _errorStr2 = 0;
+
+ delete [] _charBuffer;
+ _charBuffer = 0;
+
+#if 0
+ _textPool.Trace( "text" );
+ _elementPool.Trace( "element" );
+ _commentPool.Trace( "comment" );
+ _attributePool.Trace( "attribute" );
+#endif
+
+#ifdef DEBUG
+ if ( !hadError ) {
+ TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
+ TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
+ TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
+ TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
+ }
+#endif
+}
+
+
+XMLElement* XMLDocument::NewElement( const char* name )
+{
+ TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
+ XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
+ ele->_memPool = &_elementPool;
+ ele->SetName( name );
+ return ele;
+}
+
+
+XMLComment* XMLDocument::NewComment( const char* str )
+{
+ TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
+ XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
+ comment->_memPool = &_commentPool;
+ comment->SetValue( str );
+ return comment;
+}
+
+
+XMLText* XMLDocument::NewText( const char* str )
+{
+ TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
+ XMLText* text = new (_textPool.Alloc()) XMLText( this );
+ text->_memPool = &_textPool;
+ text->SetValue( str );
+ return text;
+}
+
+
+XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
+{
+ TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
+ XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
+ dec->_memPool = &_commentPool;
+ dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
+ return dec;
+}
+
+
+XMLUnknown* XMLDocument::NewUnknown( const char* str )
+{
+ TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
+ XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
+ unk->_memPool = &_commentPool;
+ unk->SetValue( str );
+ return unk;
+}
+
+static FILE* callfopen( const char* filepath, const char* mode )
+{
+ TIXMLASSERT( filepath );
+ TIXMLASSERT( mode );
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
+ FILE* fp = 0;
+ errno_t err = fopen_s( &fp, filepath, mode );
+ if ( err ) {
+ return 0;
+ }
+#else
+ FILE* fp = fopen( filepath, mode );
+#endif
+ return fp;
+}
+
+void XMLDocument::DeleteNode( XMLNode* node ) {
+ TIXMLASSERT( node );
+ TIXMLASSERT(node->_document == this );
+ if (node->_parent) {
+ node->_parent->DeleteChild( node );
+ }
+ else {
+ // Isn't in the tree.
+ // Use the parent delete.
+ // Also, we need to mark it tracked: we 'know'
+ // it was never used.
+ node->_memPool->SetTracked();
+ // Call the static XMLNode version:
+ XMLNode::DeleteNode(node);
+ }
+}
+
+
+XMLError XMLDocument::LoadFile( const char* filename )
+{
+ Clear();
+ FILE* fp = callfopen( filename, "rb" );
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
+ return _errorID;
+ }
+ LoadFile( fp );
+ fclose( fp );
+ return _errorID;
+}
+
+// This is likely overengineered template art to have a check that unsigned long value incremented
+// by one still fits into size_t. If size_t type is larger than unsigned long type
+// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
+// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
+// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
+// types sizes relate to each other.
+template
+<bool = (sizeof(unsigned long) >= sizeof(size_t))>
+struct LongFitsIntoSizeTMinusOne {
+ static bool Fits( unsigned long value )
+ {
+ return value < (size_t)-1;
+ }
+};
+
+template <>
+bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
+{
+ return true;
+}
+
+XMLError XMLDocument::LoadFile( FILE* fp )
+{
+ Clear();
+
+ fseek( fp, 0, SEEK_SET );
+ if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ fseek( fp, 0, SEEK_END );
+ const long filelength = ftell( fp );
+ fseek( fp, 0, SEEK_SET );
+ if ( filelength == -1L ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
+ // Cannot handle files which won't fit in buffer together with null terminator
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ if ( filelength == 0 ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return _errorID;
+ }
+
+ const size_t size = filelength;
+ TIXMLASSERT( _charBuffer == 0 );
+ _charBuffer = new char[size+1];
+ size_t read = fread( _charBuffer, 1, size, fp );
+ if ( read != size ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
+ _charBuffer[size] = 0;
+
+ Parse();
+ return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( const char* filename, bool compact )
+{
+ FILE* fp = callfopen( filename, "w" );
+ if ( !fp ) {
+ SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
+ return _errorID;
+ }
+ SaveFile(fp, compact);
+ fclose( fp );
+ return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
+{
+ // Clear any error from the last save, otherwise it will get reported
+ // for *this* call.
+ SetError( XML_NO_ERROR, 0, 0 );
+ XMLPrinter stream( fp, compact );
+ Print( &stream );
+ return _errorID;
+}
+
+
+XMLError XMLDocument::Parse( const char* p, size_t len )
+{
+ Clear();
+
+ if ( len == 0 || !p || !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return _errorID;
+ }
+ if ( len == (size_t)(-1) ) {
+ len = strlen( p );
+ }
+ TIXMLASSERT( _charBuffer == 0 );
+ _charBuffer = new char[ len+1 ];
+ memcpy( _charBuffer, p, len );
+ _charBuffer[len] = 0;
+
+ Parse();
+ if ( Error() ) {
+ // clean up now essentially dangling memory.
+ // and the parse fail can put objects in the
+ // pools that are dead and inaccessible.
+ DeleteChildren();
+ _elementPool.Clear();
+ _attributePool.Clear();
+ _textPool.Clear();
+ _commentPool.Clear();
+ }
+ return _errorID;
+}
+
+
+void XMLDocument::Print( XMLPrinter* streamer ) const
+{
+ if ( streamer ) {
+ Accept( streamer );
+ }
+ else {
+ XMLPrinter stdoutStreamer( stdout );
+ Accept( &stdoutStreamer );
+ }
+}
+
+
+void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
+{
+ TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
+ _errorID = error;
+ _errorStr1 = str1;
+ _errorStr2 = str2;
+}
+
+const char* XMLDocument::ErrorName() const
+{
+ TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
+ const char* errorName = _errorNames[_errorID];
+ TIXMLASSERT( errorName && errorName[0] );
+ return errorName;
+}
+
+void XMLDocument::PrintError() const
+{
+ if ( Error() ) {
+ static const int LEN = 20;
+ char buf1[LEN] = { 0 };
+ char buf2[LEN] = { 0 };
+
+ if ( _errorStr1 ) {
+ TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
+ }
+ if ( _errorStr2 ) {
+ TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
+ }
+
+ // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
+ // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
+ TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
+ printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
+ static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
+ }
+}
+
+void XMLDocument::Parse()
+{
+ TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
+ TIXMLASSERT( _charBuffer );
+ char* p = _charBuffer;
+ p = XMLUtil::SkipWhiteSpace( p );
+ p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
+ if ( !*p ) {
+ SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return;
+ }
+ ParseDeep(p, 0 );
+}
+
+XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
+ _elementJustOpened( false ),
+ _firstElement( true ),
+ _fp( file ),
+ _depth( depth ),
+ _textDepth( -1 ),
+ _processEntities( true ),
+ _compactMode( compact )
+{
+ for( int i=0; i<ENTITY_RANGE; ++i ) {
+ _entityFlag[i] = false;
+ _restrictedEntityFlag[i] = false;
+ }
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ const char entityValue = entities[i].value;
+ TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
+ _entityFlag[ (unsigned char)entityValue ] = true;
+ }
+ _restrictedEntityFlag[(unsigned char)'&'] = true;
+ _restrictedEntityFlag[(unsigned char)'<'] = true;
+ _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
+ _buffer.Push( 0 );
+}
+
+
+void XMLPrinter::Print( const char* format, ... )
+{
+ va_list va;
+ va_start( va, format );
+
+ if ( _fp ) {
+ vfprintf( _fp, format, va );
+ }
+ else {
+ const int len = TIXML_VSCPRINTF( format, va );
+ // Close out and re-start the va-args
+ va_end( va );
+ TIXMLASSERT( len >= 0 );
+ va_start( va, format );
+ TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
+ char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
+ TIXML_VSNPRINTF( p, len+1, format, va );
+ }
+ va_end( va );
+}
+
+
+void XMLPrinter::PrintSpace( int depth )
+{
+ for( int i=0; i<depth; ++i ) {
+ Print( " " );
+ }
+}
+
+
+void XMLPrinter::PrintString( const char* p, bool restricted )
+{
+ // Look for runs of bytes between entities to print.
+ const char* q = p;
+
+ if ( _processEntities ) {
+ const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
+ while ( *q ) {
+ TIXMLASSERT( p <= q );
+ // Remember, char is sometimes signed. (How many times has that bitten me?)
+ if ( *q > 0 && *q < ENTITY_RANGE ) {
+ // Check for entities. If one is found, flush
+ // the stream up until the entity, write the
+ // entity, and keep looking.
+ if ( flag[(unsigned char)(*q)] ) {
+ while ( p < q ) {
+ const size_t delta = q - p;
+ // %.*s accepts type int as "precision"
+ const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
+ Print( "%.*s", toPrint, p );
+ p += toPrint;
+ }
+ bool entityPatternPrinted = false;
+ for( int i=0; i<NUM_ENTITIES; ++i ) {
+ if ( entities[i].value == *q ) {
+ Print( "&%s;", entities[i].pattern );
+ entityPatternPrinted = true;
+ break;
+ }
+ }
+ if ( !entityPatternPrinted ) {
+ // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
+ TIXMLASSERT( false );
+ }
+ ++p;
+ }
+ }
+ ++q;
+ TIXMLASSERT( p <= q );
+ }
+ }
+ // Flush the remaining string. This will be the entire
+ // string if an entity wasn't found.
+ TIXMLASSERT( p <= q );
+ if ( !_processEntities || ( p < q ) ) {
+ Print( "%s", p );
+ }
+}
+
+
+void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
+{
+ if ( writeBOM ) {
+ static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
+ Print( "%s", bom );
+ }
+ if ( writeDec ) {
+ PushDeclaration( "xml version=\"1.0\"" );
+ }
+}
+
+
+void XMLPrinter::OpenElement( const char* name, bool compactMode )
+{
+ SealElementIfJustOpened();
+ _stack.Push( name );
+
+ if ( _textDepth < 0 && !_firstElement && !compactMode ) {
+ Print( "\n" );
+ }
+ if ( !compactMode ) {
+ PrintSpace( _depth );
+ }
+
+ Print( "<%s", name );
+ _elementJustOpened = true;
+ _firstElement = false;
+ ++_depth;
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, const char* value )
+{
+ TIXMLASSERT( _elementJustOpened );
+ Print( " %s=\"", name );
+ PrintString( value, false );
+ Print( "\"" );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::CloseElement( bool compactMode )
+{
+ --_depth;
+ const char* name = _stack.Pop();
+
+ if ( _elementJustOpened ) {
+ Print( "/>" );
+ }
+ else {
+ if ( _textDepth < 0 && !compactMode) {
+ Print( "\n" );
+ PrintSpace( _depth );
+ }
+ Print( "</%s>", name );
+ }
+
+ if ( _textDepth == _depth ) {
+ _textDepth = -1;
+ }
+ if ( _depth == 0 && !compactMode) {
+ Print( "\n" );
+ }
+ _elementJustOpened = false;
+}
+
+
+void XMLPrinter::SealElementIfJustOpened()
+{
+ if ( !_elementJustOpened ) {
+ return;
+ }
+ _elementJustOpened = false;
+ Print( ">" );
+}
+
+
+void XMLPrinter::PushText( const char* text, bool cdata )
+{
+ _textDepth = _depth-1;
+
+ SealElementIfJustOpened();
+ if ( cdata ) {
+ Print( "<![CDATA[%s]]>", text );
+ }
+ else {
+ PrintString( text, true );
+ }
+}
+
+void XMLPrinter::PushText( int value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( unsigned value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( bool value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( float value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( double value )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( value, buf, BUF_SIZE );
+ PushText( buf, false );
+}
+
+
+void XMLPrinter::PushComment( const char* comment )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Print( "\n" );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+ Print( "<!--%s-->", comment );
+}
+
+
+void XMLPrinter::PushDeclaration( const char* value )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Print( "\n" );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+ Print( "<?%s?>", value );
+}
+
+
+void XMLPrinter::PushUnknown( const char* value )
+{
+ SealElementIfJustOpened();
+ if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+ Print( "\n" );
+ PrintSpace( _depth );
+ }
+ _firstElement = false;
+ Print( "<!%s>", value );
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLDocument& doc )
+{
+ _processEntities = doc.ProcessEntities();
+ if ( doc.HasBOM() ) {
+ PushHeader( true, false );
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
+{
+ const XMLElement* parentElem = 0;
+ if ( element.Parent() ) {
+ parentElem = element.Parent()->ToElement();
+ }
+ const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
+ OpenElement( element.Name(), compactMode );
+ while ( attribute ) {
+ PushAttribute( attribute->Name(), attribute->Value() );
+ attribute = attribute->Next();
+ }
+ return true;
+}
+
+
+bool XMLPrinter::VisitExit( const XMLElement& element )
+{
+ CloseElement( CompactMode(element) );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLText& text )
+{
+ PushText( text.Value(), text.CData() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLComment& comment )
+{
+ PushComment( comment.Value() );
+ return true;
+}
+
+bool XMLPrinter::Visit( const XMLDeclaration& declaration )
+{
+ PushDeclaration( declaration.Value() );
+ return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLUnknown& unknown )
+{
+ PushUnknown( unknown.Value() );
+ return true;
+}
+
+} // namespace tinyxml2
+
diff --git a/hw3/src/transformation3d.cpp b/hw3/src/transformation3d.cpp
new file mode 100644
index 0000000..bde9caa
--- /dev/null
+++ b/hw3/src/transformation3d.cpp
@@ -0,0 +1,174 @@
+/******************************************************************/
+/* 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 "transformation3d.h"
+
+
+//////////////////
+// Constructors //
+//////////////////
+transformation3d::transformation3d(void)
+{
+ _translation = vec3d();
+ _transformation = mat3d(1.0f);
+ _inverseTransformation = mat3d(1.0f);
+}
+
+
+transformation3d::transformation3d(const vec3d& translation, const mat3d& transformation, const mat3d& inverseTransformation)
+{
+ _translation = translation;
+ _transformation = transformation;
+ _inverseTransformation = inverseTransformation;
+}
+
+
+transformation3d::transformation3d(const transformation3d& t)
+{
+ _translation = t._translation;
+ _transformation = t._transformation;
+ _inverseTransformation = t._inverseTransformation;
+}
+
+
+//////////////
+// Operator //
+//////////////
+transformation3d& transformation3d::operator=(const transformation3d& t)
+{
+ _assign(t);
+ return *this;
+}
+
+
+transformation3d transformation3d::operator*(const transformation3d& t) const
+{
+ return transformation3d( transformPoint(t._translation),
+ _transformation * t._transformation,
+ t._inverseTransformation * _inverseTransformation);
+}
+
+
+transformation3d& transformation3d::operator*=(const transformation3d& t)
+{
+ *this = *this * t;
+ return *this;
+}
+
+
+//////////////
+// Mutators //
+//////////////
+transformation3d& transformation3d::invert(void)
+{
+ _translation = _inverseTransformation * (-_translation);
+ swap(_transformation, _inverseTransformation);
+ return *this;
+}
+
+/////////////
+// Methods //
+/////////////
+vec3d transformation3d::transformPoint(const vec3d& p) const
+{
+ // first transform, then translate
+ vec3d transformed = _transformation * p;
+ transformed += _translation;
+
+ // Done.
+ return transformed;
+}
+
+
+vec3d transformation3d::transformDirection(const vec3d& d) const
+{
+ // Only apply transformation
+ vec3d transformed = _transformation * d;
+
+ // Done.
+ return transformed.normalize();
+}
+
+
+vec3d transformation3d::transformNormal(const vec3d& n) const
+{
+ // Don't apply translation.
+ // n' = (_transformation^T)^-1 * n
+ // n'^T = n^T * _transformation^-1
+ // n'^T = n^T * _inverseTransformation
+ vec3d transformed = n * _inverseTransformation;
+
+ // Done.
+ return transformed.normalize();
+}
+
+
+vec3d transformation3d::inverseTransformPoint(const vec3d& p) const
+{
+ // for undo translation, then invert the transformation
+ vec3d transformed = p - _translation;
+ transformed = _inverseTransformation * transformed;
+
+ // Done.
+ return transformed;
+}
+
+
+vec3d transformation3d::inverseTransformDirection(const vec3d& d) const
+{
+ // Only invert the transformation
+ vec3d transformed = _inverseTransformation * d;
+
+ // Done.
+ return transformed.normalize();
+}
+
+
+vec3d transformation3d::inverseTransformNormal(const vec3d& n) const
+{
+ // Don't apply translation. Undo (transformation^T)^-1
+ vec3d transformed = n * _transformation;
+
+ // Done.
+ return transformed.normalize();
+}
+
+
+///////////////////////
+// Protected Methods //
+///////////////////////
+void transformation3d::_swap(transformation3d& t)
+{
+ std::swap(_translation, t._translation);
+ std::swap(_transformation, t._transformation);
+ std::swap(_inverseTransformation, t._inverseTransformation);
+}
+
+
+void transformation3d::_assign(const transformation3d& t)
+{
+ // avoid copying when self-assigning
+ if(&t == this) return;
+
+ // Copy
+ _translation = t._translation;
+ _transformation = t._transformation;
+ _inverseTransformation = t._inverseTransformation;
+
+ // Done.
+}
+
+
+void transformation3d::_print(std::ostream& s) const
+{
+ s << "{";
+ s << "Translation = " << _translation << ", ";
+ s << "Transformation = " << _transformation << ", ";
+ s << "Inverse Trans. = " << _inverseTransformation;
+ s << "}";
+}
diff --git a/hw3/src/triangle.cpp b/hw3/src/triangle.cpp
new file mode 100644
index 0000000..3abe113
--- /dev/null
+++ b/hw3/src/triangle.cpp
@@ -0,0 +1,465 @@
+/******************************************************************/
+/* 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 <algorithm>
+
+#include "triangle.h"
+#include "constants.h"
+
+//////////////////
+// Constructors //
+//////////////////
+triangle::triangle(void)
+{
+ _vertex_list = nullptr;
+ _normal_list = nullptr;
+ _textureCoord_list = nullptr;
+}
+
+
+//////////////////////
+// Copy Constructor //
+//////////////////////
+triangle::triangle(const triangle& t)
+ : triangle()
+{
+ // share ptr to list
+ _vertex_list = t._vertex_list;
+ _normal_list = t._normal_list;
+ _textureCoord_list = t._textureCoord_list;
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+//////////////////////
+// Move Constructor //
+//////////////////////
+triangle::triangle(triangle&& t)
+ : triangle()
+{
+ // swap list (no need to increment ref-count)
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+//////////////////////////
+// General Constructors //
+//////////////////////////
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3)
+ : triangle()
+{
+ // create a list of three vertices
+ auto vertex_list = std::make_shared<std::vector<vec3d>>(3);
+ _vertex_list = vertex_list;
+
+ // copy values
+ (*vertex_list)[0] = v1;
+ (*vertex_list)[1] = v2;
+ (*vertex_list)[2] = v3;
+
+ // set indices
+ _vertex_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list)
+ : triangle()
+{
+ // share vertex list
+ _vertex_list = vertex_list;
+
+ // copy indices
+ _vertex_idx[0] = v1_idx;
+ _vertex_idx[1] = v2_idx;
+ _vertex_idx[2] = v3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3)
+ : triangle(v1, v2, v3)
+{
+ // create a list of three normals
+ auto normal_list = std::make_shared<std::vector<vec3d>>(3);
+ _normal_list = normal_list;
+
+ // copy values
+ (*normal_list)[0] = n1;
+ (*normal_list)[1] = n2;
+ (*normal_list)[2] = n3;
+
+ // set indices
+ _normal_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list)
+{
+ // share normal list
+ _normal_list = normal_list;
+
+ // copy indices
+ _normal_idx[0] = n1_idx;
+ _normal_idx[1] = n2_idx;
+ _normal_idx[2] = n3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3)
+ : triangle(v1, v2, v3)
+{
+ // create a list of three texture coordinates
+ auto textureCoord_list = std::make_shared<std::vector<vec2d>>(3);
+ _textureCoord_list = textureCoord_list;
+
+ // copy values
+ (*textureCoord_list)[0] = t1;
+ (*textureCoord_list)[1] = t2;
+ (*textureCoord_list)[2] = t3;
+
+ // set indices
+ _textureCoord_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list)
+{
+ // share normal list
+ _textureCoord_list = texcoord_list;
+
+ // copy indices
+ _textureCoord_idx[0] = t1_idx;
+ _textureCoord_idx[1] = t2_idx;
+ _textureCoord_idx[2] = t3_idx;
+}
+
+
+
+triangle::triangle(const vec3d& v1, const vec3d& v2, const vec3d& v3,
+ const vec3d& n1, const vec3d& n2, const vec3d& n3,
+ const vec2d& t1, const vec2d& t2, const vec2d& t3)
+ : triangle(v1, v2, v3, n1, n2, n3)
+{
+ // create a list of three texture coordinates
+ auto textureCoord_list = std::make_shared<std::vector<vec2d>>(3);
+ _textureCoord_list = textureCoord_list;
+
+ // copy values
+ (*textureCoord_list)[0] = t1;
+ (*textureCoord_list)[1] = t2;
+ (*textureCoord_list)[2] = t3;
+
+ // set indices
+ _textureCoord_idx = {0,1,2};
+}
+
+
+triangle::triangle(size_t v1_idx, size_t v2_idx, size_t v3_idx, const std::shared_ptr<const std::vector<vec3d>>& vertex_list,
+ size_t n1_idx, size_t n2_idx, size_t n3_idx, const std::shared_ptr<const std::vector<vec3d>>& normal_list,
+ size_t t1_idx, size_t t2_idx, size_t t3_idx, const std::shared_ptr<const std::vector<vec2d>>& texcoord_list)
+ : triangle(v1_idx, v2_idx, v3_idx, vertex_list,
+ n1_idx, n2_idx, n3_idx, normal_list)
+{
+ // share normal list
+ _textureCoord_list = texcoord_list;
+
+ // copy indices
+ _textureCoord_idx[0] = t1_idx;
+ _textureCoord_idx[1] = t2_idx;
+ _textureCoord_idx[2] = t3_idx;
+}
+
+
+
+////////////////
+// Inspectors //
+////////////////
+const vec3d& triangle::vertex(size_t index) const
+{
+ // bounds check
+ assert(_vertex_list && index < 3);
+
+ // Done.
+ return (*_vertex_list)[_vertex_idx[index]];
+}
+
+
+const vec3d& triangle::normal(size_t index) const
+{
+ // bounds check
+ assert(_normal_list && index < 3);
+
+ // Done.
+ return (*_normal_list)[_normal_idx[index]];
+}
+
+
+const vec2d& triangle::textureCoordinate(size_t index) const
+{
+ // bounds check
+ assert(_textureCoord_list && index < 3);
+
+ // Done.
+ return (*_textureCoord_list)[_textureCoord_idx[index]];
+}
+
+
+bool triangle::hasPerVertexNormals(void) const
+{
+ return (bool)(_normal_list);
+}
+
+
+bool triangle::hasPerVertexTextureCoordinates(void) const
+{
+ return (bool)(_textureCoord_list);
+}
+
+
+///////////////
+// Operators //
+///////////////
+triangle& triangle::operator=(const triangle& t)
+{
+ _assign(t);
+ return *this;
+}
+
+
+triangle& triangle::operator=(triangle&& t)
+{
+ // swap list (no need to increment ref-count)
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+
+ // Done.
+ return *this;
+}
+
+
+/////////////
+// Methods //
+/////////////
+bool triangle::intersect(const ray& r, vec3d& barycentricCoord, float& t) const
+{
+ // Ray-Triangle intersection [Moller and Trumbore 1997]
+ //
+ // [t ] 1 [ ((r.origin-v0) x (v1-v0)).(v2-v0) ]
+ // [barycenter.y] = -------------------------- [ (r.dir x (v2-v0)).(r.origin-v0) ]
+ // [barycenter.z] ((r.dir x (v2-vo)).(v1-v0) [ ((r.origin-v0) x (v1-v0)).r.dir ]
+ //
+
+ // compute denominator
+ vec3d e1 = vertex(1) - vertex(0);
+ vec3d e2 = vertex(2) - vertex(0);
+ vec3d p = r.direction().cross(e2);
+ float denom = p.dot(e1);
+
+ // check if parallel (denominator == 0)
+ if(fabs(denom) < EPSILON) return false;
+ denom = 1.0f / denom;
+
+ // compute barycentricCoord.y
+ vec3d diff = r.origin() - vertex(0);
+ barycentricCoord.y = denom * p.dot(diff);
+
+ // check if barycenter.y inside triangle
+ if(barycentricCoord.y < -EPSILON || barycentricCoord.y > 1.0f+EPSILON) return false;
+
+ // compute barycentricCoord.z
+ vec3d diffXe1 = diff.cross(e1);
+ barycentricCoord.z = denom * diffXe1.dot(r.direction());
+
+ // check if barycenter.z inside triangle
+ if(barycentricCoord.z < -EPSILON || barycentricCoord.z > 1.0f+EPSILON) return false;
+
+ // compute barycenter.x and check if inside
+ barycentricCoord.x = 1.0f - barycentricCoord.y - barycentricCoord.z;
+ if(barycentricCoord.y + barycentricCoord.z > 1.0f+EPSILON) return false;
+
+ // compute t
+ t = denom * diffXe1.dot(e2);
+
+ // check if in front (i.e., t>0)
+ if(t < EPSILON) return false;
+
+ // Clamp (to compensate for roundoff errors)
+ barycentricCoord.clamp(0.0f, 1.0f);
+
+ // Done.
+ return true;
+}
+
+
+boundingBox triangle::boundingbox(void) const
+{
+ boundingBox bb;
+ for(unsigned int i=0; i < 3; i++)
+ bb += vertex(i);
+ return bb;
+}
+
+
+vec3d triangle::vertex(const vec3d& barycentricCoord) const
+{
+ vec3d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += vertex(i) * barycentricCoord[i];
+ return result;
+}
+
+
+vec3d triangle::normal(void) const
+{
+ vec3d e1 = vertex(1) - vertex(0);
+ vec3d e2 = vertex(2) - vertex(0);
+ return e1.cross(e2).normalize();
+}
+
+vec3d triangle::shadingAxis(void) const
+{
+ // follow texture coordinates if defined, otherwise, return the first axis.
+ if(!_textureCoord_list) return normalize(vertex(1)-vertex(0));
+
+ // find the vector that follows the U-axis of the texture coordinates
+ // solve:
+ // [ (t1-t0) (t2-t0) ] [ delta_beta delta_gamma ]^T = [1 0]^T
+ // for delta_beta and delta_gamma.
+ vec3d v1 = vertex(1) - vertex(0);
+ vec3d v2 = vertex(2) - vertex(0);
+ vec2d t1 = textureCoordinate(1) - textureCoordinate(0);
+ vec2d t2 = textureCoordinate(2) - textureCoordinate(0);
+
+ // check special cases where U or V is aligned with a vertex
+ if( fabs(t1.v) < EPSILON ) return normalize(t1.u*v1);
+ if( fabs(t2.v) < EPSILON ) return normalize(t2.u*v2);
+
+ // compute delta_beta
+ float inv_delta_beta = t1.u - t1.v*t2.u/t2.v;
+
+ // => degenrate case
+ if(fabs(inv_delta_beta) < EPSILON) return normalize(v1);
+
+ float delta_beta = 1.0f / inv_delta_beta;
+ float delta_gamma = -delta_beta * t1.v / t2.v;
+
+ // compute U
+ return normalize( delta_beta*v1 + delta_gamma*v2 );
+}
+
+
+vec3d triangle::normal(const vec3d& barycentricCoord) const
+{
+ // sanity check
+ if(!hasPerVertexNormals()) return normal();
+
+ // interpolate
+ vec3d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += normal(i) * barycentricCoord[i];
+ return result.normalize();
+}
+
+
+vec2d triangle::textureCoordinate(const vec3d& barycentricCoord) const
+{
+ // sanity check
+ if(!hasPerVertexTextureCoordinates()) return vec2d();
+
+ // interpolate
+ vec2d result(0.0f);
+ for(unsigned int i=0; i < 3; i++)
+ result += textureCoordinate(i) * barycentricCoord[i];
+ return result;
+}
+
+
+float triangle::area(void) const
+{
+ vec3d e1 = vertex(1) - vertex(0);
+ vec3d e2 = vertex(2) - vertex(0);
+ return 0.5f * sqrt( e1.squared_length() * e2.squared_length() );
+}
+
+
+vec3d triangle::sample(float r1, float r2, vec3d& barycentricCoord, float& pdf) const
+{
+ r2 = sqrt(r2);
+
+ // compute barycentric coordinate
+ barycentricCoord.x = r1*r2;
+ barycentricCoord.y = (1.0f - r2);
+ barycentricCoord.z = 1.0f - barycentricCoord.x - barycentricCoord.y;
+
+ // compute pdf
+ pdf = 1.0f / area();
+
+ // Done.
+ return vertex(barycentricCoord);
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void triangle::_assign(const triangle& t)
+{
+ // avoid self-assign
+ if(&t == this) return;
+
+ // share ptr to list
+ _vertex_list = t._vertex_list;
+ _normal_list = t._normal_list;
+ _textureCoord_list = t._textureCoord_list;
+
+ // copy indices
+ _vertex_idx = t._vertex_idx;
+ _normal_idx = t._normal_idx;
+ _textureCoord_idx = t._textureCoord_idx;
+}
+
+
+void triangle::_swap(triangle& t)
+{
+ // copy list ptr
+ std::swap(_vertex_list, t._vertex_list);
+ std::swap(_normal_list, t._normal_list);
+ std::swap(_textureCoord_list, t._textureCoord_list);
+
+ // copy indices
+ std::swap(_vertex_idx, t._vertex_idx);
+ std::swap(_normal_idx, t._normal_idx);
+ std::swap(_textureCoord_idx, t._textureCoord_idx);
+}
+
diff --git a/hw3/src/triangleMesh.cpp b/hw3/src/triangleMesh.cpp
new file mode 100644
index 0000000..5507a9c
--- /dev/null
+++ b/hw3/src/triangleMesh.cpp
@@ -0,0 +1,57 @@
+/******************************************************************/
+/* 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 <algorithm>
+#include "triangleMesh.h"
+
+/////////////////
+// Constructors //
+//////////////////
+triangleMesh::triangleMesh(void)
+ : boundedCompound()
+{
+ // Nothing.
+}
+
+
+triangleMesh::triangleMesh(const std::vector<triangle>& triangle_list, const std::shared_ptr<const shader_base>& shader, const transformation3d& transform)
+ : boundedCompound(transform, shader)
+{
+ // allocate sufficient memory
+ _triangles.reserve(triangle_list.size());
+
+ // construct vector of boundedTriangles
+ for_each(triangle_list.begin(), triangle_list.end(), [&](const triangle& tri)
+ {
+ _triangles.push_back( std::make_shared<boundedTriangle>(tri, shader) );
+ });
+
+ // Done.
+ initializeBoundingBox();
+}
+
+
+/////////////
+// Methods //
+/////////////
+const std::vector<std::shared_ptr<const boundedPrimitive>>& triangleMesh::compounds(void) const
+{
+ return _triangles;
+}
+
+
+bool triangleMesh::hasShader(void) const
+{
+ return boundedPrimitive::hasShader();
+}
+
+
+void triangleMesh::_print(std::ostream& s) const
+{
+ s << "triangleMesh (" << _bb << ", " << _triangles.size() << " compounds)";
+}
diff --git a/hw3/src/util.cpp b/hw3/src/util.cpp
new file mode 100644
index 0000000..917eef4
--- /dev/null
+++ b/hw3/src/util.cpp
@@ -0,0 +1,45 @@
+/******************************************************************/
+/* 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 "util.h"
+
+
+std::string getFilename(const std::string& path)
+{
+#ifdef _WIN32
+ unsigned char pathSep = '\\';
+#else
+ unsigned char pathSep = '/';
+#endif
+ size_t start = path.find_last_of(pathSep);
+ size_t end = path.find_last_of(".");
+ if(start == std::string::npos) start = -1;
+ if(end == std::string::npos) end = path.size();
+ return path.substr(start+1, end-start-1);
+}
+
+
+std::string getExtension(const std::string& path)
+{
+ size_t lastidx = path.find_last_of(".");
+ if(lastidx == std::string::npos) return std::string();
+ else return path.substr(lastidx+1, std::string::npos);
+}
+
+
+std::string getDirectory(const std::string& path)
+{
+#ifdef _WIN32
+ unsigned char pathSep = '\\';
+#else
+ unsigned char pathSep = '/';
+#endif
+ size_t lastidx = path.find_last_of(pathSep);
+ if(lastidx == std::string::npos) return std::string();
+ return path.substr(0, lastidx+1);
+}
diff --git a/hw3/src/vec2d.cpp b/hw3/src/vec2d.cpp
new file mode 100644
index 0000000..ae12e41
--- /dev/null
+++ b/hw3/src/vec2d.cpp
@@ -0,0 +1,258 @@
+/******************************************************************/
+/* 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 <algorithm>
+#include "vec2d.h"
+
+//////////////////
+// Constructors //
+//////////////////
+vec2d::vec2d(vec2d::const_reference value)
+{
+ x = y = value;
+}
+
+
+vec2d::vec2d(vec2d::const_reference x, vec2d::const_reference y)
+{
+ this->x = x;
+ this->y = y;
+}
+
+
+vec2d::vec2d(const vec2d& v)
+{
+ x = v.x;
+ y = v.y;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+vec2d::const_reference vec2d::operator[](size_t index) const
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+vec2d::reference vec2d::operator[](size_t index)
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+vec2d::iterator vec2d::begin(void)
+{
+ return data;
+}
+
+
+vec2d::const_iterator vec2d::begin(void) const
+{
+ return data;
+}
+
+
+vec2d::iterator vec2d::end(void)
+{
+ return begin() + size();
+}
+
+
+vec2d::const_iterator vec2d::end(void) const
+{
+ return begin() + size();
+}
+
+
+///////////////
+// Operators //
+///////////////
+vec2d& vec2d::operator=(const vec2d& v)
+{
+ _assign(v);
+ return *this;
+}
+
+
+bool vec2d::operator==(const vec2d& v) const
+{
+ return (x == v.x) && (y == v.y);
+}
+
+
+bool vec2d::operator!=(const vec2d& v) const
+{
+ return (x != v.x) || (y != v.y);
+}
+
+
+vec2d vec2d::operator-(void) const
+{
+ return vec2d(-x, -y);
+}
+
+
+vec2d vec2d::operator+(const vec2d& v) const
+{
+ return vec2d(x + v.x, y + v.y);
+}
+
+
+vec2d vec2d::operator-(const vec2d& v) const
+{
+ return vec2d(x - v.x, y - v.y);
+}
+
+
+vec2d vec2d::operator*(const vec2d& v) const
+{
+ return vec2d(x * v.x, y * v.y);
+}
+
+
+vec2d vec2d::operator*(vec2d::const_reference scale) const
+{
+ return vec2d(x * scale, y * scale);
+}
+
+
+vec2d vec2d::operator/(const vec2d& v) const
+{
+ return vec2d(x / v.x, y / v.y);
+}
+
+
+vec2d vec2d::operator/(vec2d::const_reference scale) const
+{
+ return vec2d(x / scale, y / scale);
+}
+
+
+vec2d& vec2d::operator+=(const vec2d& v)
+{
+ x += v.x;
+ y += v.y;
+ return *this;
+}
+
+
+vec2d& vec2d::operator-=(const vec2d& v)
+{
+ x -= v.x;
+ y -= v.y;
+ return *this;
+}
+
+
+vec2d& vec2d::operator*=(const vec2d& v)
+{
+ x *= v.x;
+ y *= v.y;
+ return *this;
+}
+
+
+vec2d& vec2d::operator*=(vec2d::const_reference scale)
+{
+ x *= scale;
+ y *= scale;
+ return *this;
+}
+
+
+vec2d& vec2d::operator/=(const vec2d& v)
+{
+ x /= v.x;
+ y /= v.y;
+ return *this;
+}
+
+
+vec2d& vec2d::operator/=(vec2d::const_reference scale)
+{
+ x /= scale;
+ y /= scale;
+ return *this;
+}
+
+
+
+///////////////
+// Modifiers //
+///////////////
+vec2d::value_type vec2d::dot(const vec2d& v) const
+{
+ return (x*v.x + y*v.y);
+}
+
+
+vec2d::value_type vec2d::squared_length(void) const
+{
+ return dot(*this);
+}
+
+
+vec2d::value_type vec2d::length(void) const
+{
+ return sqrt(squared_length());
+}
+
+
+vec2d::value_type vec2d::squared_distance(const vec2d& v) const
+{
+ return (*this - v).squared_length();
+}
+
+
+vec2d::value_type vec2d::distance(const vec2d& v) const
+{
+ return sqrt(squared_distance(v));
+}
+
+
+///////////////
+// Modifiers //
+///////////////
+vec2d& vec2d::abs(void)
+{
+ std::for_each(begin(), end(), [](reference val)
+ {
+ if(val < 0) val = -val;
+ });
+ return *this;
+}
+
+
+vec2d& vec2d::normalize(void)
+{
+ *this /= length();
+ return *this;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void vec2d::_assign(const vec2d& v)
+{
+ x = v.x;
+ y = v.y;
+}
+
+
+void vec2d::_swap(vec2d& v)
+{
+ std::swap(x, v.x);
+ std::swap(y, v.y);
+}
diff --git a/hw3/src/vec3d.cpp b/hw3/src/vec3d.cpp
new file mode 100644
index 0000000..3b20ad5
--- /dev/null
+++ b/hw3/src/vec3d.cpp
@@ -0,0 +1,287 @@
+/******************************************************************/
+/* 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 <algorithm>
+#include "vec3d.h"
+
+//////////////////
+// Constructors //
+//////////////////
+vec3d::vec3d(vec3d::const_reference value)
+{
+ x = y = z = value;
+}
+
+
+vec3d::vec3d(vec3d::const_reference x, vec3d::const_reference y, vec3d::const_reference z)
+{
+ this->x = x;
+ this->y = y;
+ this->z = z;
+}
+
+
+vec3d::vec3d(const vec3d& v)
+{
+ x = v.x;
+ y = v.y;
+ z = v.z;
+}
+
+
+////////////////
+// Inspectors //
+////////////////
+vec3d::const_reference vec3d::operator[](size_t index) const
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+vec3d::reference vec3d::operator[](size_t index)
+{
+ assert(index < size());
+ return data[index];
+}
+
+
+vec3d::iterator vec3d::begin(void)
+{
+ return data;
+}
+
+
+vec3d::const_iterator vec3d::begin(void) const
+{
+ return data;
+}
+
+
+vec3d::iterator vec3d::end(void)
+{
+ return begin() + size();
+}
+
+
+vec3d::const_iterator vec3d::end(void) const
+{
+ return begin() + size();
+}
+
+
+///////////////
+// Operators //
+///////////////
+vec3d& vec3d::operator=(const vec3d& v)
+{
+ _assign(v);
+ return *this;
+}
+
+
+bool vec3d::operator==(const vec3d& v) const
+{
+ return (x == v.x) && (y == v.y) && (z == v.z);
+}
+
+
+bool vec3d::operator!=(const vec3d& v) const
+{
+ return (x != v.x) || (y != v.y) || (z != v.z);
+}
+
+
+vec3d vec3d::operator-(void) const
+{
+ return vec3d(-x, -y, -z);
+}
+
+
+vec3d vec3d::operator+(const vec3d& v) const
+{
+ return vec3d(x + v.x, y + v.y, z + v.z);
+}
+
+
+vec3d vec3d::operator-(const vec3d& v) const
+{
+ return vec3d(x - v.x, y - v.y, z - v.z);
+}
+
+
+vec3d vec3d::operator*(const vec3d& v) const
+{
+ return vec3d(x * v.x, y * v.y, z * v.z);
+}
+
+
+vec3d vec3d::operator*(vec3d::const_reference scale) const
+{
+ return vec3d(x * scale, y * scale, z * scale);
+}
+
+
+vec3d vec3d::operator/(const vec3d& v) const
+{
+ return vec3d(x / v.x, y / v.y, z / v.z);
+}
+
+
+vec3d vec3d::operator/(vec3d::const_reference scale) const
+{
+ return vec3d(x / scale, y / scale, z / scale);
+}
+
+
+vec3d& vec3d::operator+=(const vec3d& v)
+{
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ return *this;
+}
+
+
+vec3d& vec3d::operator-=(const vec3d& v)
+{
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ return *this;
+}
+
+
+vec3d& vec3d::operator*=(const vec3d& v)
+{
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ return *this;
+}
+
+
+vec3d& vec3d::operator*=(vec3d::const_reference scale)
+{
+ x *= scale;
+ y *= scale;
+ z *= scale;
+ return *this;
+}
+
+
+vec3d& vec3d::operator/=(const vec3d& v)
+{
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ return *this;
+}
+
+
+vec3d& vec3d::operator/=(vec3d::const_reference scale)
+{
+ x /= scale;
+ y /= scale;
+ z /= scale;
+ return *this;
+}
+
+
+
+///////////////
+// Modifiers //
+///////////////
+vec3d::value_type vec3d::dot(const vec3d& v) const
+{
+ return (x*v.x + y*v.y + z*v.z);
+}
+
+
+vec3d::value_type vec3d::squared_length(void) const
+{
+ return dot(*this);
+}
+
+
+vec3d::value_type vec3d::length(void) const
+{
+ return sqrt(squared_length());
+}
+
+
+vec3d::value_type vec3d::squared_distance(const vec3d& v) const
+{
+ return (*this - v).squared_length();
+}
+
+
+vec3d::value_type vec3d::distance(const vec3d& v) const
+{
+ return sqrt(squared_distance(v));
+}
+
+
+vec3d vec3d::cross(const vec3d& v) const
+{
+ return vec3d(y*v.z - z*v.y,
+ z*v.x - x*v.z,
+ x*v.y - y*v.x);
+}
+
+
+///////////////
+// Modifiers //
+///////////////
+vec3d& vec3d::abs(void)
+{
+ std::for_each(begin(), end(), [](reference val)
+ {
+ if(val < 0) val = -val;
+ });
+ return *this;
+}
+
+
+vec3d& vec3d::clamp(vec3d::value_type lower, vec3d::value_type upper)
+{
+ std::for_each(begin(), end(), [&](reference val)
+ {
+ if(val < lower) val = lower;
+ else if(val > upper) val = upper;
+ });
+ return *this;
+}
+
+
+vec3d& vec3d::normalize(void)
+{
+ *this /= length();
+ return *this;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+void vec3d::_assign(const vec3d& v)
+{
+ x = v.x;
+ y = v.y;
+ z = v.z;
+}
+
+
+void vec3d::_swap(vec3d& v)
+{
+ std::swap(x, v.x);
+ std::swap(y, v.y);
+ std::swap(z, v.z);
+}