summaryrefslogtreecommitdiff
path: root/hw2
diff options
context:
space:
mode:
Diffstat (limited to 'hw2')
-rw-r--r--hw2/.gitignore4
-rw-r--r--hw2/CMakeLists.txt71
-rw-r--r--hw2/bin/HW1.cpp38
-rw-r--r--hw2/bin/HW2.cpp112
-rw-r--r--hw2/bin/helloworld.cpp9
-rw-r--r--hw2/bin/image_compare.cpp90
-rw-r--r--hw2/include/boundingBox.h77
-rw-r--r--hw2/include/camera.h80
-rw-r--r--hw2/include/color.h105
-rw-r--r--hw2/include/constants.h15
-rw-r--r--hw2/include/errorMessage.h17
-rw-r--r--hw2/include/image.h89
-rw-r--r--hw2/include/imageIO.h19
-rw-r--r--hw2/include/imageIO.pfm.h18
-rw-r--r--hw2/include/imageIO.ppm.h18
-rw-r--r--hw2/include/interval.h77
-rw-r--r--hw2/include/mat3d.h112
-rw-r--r--hw2/include/ray.h69
-rw-r--r--hw2/include/transformation3d.h77
-rw-r--r--hw2/include/triangle.h115
-rw-r--r--hw2/include/util.h19
-rw-r--r--hw2/include/vec2d.h117
-rw-r--r--hw2/include/vec3d.h120
-rw-r--r--hw2/src/boundingBox.cpp185
-rw-r--r--hw2/src/camera.cpp150
-rw-r--r--hw2/src/color.cpp233
-rw-r--r--hw2/src/errorMessage.cpp34
-rw-r--r--hw2/src/image.cpp122
-rw-r--r--hw2/src/imageIO.cpp46
-rw-r--r--hw2/src/imageIO.pfm.cpp87
-rw-r--r--hw2/src/imageIO.ppm.cpp106
-rw-r--r--hw2/src/interval.cpp154
-rw-r--r--hw2/src/mat3d.cpp260
-rw-r--r--hw2/src/ray.cpp83
-rw-r--r--hw2/src/transformation3d.cpp174
-rw-r--r--hw2/src/triangle.cpp451
-rw-r--r--hw2/src/util.cpp45
-rw-r--r--hw2/src/vec2d.cpp258
-rw-r--r--hw2/src/vec3d.cpp287
39 files changed, 4143 insertions, 0 deletions
diff --git a/hw2/.gitignore b/hw2/.gitignore
new file mode 100644
index 0000000..aeb08d6
--- /dev/null
+++ b/hw2/.gitignore
@@ -0,0 +1,4 @@
+Debug
+Release
+Reference
+*.ppm
diff --git a/hw2/CMakeLists.txt b/hw2/CMakeLists.txt
new file mode 100644
index 0000000..984cdf2
--- /dev/null
+++ b/hw2/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/hw2/bin/HW1.cpp b/hw2/bin/HW1.cpp
new file mode 100644
index 0000000..8e66297
--- /dev/null
+++ b/hw2/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/hw2/bin/HW2.cpp b/hw2/bin/HW2.cpp
new file mode 100644
index 0000000..c116f01
--- /dev/null
+++ b/hw2/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/hw2/bin/helloworld.cpp b/hw2/bin/helloworld.cpp
new file mode 100644
index 0000000..4911d87
--- /dev/null
+++ b/hw2/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/hw2/bin/image_compare.cpp b/hw2/bin/image_compare.cpp
new file mode 100644
index 0000000..4f1a798
--- /dev/null
+++ b/hw2/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/hw2/include/boundingBox.h b/hw2/include/boundingBox.h
new file mode 100644
index 0000000..522672e
--- /dev/null
+++ b/hw2/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/hw2/include/camera.h b/hw2/include/camera.h
new file mode 100644
index 0000000..9e3be04
--- /dev/null
+++ b/hw2/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/hw2/include/color.h b/hw2/include/color.h
new file mode 100644
index 0000000..b2ca490
--- /dev/null
+++ b/hw2/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/hw2/include/constants.h b/hw2/include/constants.h
new file mode 100644
index 0000000..330e89e
--- /dev/null
+++ b/hw2/include/constants.h
@@ -0,0 +1,15 @@
+/******************************************************************/
+/* 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;
+
+#endif /* _CONSTANTS_H_ */
diff --git a/hw2/include/errorMessage.h b/hw2/include/errorMessage.h
new file mode 100644
index 0000000..7ec99d1
--- /dev/null
+++ b/hw2/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/hw2/include/image.h b/hw2/include/image.h
new file mode 100644
index 0000000..938e6c0
--- /dev/null
+++ b/hw2/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/hw2/include/imageIO.h b/hw2/include/imageIO.h
new file mode 100644
index 0000000..9e1ecfa
--- /dev/null
+++ b/hw2/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/hw2/include/imageIO.pfm.h b/hw2/include/imageIO.pfm.h
new file mode 100644
index 0000000..d09531a
--- /dev/null
+++ b/hw2/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/hw2/include/imageIO.ppm.h b/hw2/include/imageIO.ppm.h
new file mode 100644
index 0000000..7a8db42
--- /dev/null
+++ b/hw2/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/hw2/include/interval.h b/hw2/include/interval.h
new file mode 100644
index 0000000..ccb720a
--- /dev/null
+++ b/hw2/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/hw2/include/mat3d.h b/hw2/include/mat3d.h
new file mode 100644
index 0000000..e70ece4
--- /dev/null
+++ b/hw2/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/hw2/include/ray.h b/hw2/include/ray.h
new file mode 100644
index 0000000..743375f
--- /dev/null
+++ b/hw2/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/hw2/include/transformation3d.h b/hw2/include/transformation3d.h
new file mode 100644
index 0000000..7b61ecc
--- /dev/null
+++ b/hw2/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/hw2/include/triangle.h b/hw2/include/triangle.h
new file mode 100644
index 0000000..f7d85bf
--- /dev/null
+++ b/hw2/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/hw2/include/util.h b/hw2/include/util.h
new file mode 100644
index 0000000..2146464
--- /dev/null
+++ b/hw2/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/hw2/include/vec2d.h b/hw2/include/vec2d.h
new file mode 100644
index 0000000..36e0e5c
--- /dev/null
+++ b/hw2/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/hw2/include/vec3d.h b/hw2/include/vec3d.h
new file mode 100644
index 0000000..50d918f
--- /dev/null
+++ b/hw2/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/hw2/src/boundingBox.cpp b/hw2/src/boundingBox.cpp
new file mode 100644
index 0000000..9708093
--- /dev/null
+++ b/hw2/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/hw2/src/camera.cpp b/hw2/src/camera.cpp
new file mode 100644
index 0000000..2e8daaa
--- /dev/null
+++ b/hw2/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 * M_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 * M_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/hw2/src/color.cpp b/hw2/src/color.cpp
new file mode 100644
index 0000000..b2b720f
--- /dev/null
+++ b/hw2/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/hw2/src/errorMessage.cpp b/hw2/src/errorMessage.cpp
new file mode 100644
index 0000000..3eddb6a
--- /dev/null
+++ b/hw2/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/hw2/src/image.cpp b/hw2/src/image.cpp
new file mode 100644
index 0000000..59434cc
--- /dev/null
+++ b/hw2/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/hw2/src/imageIO.cpp b/hw2/src/imageIO.cpp
new file mode 100644
index 0000000..cee716b
--- /dev/null
+++ b/hw2/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/hw2/src/imageIO.pfm.cpp b/hw2/src/imageIO.pfm.cpp
new file mode 100644
index 0000000..843b751
--- /dev/null
+++ b/hw2/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());
+ 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/hw2/src/imageIO.ppm.cpp b/hw2/src/imageIO.ppm.cpp
new file mode 100644
index 0000000..28dbc31
--- /dev/null
+++ b/hw2/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());
+ 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/hw2/src/interval.cpp b/hw2/src/interval.cpp
new file mode 100644
index 0000000..4323cbd
--- /dev/null
+++ b/hw2/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/hw2/src/mat3d.cpp b/hw2/src/mat3d.cpp
new file mode 100644
index 0000000..7674777
--- /dev/null
+++ b/hw2/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/hw2/src/ray.cpp b/hw2/src/ray.cpp
new file mode 100644
index 0000000..18c839d
--- /dev/null
+++ b/hw2/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/hw2/src/transformation3d.cpp b/hw2/src/transformation3d.cpp
new file mode 100644
index 0000000..bde9caa
--- /dev/null
+++ b/hw2/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/hw2/src/triangle.cpp b/hw2/src/triangle.cpp
new file mode 100644
index 0000000..1e3990e
--- /dev/null
+++ b/hw2/src/triangle.cpp
@@ -0,0 +1,451 @@
+/******************************************************************/
+/* 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
+{
+ // HW2: Implement this.
+ // Compute the intersection between the triangle (this) and the ray (r).
+ // Use the method 'vertex(i)' to access the i-th vertex of the triangle (i=[0,1,2]).
+ // Use the method 'normal()' to access the normal of the plane in which the traingle lies.
+ // Returns: bool (true if hit, false if not)
+ // barycentricCoord (fill in alpha, beta, gamma barycentric coordinates
+ // of (vertex(0), vertex(1), and vertex(2)) if hit)
+ // t (the distance at which the ray intersects => r(t) == intersection point)
+ float d, a1, a2, a3, area, alpha, beta, gamma;
+ vec3d n, q, p1, p2, p3;
+
+ d = -(vertex(0).dot(normal()));
+ t = (-((r.origin().dot(normal())) + d)) / (r.direction().dot(normal()));
+
+ if (t < 0) {return false;}
+
+ q = r.origin() + t * r.direction();
+ p1 = vertex(0);
+ p2 = vertex(1);
+ p3 = vertex(2);
+ n = (p2 - p1).cross(p3 - p1);
+ a1 = 0.5f * (p2 - q).cross(p3 - q).dot(n);
+ a2 = 0.5f * (p3 - q).cross(p1 - q).dot(n);
+ a3 = 0.5f * (p1 - q).cross(p2 - q).dot(n);
+ area = a1 + a2 + a3;
+ alpha = a1 / area;
+ beta = a2 / area;
+ gamma = a3 / area;
+
+ if (alpha < 0 || beta < 0 || gamma < 0) {return false;}
+
+ barycentricCoord = vec3d(alpha, beta, gamma);
+ 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/hw2/src/util.cpp b/hw2/src/util.cpp
new file mode 100644
index 0000000..917eef4
--- /dev/null
+++ b/hw2/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/hw2/src/vec2d.cpp b/hw2/src/vec2d.cpp
new file mode 100644
index 0000000..ae12e41
--- /dev/null
+++ b/hw2/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/hw2/src/vec3d.cpp b/hw2/src/vec3d.cpp
new file mode 100644
index 0000000..3b20ad5
--- /dev/null
+++ b/hw2/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);
+}