diff options
Diffstat (limited to 'hw2')
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); +} |