diff options
Diffstat (limited to 'hw2/src')
-rw-r--r-- | hw2/src/boundingBox.cpp | 185 | ||||
-rw-r--r-- | hw2/src/camera.cpp | 150 | ||||
-rw-r--r-- | hw2/src/color.cpp | 233 | ||||
-rw-r--r-- | hw2/src/errorMessage.cpp | 34 | ||||
-rw-r--r-- | hw2/src/image.cpp | 122 | ||||
-rw-r--r-- | hw2/src/imageIO.cpp | 46 | ||||
-rw-r--r-- | hw2/src/imageIO.pfm.cpp | 87 | ||||
-rw-r--r-- | hw2/src/imageIO.ppm.cpp | 106 | ||||
-rw-r--r-- | hw2/src/interval.cpp | 154 | ||||
-rw-r--r-- | hw2/src/mat3d.cpp | 260 | ||||
-rw-r--r-- | hw2/src/ray.cpp | 83 | ||||
-rw-r--r-- | hw2/src/transformation3d.cpp | 174 | ||||
-rw-r--r-- | hw2/src/triangle.cpp | 451 | ||||
-rw-r--r-- | hw2/src/util.cpp | 45 | ||||
-rw-r--r-- | hw2/src/vec2d.cpp | 258 | ||||
-rw-r--r-- | hw2/src/vec3d.cpp | 287 |
16 files changed, 2675 insertions, 0 deletions
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); +} |