Merge branch 'feature/transform-matrix' into develop
This commit is contained in:
commit
db2804ac17
60 changed files with 3053 additions and 1906 deletions
|
@ -8,6 +8,7 @@ Import('env')
|
|||
objs = []
|
||||
|
||||
subdirs = [
|
||||
'basics',
|
||||
'yaml',
|
||||
]
|
||||
|
||||
|
@ -17,9 +18,9 @@ for d in subdirs:
|
|||
|
||||
|
||||
files = [
|
||||
'basics.cc',
|
||||
'camera.cc',
|
||||
'light.cc',
|
||||
'lightPoint.cc',
|
||||
'log.cc',
|
||||
'material.cc',
|
||||
'object.cc',
|
||||
|
|
530
src/basics.cc
530
src/basics.cc
|
@ -1,530 +0,0 @@
|
|||
/* basics.c
|
||||
*
|
||||
* Definition of basic types.
|
||||
*
|
||||
* - Vector3 is a three tuple vector of x, y, and z.
|
||||
* - Ray is a vector plus a direction.
|
||||
* - Color is a four tuple of red, green, blue, and alpha.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include "basics.h"
|
||||
|
||||
#pragma mark - Vectors
|
||||
|
||||
const Vector3 Vector3::Zero = Vector3();
|
||||
const Vector3 Vector3::X = Vector3(1, 0, 0);
|
||||
const Vector3 Vector3::Y = Vector3(0, 1, 0);
|
||||
const Vector3 Vector3::Z = Vector3(0, 0, 1);
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::Vector3 --
|
||||
*
|
||||
* Default constructor. Create a zero vector.
|
||||
*/
|
||||
Vector3::Vector3()
|
||||
: Vector3(0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::Vector3 --
|
||||
*
|
||||
* Constructor. Create a vector consisting of the given coordinates.
|
||||
*/
|
||||
Vector3::Vector3(Double _x, Double _y, Double _z)
|
||||
: x(_x), y(_y), z(_z)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator= --
|
||||
*
|
||||
* Copy the given vector's values into this vector. Return a reference to this vector.
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::operator=(const Vector3 &v)
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator*= --
|
||||
* Vector3::operator/= --
|
||||
* Vector3::operator+= --
|
||||
* Vector3::operator-= --
|
||||
*
|
||||
* Perform the corresponding arithmetic operation on this vector and the given vector. These methods are destructive and
|
||||
* a reference to this vector is returned.
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::operator*=(const Double &rhs)
|
||||
{
|
||||
x *= rhs;
|
||||
y *= rhs;
|
||||
z *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator/=(const Double &rhs)
|
||||
{
|
||||
return *this *= (1.0f / rhs);
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator+=(const Vector3 &rhs)
|
||||
{
|
||||
x += rhs.x;
|
||||
y += rhs.y;
|
||||
z += rhs.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator-=(const Vector3 &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator* --
|
||||
* Vector3::operator/ --
|
||||
* Vector3::operator+ --
|
||||
* Vector3::operator- --
|
||||
*
|
||||
* Perform the corresponding operation on a copy of this vector. Return a new vector.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::operator*(const Double &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) *= rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator/(const Double &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) /= rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator+(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) += rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator-(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator- --
|
||||
*
|
||||
* Negate this vector. Return a new vector.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::operator-()
|
||||
const
|
||||
{
|
||||
return Vector3(-x, -y, -z);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator== --
|
||||
* Vector3::operator!= --
|
||||
*
|
||||
* Compute boolean equality and non-equality of this and the given vectors.
|
||||
*/
|
||||
bool
|
||||
Vector3::operator==(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return x == rhs.x && y == rhs.y && z == rhs.z;
|
||||
}
|
||||
|
||||
bool
|
||||
Vector3::operator!=(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::length2 --
|
||||
*
|
||||
* Compute and return the length-squared of this vector.
|
||||
*/
|
||||
Double
|
||||
Vector3::length2()
|
||||
const
|
||||
{
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::length --
|
||||
*
|
||||
* Compute and return the length of this vector.
|
||||
*/
|
||||
Double
|
||||
Vector3::length()
|
||||
const
|
||||
{
|
||||
return sqrt(length2());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::dot --
|
||||
*
|
||||
* Compute and return the dot product of this and the given vectors.
|
||||
*/
|
||||
Double
|
||||
Vector3::dot(const Vector3 &v)
|
||||
const
|
||||
{
|
||||
return x*v.x + y*v.y + z*v.z;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::cross --
|
||||
*
|
||||
* Compute and return the cross product of this and the given vectors.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::cross(const Vector3 &v)
|
||||
const
|
||||
{
|
||||
return Vector3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::normalize --
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::normalize()
|
||||
{
|
||||
// Use the overloaded /= compound operator to do this.
|
||||
return *this /= length();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::normalized --
|
||||
*/
|
||||
Vector3
|
||||
Vector3::normalized()
|
||||
const
|
||||
{
|
||||
return *this / length();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* operator* --
|
||||
*
|
||||
* Multiply the given float by the given vector. Return a new vector.
|
||||
*/
|
||||
const Vector3
|
||||
operator*(const Double &lhs, const Vector3 &rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Vector3 &v)
|
||||
{
|
||||
// Stream the vector like this: <x, y, z>
|
||||
os << "<" << v.x << ", " << v.y << ", " << v.z << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
Vector3
|
||||
LinearCombination(const Double k1, const Vector3& v1,
|
||||
const Double k2, const Vector3& v2,
|
||||
const Double k3, const Vector3& v3)
|
||||
{
|
||||
return Vector3(k1 * v1.x + k2 * v2.x + k3 * v3.x,
|
||||
k1 * v1.y + k2 * v2.y + k3 * v3.y,
|
||||
k1 * v1.z + k2 * v2.z + k3 * v3.z);
|
||||
}
|
||||
|
||||
#pragma mark - Rays
|
||||
|
||||
/*
|
||||
* Ray::Ray --
|
||||
*
|
||||
* Default constructor. Create a ray at the origin (0, 0, 0) with direction (0, 0, 0).
|
||||
*/
|
||||
Ray::Ray()
|
||||
: Ray(Vector3::Zero, Vector3::Zero)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Ray::Ray --
|
||||
*
|
||||
* Constructor. Create a ray with the given origin and direction.
|
||||
*/
|
||||
Ray::Ray(Vector3 o, Vector3 d)
|
||||
: origin(o), direction(d)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Ray::parameterize --
|
||||
*
|
||||
* Compute and return the point given by parameterizing this Ray by time t.
|
||||
*/
|
||||
Vector3
|
||||
Ray::parameterize(const Double& t)
|
||||
const
|
||||
{
|
||||
return origin + t * direction;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Ray &r)
|
||||
{
|
||||
os << "[Ray " << r.origin << " " << r.direction << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
#pragma mark - Colors
|
||||
|
||||
const Color Color::Black = Color();
|
||||
const Color Color::White = Color(1.0, 1.0, 1.0, 1.0);
|
||||
const Color Color::Red = Color(1.0, 0.0, 0.0, 1.0);
|
||||
const Color Color::Green = Color(0.0, 1.0, 0.0, 1.0);
|
||||
const Color Color::Blue = Color(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Default constructor. Create a new Color with zeros for all components (black).
|
||||
*/
|
||||
Color::Color()
|
||||
: Color(0.0, 0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Constructor. Create a new Color with the given RGB components. Alpha is 1.0.
|
||||
*/
|
||||
Color::Color(const float &r, const float &g, const float &b)
|
||||
: Color(r, g, b, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Constructor. Create a new Color with the given components.
|
||||
*/
|
||||
Color::Color(const float &r, const float &g, const float &b, const float &a)
|
||||
: red(r), green(g), blue(b), alpha(a)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator*= --
|
||||
* Color::operator/= --
|
||||
* Color::operator+= --
|
||||
* Color::operator-= --
|
||||
*
|
||||
* Perform the corresponding arithmetic operation on this color and the given scalar. These methods are destructive and
|
||||
* a reference to this color is returned.
|
||||
*/
|
||||
Color &
|
||||
Color::operator*=(const float &rhs)
|
||||
{
|
||||
red *= rhs;
|
||||
green *= rhs;
|
||||
blue *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator/=(const float &rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator+=(const float &rhs)
|
||||
{
|
||||
red += rhs;
|
||||
green += rhs;
|
||||
blue += rhs;
|
||||
alpha += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator-=(const float &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator* --
|
||||
* Color::operator/ --
|
||||
* Color::operator+ --
|
||||
* Color::operator- --
|
||||
*
|
||||
* Perform the corresponding operation on a copy of this color and the given scalar. Return a new vector.
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator/(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator+(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator-(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator= --
|
||||
*
|
||||
* Copy the given color's values into this color. Return a reference to this color.
|
||||
*/
|
||||
Color &
|
||||
Color::operator=(const Color &rhs)
|
||||
{
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
alpha = rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Color &
|
||||
Color::operator*=(const Color &rhs)
|
||||
{
|
||||
red *= rhs.red;
|
||||
green *= rhs.green;
|
||||
blue *= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator/=(const Color &rhs)
|
||||
{
|
||||
red *= (1.0 / rhs.red);
|
||||
green *= (1.0 / rhs.green);
|
||||
blue *= (1.0 / rhs.blue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator+=(const Color &rhs)
|
||||
{
|
||||
red += rhs.red;
|
||||
green += rhs.green;
|
||||
blue += rhs.blue;
|
||||
alpha += rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator-=(const Color &rhs)
|
||||
{
|
||||
red -= rhs.red;
|
||||
green -= rhs.green;
|
||||
blue -= rhs.blue;
|
||||
alpha -= rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Color
|
||||
Color::operator*(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator/(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator+(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator-(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
const Color
|
||||
operator*(const float &lhs, const Color &rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Color &c)
|
||||
{
|
||||
// Stream colors like this: <r, g, b, a>
|
||||
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
|
||||
return os;
|
||||
}
|
174
src/basics.h
174
src/basics.h
|
@ -1,174 +0,0 @@
|
|||
/* basics.h
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_H__
|
||||
#define __BASICS_H__
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
/*
|
||||
* XXX: THIS SHOULD NOT BE HERE. REMOVE IT WHEN MOVING TO CHARLES NAMESPACE IS
|
||||
* DONE.
|
||||
*/
|
||||
using charles::Double;
|
||||
|
||||
|
||||
/**
|
||||
* A very small constant. If a value is between EPSILON and 0.0, it is
|
||||
* considered to be zero.
|
||||
*/
|
||||
const Double EPSILON = 1.0e-10;
|
||||
|
||||
/**
|
||||
* The maximum distance a ray can travel. This is the maximum value t can be.
|
||||
*/
|
||||
const Double MAX_DISTANCE = 1.0e7;
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the value is "close enough" to zero. Takes the absolute value
|
||||
* and compares it to `EPSILON`.
|
||||
*
|
||||
* @see EPSILON
|
||||
*
|
||||
* @param [in] value The value to check
|
||||
* @returns `true` if the value is close enough to zero
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool
|
||||
NearZero(const T value)
|
||||
{
|
||||
return std::fabs(value) < EPSILON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two values are "close enough" to be considered equal. Subtracts
|
||||
* one from the other and checks if the result is near zero.
|
||||
*
|
||||
* @see NearZero
|
||||
*
|
||||
* @param [in] left The left parameter
|
||||
* @param [in] right The right parameter
|
||||
* @returns `true` if the values are close enough to be equal
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool
|
||||
NearlyEqual(const T left,
|
||||
const T right)
|
||||
{
|
||||
return NearZero(left - right);
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
TooFar(const Double& value)
|
||||
{
|
||||
return value > MAX_DISTANCE;
|
||||
}
|
||||
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
Vector3();
|
||||
Vector3(Double x, Double y, Double z);
|
||||
|
||||
Vector3 &operator=(const Vector3 &v);
|
||||
Vector3 &operator*=(const Double &rhs);
|
||||
Vector3 &operator/=(const Double &rhs);
|
||||
Vector3 &operator+=(const Vector3 &rhs);
|
||||
Vector3 &operator-=(const Vector3 &rhs);
|
||||
Vector3 operator*(const Double &rhs) const;
|
||||
Vector3 operator/(const Double &rhs) const;
|
||||
Vector3 operator+(const Vector3 &rhs) const;
|
||||
Vector3 operator-(const Vector3 &rhs) const;
|
||||
Vector3 operator-() const;
|
||||
|
||||
bool operator==(const Vector3 &rhs) const;
|
||||
bool operator!=(const Vector3 &rhs) const;
|
||||
|
||||
Double length2() const;
|
||||
Double length() const;
|
||||
Double dot(const Vector3 &v) const;
|
||||
Vector3 cross(const Vector3 &v) const;
|
||||
|
||||
/** Normalize and return a reference to this vector. */
|
||||
Vector3 &normalize();
|
||||
|
||||
/** Return a copy of this vector, normalized. Does not modify this vector. */
|
||||
Vector3 normalized() const;
|
||||
|
||||
static const Vector3 Zero;
|
||||
// Unit vectors in each of the three cartesian directions.
|
||||
static const Vector3 X, Y, Z;
|
||||
|
||||
Double x, y, z;
|
||||
};
|
||||
|
||||
const Vector3 operator*(const Double &lhs, const Vector3 &rhs);
|
||||
std::ostream &operator<<(std::ostream &os, const Vector3 &v);
|
||||
|
||||
|
||||
Vector3 LinearCombination(const Double k1, const Vector3& v1,
|
||||
const Double k2, const Vector3& v2,
|
||||
const Double k3, const Vector3& v3);
|
||||
|
||||
|
||||
struct Ray
|
||||
{
|
||||
Ray();
|
||||
Ray(Vector3 o, Vector3 d);
|
||||
|
||||
Vector3 parameterize(const Double& t) const;
|
||||
|
||||
Vector3 origin, direction;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Ray &r);
|
||||
|
||||
|
||||
struct Color
|
||||
{
|
||||
Color();
|
||||
Color(const float &r, const float &g, const float &b);
|
||||
Color(const float &r, const float &g, const float &b, const float &a);
|
||||
|
||||
Color &operator*=(const float &rhs);
|
||||
Color &operator/=(const float &rhs);
|
||||
Color &operator+=(const float &rhs);
|
||||
Color &operator-=(const float &rhs);
|
||||
Color operator*(const float &rhs) const;
|
||||
Color operator/(const float &rhs) const;
|
||||
Color operator+(const float &rhs) const;
|
||||
Color operator-(const float &rhs) const;
|
||||
|
||||
Color &operator=(const Color &rhs);
|
||||
|
||||
// These operators blend the two colors.
|
||||
Color &operator*=(const Color &rhs);
|
||||
Color &operator/=(const Color &rhs);
|
||||
Color &operator+=(const Color &rhs);
|
||||
Color &operator-=(const Color &rhs);
|
||||
Color operator*(const Color &rhs) const;
|
||||
Color operator/(const Color &rhs) const;
|
||||
Color operator+(const Color &rhs) const;
|
||||
Color operator-(const Color &rhs) const;
|
||||
|
||||
static const Color Black;
|
||||
static const Color White;
|
||||
static const Color Red;
|
||||
static const Color Green;
|
||||
static const Color Blue;
|
||||
|
||||
float red, green, blue, alpha;
|
||||
};
|
||||
|
||||
const Color operator*(const float &lhs, const Color &rhs);
|
||||
std::ostream &operator<<(std::ostream &os, const Color &c);
|
||||
|
||||
#endif
|
16
src/basics/SConscript
Normal file
16
src/basics/SConscript
Normal file
|
@ -0,0 +1,16 @@
|
|||
# SConscript
|
||||
# vim: set ft=python:
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
Import('env')
|
||||
|
||||
|
||||
files = [
|
||||
'color.cc',
|
||||
'matrix.cc',
|
||||
'ray.cc',
|
||||
'vector.cc',
|
||||
]
|
||||
|
||||
objs = [env.Object(f) for f in files]
|
||||
Return('objs')
|
21
src/basics/basics.hh
Normal file
21
src/basics/basics.hh
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* basics.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Top-level include for the basics module.
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_BASICS_HH__
|
||||
#define __BASICS_BASICS_HH__
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "basics/color.hh"
|
||||
#include "basics/matrix.hh"
|
||||
#include "basics/ray.hh"
|
||||
#include "basics/types.hh"
|
||||
#include "basics/util.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
#endif /* __BASICS_BASICS_HH__ */
|
272
src/basics/color.cc
Normal file
272
src/basics/color.cc
Normal file
|
@ -0,0 +1,272 @@
|
|||
/* color.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "basics/color.hh"
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
const Color Color::Black = Color();
|
||||
const Color Color::White = Color(1, 1, 1);
|
||||
const Color Color::Red = Color(1, 0, 0);
|
||||
const Color Color::Green = Color(0, 1, 0);
|
||||
const Color Color::Blue = Color(0, 0, 1);
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::Color --
|
||||
*/
|
||||
Color::Color()
|
||||
: Color(0.0, 0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::Color --
|
||||
*/
|
||||
Color::Color(const Double& r,
|
||||
const Double& g,
|
||||
const Double& b,
|
||||
const Double& a)
|
||||
: red(r),
|
||||
green(g),
|
||||
blue(b),
|
||||
alpha(a)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator=(const Color& rhs)
|
||||
{
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
alpha = rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator*= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator*=(const Double& rhs)
|
||||
{
|
||||
red *= rhs;
|
||||
green *= rhs;
|
||||
blue *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator/=(const Double& rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator+=(const Double& rhs)
|
||||
{
|
||||
red += rhs;
|
||||
green += rhs;
|
||||
blue += rhs;
|
||||
alpha += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator-= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator-=(const Double& rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator* --
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/ --
|
||||
*/
|
||||
Color
|
||||
Color::operator/(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+ --
|
||||
*/
|
||||
Color
|
||||
Color::operator+(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator- --
|
||||
*/
|
||||
Color
|
||||
Color::operator-(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator*= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator*=(const Color& rhs)
|
||||
{
|
||||
red *= rhs.red;
|
||||
green *= rhs.green;
|
||||
blue *= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator/=(const Color& rhs)
|
||||
{
|
||||
red /= rhs.red;
|
||||
green /= rhs.green;
|
||||
blue /= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator+=(const Color& rhs)
|
||||
{
|
||||
red += rhs.red;
|
||||
green += rhs.green;
|
||||
blue += rhs.blue;
|
||||
alpha += rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator-= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator-=(const Color& rhs)
|
||||
{
|
||||
red -= rhs.red;
|
||||
green -= rhs.green;
|
||||
blue -= rhs.blue;
|
||||
alpha -= rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator* --
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/ --
|
||||
*/
|
||||
Color
|
||||
Color::operator/(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+ --
|
||||
*/
|
||||
Color
|
||||
Color::operator+(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator- --
|
||||
*/
|
||||
Color
|
||||
Color::operator-(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
const Color
|
||||
operator*(const Double& lhs,
|
||||
const Color& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream &
|
||||
operator<<(std::ostream& os,
|
||||
const Color& c)
|
||||
{
|
||||
// Stream colors like this: <r, g, b, a>
|
||||
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
58
src/basics/color.hh
Normal file
58
src/basics/color.hh
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* color.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_COLOR_HH__
|
||||
#define __BASICS_COLOR_HH__
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Color
|
||||
{
|
||||
Color();
|
||||
Color(const Double& r, const Double& g, const Double& b, const Double& a = 1.0);
|
||||
|
||||
Color &operator*=(const Double &rhs);
|
||||
Color &operator/=(const Double &rhs);
|
||||
Color &operator+=(const Double &rhs);
|
||||
Color &operator-=(const Double &rhs);
|
||||
Color operator*(const Double &rhs) const;
|
||||
Color operator/(const Double &rhs) const;
|
||||
Color operator+(const Double &rhs) const;
|
||||
Color operator-(const Double &rhs) const;
|
||||
|
||||
Color &operator=(const Color &rhs);
|
||||
|
||||
// These operators blend the two colors.
|
||||
Color &operator*=(const Color &rhs);
|
||||
Color &operator/=(const Color &rhs);
|
||||
Color &operator+=(const Color &rhs);
|
||||
Color &operator-=(const Color &rhs);
|
||||
Color operator*(const Color &rhs) const;
|
||||
Color operator/(const Color &rhs) const;
|
||||
Color operator+(const Color &rhs) const;
|
||||
Color operator-(const Color &rhs) const;
|
||||
|
||||
static const Color Black;
|
||||
static const Color White;
|
||||
static const Color Red;
|
||||
static const Color Green;
|
||||
static const Color Blue;
|
||||
|
||||
Double red, green, blue, alpha;
|
||||
};
|
||||
|
||||
|
||||
const Color operator*(const Double &lhs, const Color &rhs);
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Color &c);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_COLOR_HH__ */
|
382
src/basics/matrix.cc
Normal file
382
src/basics/matrix.cc
Normal file
|
@ -0,0 +1,382 @@
|
|||
/* matrix.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "basics/matrix.hh"
|
||||
|
||||
#include "basics/util.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
#pragma mark Static Methods
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Zero --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Zero()
|
||||
{
|
||||
Matrix4 m;
|
||||
bzero(m.mData, sizeof(Double) * 16);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Identity --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Identity()
|
||||
{
|
||||
auto m = Matrix4::Zero();
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
m(i,i) = 1.0;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Translation --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Translation(const Vector4& p)
|
||||
{
|
||||
return Translation(p.X(), p.Y(), p.Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::TranslationMatrix --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Translation(Double x,
|
||||
Double y,
|
||||
Double z)
|
||||
{
|
||||
Matrix4 m = Matrix4::Identity();
|
||||
m(0,3) = x;
|
||||
m(1,3) = y;
|
||||
m(2,3) = z;
|
||||
return m;
|
||||
}
|
||||
|
||||
#pragma mark Constructors and Assignment
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4()
|
||||
: mData(),
|
||||
mTransposed(false)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4(const Double data[16])
|
||||
: mTransposed(false)
|
||||
{
|
||||
/* TODO: Replace with std::copy */
|
||||
memcpy(mData, data, sizeof(Double) * 16);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4(const Matrix4 &rhs)
|
||||
: Matrix4(rhs.mData)
|
||||
{
|
||||
/*
|
||||
* Needs to be in the body instead of the initializer list because
|
||||
* (apparently) delegating constructors must be the only thing in the list.
|
||||
*/
|
||||
mTransposed = rhs.mTransposed;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator=(const Matrix4 &rhs)
|
||||
{
|
||||
/* TODO: Replace with std::copy */
|
||||
memcpy(mData, rhs.mData, sizeof(Double) * 16);
|
||||
mTransposed = rhs.mTransposed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma mark Boolean Operators
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator== --
|
||||
*/
|
||||
bool
|
||||
Matrix4::operator==(const Matrix4 &rhs)
|
||||
const
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!NearlyEqual(mData[i], rhs.mData[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator!= --
|
||||
*/
|
||||
bool
|
||||
Matrix4::operator!=(const Matrix4 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
#pragma mark Element Access
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator() --
|
||||
*/
|
||||
Double&
|
||||
Matrix4::operator()(UInt i,
|
||||
UInt j)
|
||||
{
|
||||
if (i >= 4 || j >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
|
||||
if (!mTransposed) {
|
||||
return mData[i*4 + j];
|
||||
} else {
|
||||
return mData[i + j*4];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator() --
|
||||
*/
|
||||
Double
|
||||
Matrix4::operator()(UInt i,
|
||||
UInt j)
|
||||
const
|
||||
{
|
||||
if (i >= 4 || j >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
if (!mTransposed) {
|
||||
return mData[i*4 + j];
|
||||
} else {
|
||||
return mData[i + j*4];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector4
|
||||
Matrix4::Column(const UInt i)
|
||||
const noexcept
|
||||
{
|
||||
return Vector4(operator()(i,0), operator()(i,1), operator()(i,2), operator()(i,3));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::CArray --
|
||||
*/
|
||||
const Double*
|
||||
Matrix4::CArray()
|
||||
const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
#pragma mark Maths
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator*(Double rhs)
|
||||
const
|
||||
{
|
||||
return Matrix4(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator/ --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator/(Double rhs)
|
||||
const
|
||||
{
|
||||
return Matrix4(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator*= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator*=(Double rhs)
|
||||
{
|
||||
for (UInt i = 0; i < 16; i++) {
|
||||
mData[i] *= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator/= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator/=(Double rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator*(const Matrix4& rhs)
|
||||
const
|
||||
{
|
||||
Matrix4 result;
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
/* Each cell is Sigma(k=0, M)(lhs[ik] * rhs[kj]) */
|
||||
result(i,j) = 0.0;
|
||||
for (UInt k = 0; k < 4; k++) {
|
||||
result(i,j) += mData[i*4 + k] * rhs(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Matrix4::operator*(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
Vector4 result;
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
result(i) = 0.0;
|
||||
for (UInt k = 0; k < 4; k++) {
|
||||
result(i) += mData[i*4 + k] * rhs(k);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Transpose --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::Transpose()
|
||||
{
|
||||
mTransposed = !mTransposed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Matrix4&
|
||||
Matrix4::Inverse()
|
||||
{
|
||||
/* XXX: Only translation matrices are supported right now. */
|
||||
operator()(0,3) = -operator()(0,3);
|
||||
operator()(1,3) = -operator()(1,3);
|
||||
operator()(2,3) = -operator()(2,3);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
operator*(Double lhs,
|
||||
const Matrix4& rhs)
|
||||
{
|
||||
/* Scalar multiplication is commutative. */
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Transposed --
|
||||
*/
|
||||
Matrix4
|
||||
Transpose(Matrix4 m)
|
||||
{
|
||||
return m.Transpose();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Inverse --
|
||||
*/
|
||||
Matrix4
|
||||
Inverse(Matrix4 m)
|
||||
{
|
||||
return m.Inverse();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream &ost,
|
||||
const Matrix4 &m)
|
||||
{
|
||||
ost << "[";
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
if (i != 0) {
|
||||
ost << " ";
|
||||
}
|
||||
ost << "[";
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
ost << m(i,j);
|
||||
if (j < 3) {
|
||||
ost << " ";
|
||||
}
|
||||
}
|
||||
ost << "]";
|
||||
if (i < 3) {
|
||||
ost << "\n";
|
||||
}
|
||||
}
|
||||
ost << "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace mespace */
|
||||
} /* namespace charles */
|
||||
|
108
src/basics/matrix.hh
Normal file
108
src/basics/matrix.hh
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* matrix.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_MATRIX_HH__
|
||||
#define __BASICS_MATRIX_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Vector4;
|
||||
|
||||
|
||||
/** A 4x4 matrix, used for 3D transforms. */
|
||||
struct Matrix4
|
||||
{
|
||||
/** Create a 4x4 matrix of zeros. */
|
||||
static Matrix4 Zero();
|
||||
|
||||
/** Create a 4x4 identity matrix. */
|
||||
static Matrix4 Identity();
|
||||
|
||||
/** Create a 4x4 translation matrix. */
|
||||
static Matrix4 Translation(Double x, Double y, Double z);
|
||||
static Matrix4 Translation(const Vector4 &p);
|
||||
|
||||
Matrix4();
|
||||
Matrix4(const Double *data);
|
||||
Matrix4(const Matrix4 &rhs);
|
||||
|
||||
Matrix4& operator=(const Matrix4 &rhs);
|
||||
|
||||
bool operator==(const Matrix4 &rhs) const;
|
||||
bool operator!=(const Matrix4 &rhs) const;
|
||||
|
||||
/**
|
||||
* Get the ij'th item. In debug builds, this will assert if i or j are
|
||||
* outside the bounds of the array.
|
||||
*/
|
||||
Double& operator()(UInt i, UInt j);
|
||||
Double operator()(UInt i, UInt j) const;
|
||||
Vector4 Column(const UInt i) const noexcept;
|
||||
|
||||
/** Get the underlying C array */
|
||||
const Double *CArray() const;
|
||||
|
||||
/*
|
||||
* TODO: For completeness, matrix addition and subtraction, though I have
|
||||
* yet to find a need for them...
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Scalar multiplication
|
||||
* @{
|
||||
*/
|
||||
Matrix4 operator*(Double rhs) const;
|
||||
Matrix4 operator/(Double rhs) const;
|
||||
Matrix4& operator*=(Double rhs);
|
||||
Matrix4& operator/=(Double rhs);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup Matrix multiplication
|
||||
* @{
|
||||
*/
|
||||
Matrix4 operator*(const Matrix4 &rhs) const;
|
||||
Vector4 operator*(const Vector4 &rhs) const;
|
||||
/** @} */
|
||||
|
||||
Matrix4 &Transpose();
|
||||
Matrix4 &Inverse();
|
||||
|
||||
protected:
|
||||
/** The matrix data */
|
||||
Double mData[16];
|
||||
|
||||
/**
|
||||
* `true` if the matrix has been transposed (i.e. should be indexed in
|
||||
* column-major format).
|
||||
*/
|
||||
bool mTransposed;
|
||||
};
|
||||
|
||||
|
||||
/** Scalar multiplication, scalar factor on the left. */
|
||||
Matrix4 operator*(Double lhs, const Matrix4 &rhs);
|
||||
|
||||
/** Transpose the given matrix. */
|
||||
Matrix4 Transpose(Matrix4 m);
|
||||
|
||||
/** Invert the given matrix. */
|
||||
Matrix4 Inverse(Matrix4 m);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &ost, const Matrix4 &m);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_MATRIX_HH__ */
|
35
src/basics/ray.cc
Normal file
35
src/basics/ray.cc
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* ray.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics/ray.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
/*
|
||||
* charles::basics::Ray::Ray --
|
||||
*/
|
||||
Ray::Ray(Vector4 o,
|
||||
Vector4 d)
|
||||
: origin(o),
|
||||
direction(d)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Ray::Parameterize --
|
||||
*/
|
||||
Vector4
|
||||
Ray::Parameterize(const Double& t)
|
||||
const
|
||||
{
|
||||
return origin + direction * t;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
25
src/basics/ray.hh
Normal file
25
src/basics/ray.hh
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* ray.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics/types.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Ray
|
||||
{
|
||||
Ray(Vector4 o = Vector4(), Vector4 d = Vector4());
|
||||
|
||||
Vector4 Parameterize(const Double& t) const;
|
||||
|
||||
Vector4 origin;
|
||||
Vector4 direction;
|
||||
};
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
21
src/basics/types.hh
Normal file
21
src/basics/types.hh
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* types.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Some basic types.
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_TYPES_HH__
|
||||
#define __BASICS_TYPES_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
typedef double Double;
|
||||
typedef unsigned int UInt;
|
||||
|
||||
typedef std::vector<Double> DoubleVector;
|
||||
typedef DoubleVector TVector;
|
||||
|
||||
#endif /* __BASICS_TYPES_HH__ */
|
68
src/basics/util.hh
Normal file
68
src/basics/util.hh
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* util.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_UTIL_HH__
|
||||
#define __BASICS_UTIL_HH__
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
/**
|
||||
* A very small constant. If a value is between EPSILON and 0.0, it is
|
||||
* considered to be zero.
|
||||
*/
|
||||
const Double EPSILON = 1.0e-10;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum distance a ray can travel. This is the maximum value t can be.
|
||||
*/
|
||||
const Double MAX_DISTANCE = 1.0e7;
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the value is "close enough" to zero. Takes the absolute value
|
||||
* and compares it to `EPSILON`.
|
||||
*
|
||||
* @see EPSILON
|
||||
*
|
||||
* @param [in] value The value to check
|
||||
* @returns `true` if the value is close enough to zero
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool
|
||||
NearZero(T value)
|
||||
{
|
||||
return std::fabs(value) < EPSILON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two values are "close enough" to be considered equal. Subtracts
|
||||
* one from the other and checks if the result is near zero.
|
||||
*
|
||||
* @see NearZero
|
||||
*
|
||||
* @param [in] left The left parameter
|
||||
* @param [in] right The right parameter
|
||||
* @returns `true` if the values are close enough to be equal
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
inline bool
|
||||
NearlyEqual(T left,
|
||||
U right)
|
||||
{
|
||||
return NearZero(left - right);
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
TooFar(const Double& value)
|
||||
{
|
||||
return value > MAX_DISTANCE;
|
||||
}
|
||||
|
||||
#endif /* __BASICS_UTIL_HH__ */
|
||||
|
400
src/basics/vector.cc
Normal file
400
src/basics/vector.cc
Normal file
|
@ -0,0 +1,400 @@
|
|||
/* vector.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "basics/vector.hh"
|
||||
|
||||
#include "basics/util.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
#pragma mark Constructors and Assignment
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4()
|
||||
{
|
||||
bzero(mData, sizeof(Double) * 4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4(Double x,
|
||||
Double y,
|
||||
Double z)
|
||||
: Vector4(x, y, z, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4(Double x,
|
||||
Double y,
|
||||
Double z,
|
||||
Double w)
|
||||
{
|
||||
mData[0] = x;
|
||||
mData[1] = y;
|
||||
mData[2] = z;
|
||||
mData[3] = w;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator=(const Vector4 &rhs)
|
||||
{
|
||||
memcpy(mData, rhs.mData, sizeof(Double) * 4);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma mark Component Access
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::X --
|
||||
*/
|
||||
Double&
|
||||
Vector4::X()
|
||||
{
|
||||
return mData[0];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::X --
|
||||
*/
|
||||
Double
|
||||
Vector4::X()
|
||||
const
|
||||
{
|
||||
return mData[0];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Y --
|
||||
*/
|
||||
Double&
|
||||
Vector4::Y()
|
||||
{
|
||||
return mData[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Y --
|
||||
*/
|
||||
Double
|
||||
Vector4::Y()
|
||||
const
|
||||
{
|
||||
return mData[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Z --
|
||||
*/
|
||||
Double&
|
||||
Vector4::Z()
|
||||
{
|
||||
return mData[2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Z --
|
||||
*/
|
||||
Double
|
||||
Vector4::Z()
|
||||
const
|
||||
{
|
||||
return mData[2];
|
||||
}
|
||||
|
||||
|
||||
Double&
|
||||
Vector4::operator()(UInt i)
|
||||
{
|
||||
if (i >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "vector index out of bounds: i = " << i;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
return mData[i];
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Vector4::operator()(UInt i)
|
||||
const
|
||||
{
|
||||
if (i >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "vector index out of bounds: i = " << i;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
return mData[i];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::CArray --
|
||||
*/
|
||||
const Double*
|
||||
Vector4::CArray()
|
||||
const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
#pragma mark Boolean Operators
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator== --
|
||||
*/
|
||||
bool
|
||||
Vector4::operator==(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
if (!NearlyEqual(mData[i], rhs.mData[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator!= --
|
||||
*/
|
||||
bool
|
||||
Vector4::operator!=(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
#pragma mark Maths
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator*(Double rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator/(Double rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator*= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator*=(Double rhs)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mData[i] *= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator/= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator/=(Double rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator+ --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator+(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator+= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator+=(const Vector4 &rhs)
|
||||
{
|
||||
mData[0] += rhs.mData[0];
|
||||
mData[1] += rhs.mData[1];
|
||||
mData[2] += rhs.mData[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator-= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator-=(const Vector4 &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-()
|
||||
const
|
||||
{
|
||||
return Vector4(-X(), -Y(), -Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Length2 --
|
||||
*/
|
||||
Double
|
||||
Vector4::Length2()
|
||||
const
|
||||
{
|
||||
return X()*X() + Y()*Y() + Z()*Z();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Length --
|
||||
*/
|
||||
Double
|
||||
Vector4::Length()
|
||||
const
|
||||
{
|
||||
return std::sqrt(Length2());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Dot --
|
||||
*/
|
||||
Double
|
||||
Vector4::Dot(const Vector4& rhs)
|
||||
const
|
||||
{
|
||||
return X()*rhs.X() + Y()*rhs.Y() + Z()*rhs.Z();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Cross --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::Cross(const Vector4& rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(mData[1]*rhs.mData[2] - mData[2]*rhs.mData[1],
|
||||
mData[2]*rhs.mData[0] - mData[0]*rhs.mData[2],
|
||||
mData[0]*rhs.mData[1] - mData[1]*rhs.mData[0]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Normalize --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::Normalize()
|
||||
{
|
||||
return *this /= Length();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
Vector4
|
||||
operator*(Double lhs,
|
||||
const Vector4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Normalized --
|
||||
*/
|
||||
Vector4
|
||||
Normalized(Vector4 v)
|
||||
{
|
||||
return v.Normalize();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::LinearCombination --
|
||||
*/
|
||||
Vector4
|
||||
LinearCombination(const Double k1, const Vector4& v1,
|
||||
const Double k2, const Vector4& v2,
|
||||
const Double k3, const Vector4& v3)
|
||||
{
|
||||
return Vector4(k1 * v1.X() + k2 * v2.X() + k3 * v3.X(),
|
||||
k1 * v1.Y() + k2 * v2.Y() + k3 * v3.Y(),
|
||||
k1 * v1.Z() + k2 * v2.Z() + k3 * v3.Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Vector4& v)
|
||||
{
|
||||
// Stream the vector like this: <x, y, z>
|
||||
os << "<" << v.X() << ", " << v.Y() << ", " << v.Z() << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
110
src/basics/vector.hh
Normal file
110
src/basics/vector.hh
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* vector.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_VECTOR_HH__
|
||||
#define __BASICS_VECTOR_HH__
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "basics/matrix.hh"
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
/** A 4x1 matrix, used for specifying points and directions in 3D space. */
|
||||
struct Vector4
|
||||
{
|
||||
Vector4();
|
||||
Vector4(Double x, Double y, Double z);
|
||||
Vector4(Double x, Double y, Double z, Double w);
|
||||
|
||||
Vector4 &operator=(const Vector4 &rhs);
|
||||
|
||||
/**
|
||||
* @defgroup Component access
|
||||
* @{
|
||||
*/
|
||||
Double& X();
|
||||
Double X() const;
|
||||
Double& Y();
|
||||
Double Y() const;
|
||||
Double& Z();
|
||||
Double Z() const;
|
||||
|
||||
Double &operator()(UInt i);
|
||||
Double operator()(UInt i) const;
|
||||
|
||||
/** Get the underlying C array. */
|
||||
const Double *CArray() const;
|
||||
/** @} */
|
||||
|
||||
bool operator==(const Vector4 &rhs) const;
|
||||
bool operator!=(const Vector4 &rhs) const;
|
||||
|
||||
/**
|
||||
* @defgroup Scalar multiplication
|
||||
* @{
|
||||
*/
|
||||
Vector4 operator*(Double rhs) const;
|
||||
Vector4 operator/(Double rhs) const;
|
||||
Vector4 &operator*=(Double rhs);
|
||||
Vector4 &operator/=(Double rhs);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup Vector addition and subtraction
|
||||
* @{
|
||||
*/
|
||||
Vector4 operator+(const Vector4 &rhs) const;
|
||||
Vector4 operator-(const Vector4 &rhs) const;
|
||||
Vector4 &operator+=(const Vector4 &rhs);
|
||||
Vector4 &operator-=(const Vector4 &rhs);
|
||||
/** @} */
|
||||
|
||||
/** Negate this vector. */
|
||||
Vector4 operator-() const;
|
||||
|
||||
/** Get the length-squared of this vector. */
|
||||
Double Length2() const;
|
||||
|
||||
/** Get the length of this vector. */
|
||||
Double Length() const;
|
||||
|
||||
/** Get the dot product of `this` and `rhs`. */
|
||||
Double Dot(const Vector4 &rhs) const;
|
||||
|
||||
/** Get the cross product of `this` and `rhs`. */
|
||||
Vector4 Cross(const Vector4& rhs) const;
|
||||
|
||||
/** Normalize this vector. */
|
||||
Vector4& Normalize();
|
||||
|
||||
private:
|
||||
Double mData[4];
|
||||
};
|
||||
|
||||
|
||||
/** Scalar multiplication of vectors, with the scalar factor on the left. */
|
||||
Vector4 operator*(Double lhs, const Vector4 &rhs);
|
||||
|
||||
|
||||
/** Normalize a copy of the given vector. */
|
||||
Vector4 Normalized(Vector4 v);
|
||||
|
||||
|
||||
Vector4 LinearCombination(Double k1, const Vector4 &v1,
|
||||
Double k2, const Vector4 &v2,
|
||||
Double k3, const Vector4 &v3);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &ost, const Vector4 &v);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_VECTOR_HH__ */
|
||||
|
177
src/camera.cc
177
src/camera.cc
|
@ -3,29 +3,45 @@
|
|||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "camera.h"
|
||||
#include "camera.hh"
|
||||
#include "log.hh"
|
||||
|
||||
#define LOG_NAME "camera"
|
||||
#include "logModule.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
#pragma mark - Generic Camera
|
||||
|
||||
/*
|
||||
* charles::Camera::Camera --
|
||||
*/
|
||||
Camera::Camera()
|
||||
: mDirection(Vector3::Z),
|
||||
: mDirection(0, 0, 1),
|
||||
mRight(1.33, 0, 0),
|
||||
mUp(Vector3::Y)
|
||||
mUp(0, 1, 0)
|
||||
{ }
|
||||
|
||||
|
||||
Camera::Camera(const Camera& other)
|
||||
: mDirection(other.mDirection),
|
||||
mRight(other.mRight),
|
||||
mUp(other.mUp)
|
||||
/*
|
||||
* charles::Camera::Camera --
|
||||
*/
|
||||
Camera::Camera(const Camera& rhs)
|
||||
: mOrigin(rhs.mOrigin),
|
||||
mDirection(rhs.mDirection),
|
||||
mRight(rhs.mRight),
|
||||
mUp(rhs.mUp)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::~Camera --
|
||||
*/
|
||||
Camera::~Camera()
|
||||
{ }
|
||||
|
||||
|
@ -33,7 +49,17 @@ Camera::~Camera()
|
|||
/*
|
||||
* Camera::GetOrigin --
|
||||
*/
|
||||
const Vector3&
|
||||
Vector4&
|
||||
Camera::GetOrigin()
|
||||
{
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetOrigin --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetOrigin()
|
||||
const
|
||||
{
|
||||
|
@ -45,27 +71,57 @@ Camera::GetOrigin()
|
|||
* Camera::SetOrigin --
|
||||
*/
|
||||
void
|
||||
Camera::SetOrigin(const Vector3 &origin)
|
||||
Camera::SetOrigin(const Vector4& origin)
|
||||
{
|
||||
mOrigin = origin;
|
||||
}
|
||||
|
||||
|
||||
const Vector3&
|
||||
Camera::get_direction()
|
||||
/*
|
||||
* Camera::GetDirection --
|
||||
*/
|
||||
Vector4&
|
||||
Camera::GetDirection()
|
||||
{
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetDirection --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetDirection()
|
||||
const
|
||||
{
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetDirection --
|
||||
*/
|
||||
void
|
||||
Camera::set_direction(const Vector3 &direction)
|
||||
Camera::SetDirection(const Vector4& direction)
|
||||
{
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
|
||||
const Vector3&
|
||||
/*
|
||||
* Camera::GetRight --
|
||||
*/
|
||||
Vector4&
|
||||
Camera::GetRight()
|
||||
{
|
||||
return mRight;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetRight --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetRight()
|
||||
const
|
||||
{
|
||||
|
@ -73,14 +129,30 @@ Camera::GetRight()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetRight --
|
||||
*/
|
||||
void
|
||||
Camera::SetRight(const Vector3& right)
|
||||
Camera::SetRight(const Vector4& right)
|
||||
{
|
||||
mRight = right;
|
||||
}
|
||||
|
||||
|
||||
const Vector3&
|
||||
/*
|
||||
* Camera::GetUp --
|
||||
*/
|
||||
Vector4&
|
||||
Camera::GetUp()
|
||||
{
|
||||
return mUp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetUp --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetUp()
|
||||
const
|
||||
{
|
||||
|
@ -88,13 +160,19 @@ Camera::GetUp()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetUp --
|
||||
*/
|
||||
void
|
||||
Camera::SetUp(const Vector3& up)
|
||||
Camera::SetUp(const Vector4& up)
|
||||
{
|
||||
mUp = up;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::IsLeftHanded --
|
||||
*/
|
||||
bool
|
||||
Camera::IsLeftHanded()
|
||||
const
|
||||
|
@ -110,24 +188,27 @@ Camera::IsLeftHanded()
|
|||
* than 0, the vector is pointing left of the up-direction plane and the
|
||||
* coordinate system is left-handed.
|
||||
*/
|
||||
return mUp.cross(mDirection).dot(mRight) < 0.0;
|
||||
return mUp.Cross(mDirection).Dot(mRight) < 0.0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::LookAt --
|
||||
*/
|
||||
void
|
||||
Camera::LookAt(const Vector3& pt)
|
||||
Camera::LookAt(const Vector4& p)
|
||||
{
|
||||
/*
|
||||
* Precalulate these in order to preserve the aspect ratio and orientation
|
||||
* of the camera across the LookAt operation.
|
||||
*/
|
||||
const Double directionLength = mDirection.length();
|
||||
const Double rightLength = mRight.length();
|
||||
const Double upLength = mUp.length();
|
||||
const Double directionLength = mDirection.Length();
|
||||
const Double rightLength = mRight.Length();
|
||||
const Double upLength = mUp.Length();
|
||||
const bool isLeftHanded = IsLeftHanded();
|
||||
|
||||
/* Orient the camera towards the point. */
|
||||
mDirection = (pt - mOrigin).normalize();
|
||||
mDirection = basics::Normalized(p - mOrigin);
|
||||
/* TODO: Check for zero length direction vector. */
|
||||
|
||||
/*
|
||||
|
@ -141,8 +222,8 @@ Camera::LookAt(const Vector3& pt)
|
|||
* specifies the vector along which LookAt pans and tilts the camera. It
|
||||
* might be worth looking into, at some point.
|
||||
*/
|
||||
mRight = Vector3::Y.cross(mDirection).normalize();
|
||||
mUp = mDirection.cross(mRight);
|
||||
mRight = basics::Normalized(Vector4(0, 1, 0).Cross(mDirection));
|
||||
mUp = mDirection.Cross(mRight);
|
||||
|
||||
/*
|
||||
* Now, fix up the direction, right, and up vectors so that their magnitudes
|
||||
|
@ -152,10 +233,13 @@ Camera::LookAt(const Vector3& pt)
|
|||
mRight *= isLeftHanded ? rightLength : -rightLength;
|
||||
mUp *= upLength;
|
||||
|
||||
LOG_DEBUG << "Camera is looking at " << pt;
|
||||
LOG_DEBUG << "Camera is looking at " << p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::GetTypeString --
|
||||
*/
|
||||
std::string
|
||||
Camera::GetTypeString()
|
||||
const
|
||||
|
@ -164,6 +248,9 @@ Camera::GetTypeString()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::WriteType --
|
||||
*/
|
||||
void
|
||||
Camera::WriteType(std::ostream& ost)
|
||||
const
|
||||
|
@ -184,23 +271,23 @@ PerspectiveCamera::PerspectiveCamera(const Camera& other)
|
|||
|
||||
|
||||
Ray
|
||||
PerspectiveCamera::compute_primary_ray(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
PerspectiveCamera::PrimaryRay(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
const
|
||||
{
|
||||
/*
|
||||
* Center x and y in the pixel and convert them to be coordinates between
|
||||
* -0.5 and 0.5.
|
||||
*/
|
||||
double x0 = (x + 0.5) / width - 0.5;
|
||||
double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
Double x0 = (x + 0.5) / width - 0.5;
|
||||
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
|
||||
Vector3 direction = LinearCombination(1.0, get_direction(),
|
||||
Vector4 direction = LinearCombination(1.0, GetDirection(),
|
||||
x0, GetRight(),
|
||||
y0, GetUp());
|
||||
return Ray(GetOrigin(), direction.normalize());
|
||||
return Ray(GetOrigin(), basics::Normalized(direction));
|
||||
}
|
||||
|
||||
|
||||
|
@ -226,30 +313,24 @@ OrthographicCamera::OrthographicCamera(const Camera& other)
|
|||
/*
|
||||
* OrthographicCamera::compute_primary_ray --
|
||||
*/
|
||||
/**
|
||||
* Compute a primary ray given an (x,y) coordinate pair. The orthographic camera
|
||||
* projects rays parallel to the viewing direction through the (x,y) coordinate
|
||||
* given. Thus, the size of the orthographic camera should be set to the size of
|
||||
* the view into the scene.
|
||||
*/
|
||||
Ray
|
||||
OrthographicCamera::compute_primary_ray(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
OrthographicCamera::PrimaryRay(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
const
|
||||
{
|
||||
/*
|
||||
* Center x and y in the pixel and convert them to be coordinates between
|
||||
* -0.5 and 0.5.
|
||||
*/
|
||||
double x0 = (x + 0.5) / width + 0.5;
|
||||
double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
Double x0 = (x + 0.5) / width + 0.5;
|
||||
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
|
||||
Vector3 origin = LinearCombination(1.0, GetOrigin(),
|
||||
Vector4 origin = LinearCombination(1.0, GetOrigin(),
|
||||
x0, GetRight(),
|
||||
y0, GetUp());
|
||||
return Ray(origin, get_direction());
|
||||
return Ray(origin, GetDirection());
|
||||
}
|
||||
|
||||
|
||||
|
@ -274,3 +355,5 @@ operator<<(std::ostream& ost,
|
|||
<< "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
117
src/camera.h
117
src/camera.h
|
@ -1,117 +0,0 @@
|
|||
/* camera.h
|
||||
*
|
||||
* The Camera is the eye into the scene. It defines several parameters and a
|
||||
* single compute_primary_ray method that generates rays with which the ray
|
||||
* tracer draws the scene.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __CAMERA_H__
|
||||
#define __CAMERA_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
|
||||
struct Camera
|
||||
{
|
||||
typedef std::shared_ptr<Camera> Ptr;
|
||||
|
||||
Camera();
|
||||
Camera(const Camera& other);
|
||||
virtual ~Camera();
|
||||
|
||||
const Vector3& GetOrigin() const;
|
||||
void SetOrigin(const Vector3& origin);
|
||||
|
||||
const Vector3& get_direction() const;
|
||||
void set_direction(const Vector3& direction);
|
||||
|
||||
const Vector3& GetRight() const;
|
||||
void SetRight(const Vector3& right);
|
||||
|
||||
const Vector3& GetUp() const;
|
||||
void SetUp(const Vector3& up);
|
||||
|
||||
/**
|
||||
* Get the camera's handedness. Left handed is the default.
|
||||
*
|
||||
* @returns `true` if the camera is set up for left-handed coordinates.
|
||||
*/
|
||||
bool IsLeftHanded() const;
|
||||
|
||||
/**
|
||||
* Pan and tilt the camera towards the given point.
|
||||
*
|
||||
* @param [in] pt The point at which to face the camera
|
||||
*/
|
||||
void LookAt(const Vector3& pt);
|
||||
|
||||
virtual Ray compute_primary_ray(const int x, const int width,
|
||||
const int y, const int height) const = 0;
|
||||
|
||||
virtual std::string GetTypeString() const;
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
void WriteType(std::ostream& ost) const;
|
||||
|
||||
/**
|
||||
* The location of the camera in the scene. Depending on the type of camera,
|
||||
* this is the point from which rays will be emitted.
|
||||
*/
|
||||
Vector3 mOrigin;
|
||||
|
||||
/** A normalized vector defining where the camera is pointed. */
|
||||
Vector3 mDirection;
|
||||
|
||||
/**
|
||||
* A vector defining the width of the camera's image plane. The ratio of
|
||||
* this and mUp determine the aspect ratio of the image.
|
||||
*/
|
||||
Vector3 mRight;
|
||||
|
||||
/**
|
||||
* A vector defining the height of the camera's image plane. The ratio of
|
||||
* this and mRight determine the aspect ratio of the image.
|
||||
*/
|
||||
Vector3 mUp;
|
||||
};
|
||||
|
||||
|
||||
class PerspectiveCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
PerspectiveCamera();
|
||||
PerspectiveCamera(const Camera& other);
|
||||
|
||||
Ray compute_primary_ray(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
class OrthographicCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
OrthographicCamera();
|
||||
OrthographicCamera(const Camera& other);
|
||||
|
||||
Ray compute_primary_ray(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
#endif
|
124
src/camera.hh
Normal file
124
src/camera.hh
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* camera.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __CAMERA_H__
|
||||
#define __CAMERA_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* The Camera is the eye into the scene. It defines several parameters and a
|
||||
* single compute_primary_ray method that generates rays with which the ray
|
||||
* tracer draws the scene.
|
||||
*/
|
||||
struct Camera
|
||||
{
|
||||
typedef std::shared_ptr<Camera> Ptr;
|
||||
|
||||
Camera();
|
||||
Camera(const Camera& other);
|
||||
virtual ~Camera();
|
||||
|
||||
basics::Vector4& GetOrigin();
|
||||
const basics::Vector4& GetOrigin() const;
|
||||
void SetOrigin(const basics::Vector4& origin);
|
||||
|
||||
basics::Vector4& GetDirection();
|
||||
const basics::Vector4& GetDirection() const;
|
||||
void SetDirection(const basics::Vector4& direction);
|
||||
|
||||
basics::Vector4& GetRight();
|
||||
const basics::Vector4& GetRight() const;
|
||||
void SetRight(const basics::Vector4& right);
|
||||
|
||||
basics::Vector4& GetUp();
|
||||
const basics::Vector4& GetUp() const;
|
||||
void SetUp(const basics::Vector4& up);
|
||||
|
||||
/** Get the camera's handedness. Left handed is the default. */
|
||||
bool IsLeftHanded() const;
|
||||
|
||||
/** Pan and tilt the camera towards the given point. */
|
||||
void LookAt(const basics::Vector4& p);
|
||||
|
||||
virtual basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const = 0;
|
||||
|
||||
virtual std::string GetTypeString() const;
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
void WriteType(std::ostream& ost) const;
|
||||
|
||||
/**
|
||||
* The location of the camera in the scene. Depending on the type of camera,
|
||||
* this is the point from which rays will be emitted.
|
||||
*/
|
||||
basics::Vector4 mOrigin;
|
||||
|
||||
/** A vector defining where the camera is pointed. */
|
||||
basics::Vector4 mDirection;
|
||||
|
||||
/**
|
||||
* A vector defining the width of the camera's image plane. The ratio of
|
||||
* this and mUp determine the aspect ratio of the image.
|
||||
*/
|
||||
basics::Vector4 mRight;
|
||||
|
||||
/**
|
||||
* A vector defining the height of the camera's image plane. The ratio of
|
||||
* this and mRight determine the aspect ratio of the image.
|
||||
*/
|
||||
basics::Vector4 mUp;
|
||||
};
|
||||
|
||||
|
||||
class PerspectiveCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
PerspectiveCamera();
|
||||
PerspectiveCamera(const Camera& other);
|
||||
|
||||
basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
class OrthographicCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
OrthographicCamera();
|
||||
OrthographicCamera(const Camera& other);
|
||||
|
||||
/**
|
||||
* Compute a primary ray given an (x,y) coordinate pair. The orthographic
|
||||
* camera projects rays parallel to the viewing direction through the (x,y)
|
||||
* coordinate given. Thus, the size of the orthographic camera should be set
|
||||
* to the size of the view into the scene.
|
||||
*/
|
||||
basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
|
@ -8,18 +8,19 @@
|
|||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "basics.h"
|
||||
#include "log.hh"
|
||||
#include "light.h"
|
||||
#include "light.hh"
|
||||
#include "reader_yaml.hh"
|
||||
#include "scene.h"
|
||||
#include "scene.hh"
|
||||
#include "writer_png.h"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
#define LOG_NAME "ROOT"
|
||||
#include "logModule.hh"
|
||||
|
||||
|
||||
int verbosity = 0;
|
||||
using namespace charles;
|
||||
using namespace charles::basics;
|
||||
|
||||
|
||||
static void
|
||||
|
@ -38,37 +39,10 @@ main(int argc,
|
|||
|
||||
Scene scene;
|
||||
|
||||
scene.get_ambient().set_intensity(1.0);
|
||||
PointLight *l1 = new PointLight(Vector4(4.0, 6.0, 1.0), Color::White, 0.8);
|
||||
scene.AddLight(l1);
|
||||
|
||||
#if 0
|
||||
Material *m1 = new Material();
|
||||
m1->set_diffuse_color(Color::Red);
|
||||
Material *m2 = new Material();
|
||||
m2->set_diffuse_color(Color::Green);
|
||||
Material *m3 = new Material();
|
||||
m3->set_diffuse_color(Color::Blue);
|
||||
|
||||
// Make some spheres.
|
||||
Sphere *s1 = new Sphere(Vector3(0, 0.5, 2), 0.33);
|
||||
Sphere *s2 = new Sphere(Vector3(-0.33, 0, 2), 0.33);
|
||||
Sphere *s3 = new Sphere(Vector3(0.33, 0, 2), 0.33);
|
||||
s1->set_material(m1);
|
||||
s2->set_material(m2);
|
||||
s3->set_material(m3);
|
||||
scene.add_shape(s1);
|
||||
scene.add_shape(s2);
|
||||
scene.add_shape(s3);
|
||||
|
||||
// Make a plane
|
||||
/*
|
||||
Plane *p1 = new Plane(Vector3(0, 460, 400), Vector3(0, 1, 0.01));
|
||||
p1->set_material(m1);
|
||||
scene.add_shape(p1);
|
||||
*/
|
||||
#endif
|
||||
|
||||
PointLight *l1 = new PointLight(Vector3(4.0, 6.0, 1.0), Color::White, 0.8);
|
||||
scene.add_light(l1);
|
||||
bool shouldRender = true;
|
||||
|
||||
std::string logFilename;
|
||||
unsigned int logLevel = 0;
|
||||
|
@ -76,7 +50,7 @@ main(int argc,
|
|||
std::string outfile, infile;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, (char *const *)argv, "hl:L:o:v:")) != -1) {
|
||||
while ((opt = getopt(argc, (char *const *)argv, "hl:L:no:v:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
|
@ -88,6 +62,9 @@ main(int argc,
|
|||
case 'L':
|
||||
logLevel = std::stoul(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
shouldRender = false;
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
|
@ -124,12 +101,14 @@ main(int argc,
|
|||
}
|
||||
|
||||
/* Call tracer. */
|
||||
LOG_INFO << "Beginning render";
|
||||
scene.render();
|
||||
if (shouldRender) {
|
||||
LOG_INFO << "Beginning render";
|
||||
scene.Render();
|
||||
|
||||
/* Write rendered scene to PNG file. */
|
||||
PNGWriter writer;
|
||||
scene.write(writer, outfile);
|
||||
/* Write rendered scene to PNG file. */
|
||||
PNGWriter writer;
|
||||
scene.Write(writer, outfile);
|
||||
}
|
||||
|
||||
if (logLevel > 0) {
|
||||
Log::Close();
|
||||
|
|
141
src/light.cc
141
src/light.cc
|
@ -1,112 +1,81 @@
|
|||
/* light.cc
|
||||
*
|
||||
* Lights light the scene.
|
||||
*
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include "light.h"
|
||||
#include "object.h"
|
||||
#include "light.hh"
|
||||
|
||||
#pragma mark - Ambient Lights
|
||||
|
||||
AmbientLight::AmbientLight()
|
||||
: AmbientLight(Color::White)
|
||||
using charles::basics::Color;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
Light::Light(const Color& color,
|
||||
const Double& intensity)
|
||||
: mColor(color),
|
||||
mIntensity(ClampIntensity(intensity))
|
||||
{ }
|
||||
|
||||
|
||||
AmbientLight::AmbientLight(const Color &c)
|
||||
: AmbientLight(c, 0.0)
|
||||
Light::~Light()
|
||||
{ }
|
||||
|
||||
|
||||
AmbientLight::AmbientLight(const Color &c, const float &i)
|
||||
: color(c),
|
||||
intensity(i)
|
||||
Color&
|
||||
Light::GetColor()
|
||||
{
|
||||
_clamp_intensity();
|
||||
return mColor;
|
||||
}
|
||||
|
||||
|
||||
const Color &
|
||||
AmbientLight::get_color()
|
||||
const Color&
|
||||
Light::GetColor()
|
||||
const
|
||||
{
|
||||
return color;
|
||||
return mColor;
|
||||
}
|
||||
|
||||
|
||||
const float &
|
||||
AmbientLight::get_intensity()
|
||||
void
|
||||
Light::SetColor(const Color& color)
|
||||
{
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Light::GetIntensity()
|
||||
const
|
||||
{
|
||||
return mIntensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Light::SetIntensity(const Double& intensity)
|
||||
{
|
||||
mIntensity = ClampIntensity(intensity);
|
||||
}
|
||||
|
||||
|
||||
Color&&
|
||||
Light::Contribution()
|
||||
const
|
||||
{
|
||||
return mColor * mIntensity;
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Light::ClampIntensity(const Double& intensity)
|
||||
{
|
||||
if (intensity < 0.0) {
|
||||
return 0.0;
|
||||
} else if (intensity > 1.0) {
|
||||
return 1.0;
|
||||
}
|
||||
return intensity;
|
||||
}
|
||||
|
||||
void
|
||||
AmbientLight::set_intensity(const float &i)
|
||||
{
|
||||
intensity = i;
|
||||
_clamp_intensity();
|
||||
}
|
||||
|
||||
|
||||
Color
|
||||
AmbientLight::compute_color_contribution()
|
||||
const
|
||||
{
|
||||
return color * intensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AmbientLight::_clamp_intensity()
|
||||
{
|
||||
if (intensity < 0.0) {
|
||||
intensity = 0.0;
|
||||
}
|
||||
else if (intensity > 1.0) {
|
||||
intensity = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Point Lights
|
||||
|
||||
PointLight::PointLight()
|
||||
: PointLight(Vector3())
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o)
|
||||
: PointLight(o, Color::White)
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o,
|
||||
const Color &c)
|
||||
: PointLight(o, c, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o,
|
||||
const Color &c,
|
||||
const float &i)
|
||||
: AmbientLight(c, i),
|
||||
mOrigin(o)
|
||||
{ }
|
||||
|
||||
|
||||
const Vector3&
|
||||
PointLight::GetOrigin()
|
||||
const
|
||||
{
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PointLight::SetOrigin(const Vector3& origin)
|
||||
{
|
||||
mOrigin = origin;
|
||||
}
|
||||
} /* namespace charles */
|
||||
|
|
53
src/light.h
53
src/light.h
|
@ -1,53 +0,0 @@
|
|||
/* light.h
|
||||
*
|
||||
* Lights light the scene.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHT_H__
|
||||
#define __LIGHT_H__
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
|
||||
class AmbientLight
|
||||
{
|
||||
public:
|
||||
AmbientLight();
|
||||
AmbientLight(const Color &c);
|
||||
AmbientLight(const Color &c, const float &i);
|
||||
|
||||
const Color &get_color() const;
|
||||
const float &get_intensity() const;
|
||||
void set_intensity(const float &i);
|
||||
|
||||
Color compute_color_contribution() const;
|
||||
|
||||
protected:
|
||||
Color color;
|
||||
float intensity;
|
||||
|
||||
private:
|
||||
void _clamp_intensity();
|
||||
};
|
||||
|
||||
|
||||
class PointLight
|
||||
: public AmbientLight
|
||||
{
|
||||
public:
|
||||
PointLight();
|
||||
|
||||
PointLight(const Vector3 &o);
|
||||
PointLight(const Vector3 &o, const Color &c);
|
||||
PointLight(const Vector3 &o, const Color &c, const float &i);
|
||||
|
||||
const Vector3& GetOrigin() const;
|
||||
void SetOrigin(const Vector3& origin);
|
||||
|
||||
private:
|
||||
Vector3 mOrigin;
|
||||
};
|
||||
|
||||
#endif
|
52
src/light.hh
Normal file
52
src/light.hh
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* light.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHT_H__
|
||||
#define __LIGHT_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
struct Light
|
||||
{
|
||||
typedef std::shared_ptr<Light> Ptr;
|
||||
|
||||
Light(const basics::Color& color,
|
||||
const Double& intensity = 1.0);
|
||||
|
||||
virtual ~Light();
|
||||
|
||||
basics::Color& GetColor();
|
||||
const basics::Color& GetColor() const;
|
||||
void SetColor(const basics::Color& color);
|
||||
|
||||
Double GetIntensity() const;
|
||||
void SetIntensity(const Double& intensity);
|
||||
|
||||
virtual basics::Color&& Contribution() const;
|
||||
|
||||
private:
|
||||
Double ClampIntensity(const Double& intensity);
|
||||
|
||||
/** The color of the light. */
|
||||
basics::Color mColor;
|
||||
|
||||
/**
|
||||
* The intensity of the light. Normal values range from 0.0 to 1.0, but
|
||||
* they can be set higher.
|
||||
*/
|
||||
Double mIntensity;
|
||||
};
|
||||
|
||||
|
||||
typedef Light AmbientLight;
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
37
src/lightPoint.cc
Normal file
37
src/lightPoint.cc
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* lightPoint.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "lightPoint.hh"
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
PointLight::PointLight(const Vector4& origin,
|
||||
const Color& color,
|
||||
const Double& intensity)
|
||||
: Light(color, intensity),
|
||||
mOrigin(origin)
|
||||
{ }
|
||||
|
||||
|
||||
Vector4&
|
||||
PointLight::GetOrigin()
|
||||
{
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PointLight::SetOrigin(const Vector4& origin)
|
||||
{
|
||||
mOrigin = origin;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
35
src/lightPoint.hh
Normal file
35
src/lightPoint.hh
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* lightPoint.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHTPOINT_HH__
|
||||
#define __LIGHTPOINT_HH__
|
||||
|
||||
#include "light.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* The simplest light source. Emits light in all directions uniformly, without
|
||||
* falloff.
|
||||
*/
|
||||
class PointLight
|
||||
: public Light
|
||||
{
|
||||
public:
|
||||
PointLight(const basics::Vector4 &origin,
|
||||
const basics::Color& color,
|
||||
const Double& intensity);
|
||||
|
||||
basics::Vector4& GetOrigin();
|
||||
void SetOrigin(const basics::Vector4& origin);
|
||||
|
||||
private:
|
||||
basics::Vector4 mOrigin;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __LIGHTPOINT_HH__ */
|
|
@ -69,8 +69,8 @@ struct Tracer
|
|||
~Tracer();
|
||||
|
||||
private:
|
||||
const std::string& mName;
|
||||
const std::string& mFunction;
|
||||
const std::string mName;
|
||||
const std::string mFunction;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/* material.h
|
||||
*
|
||||
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
|
||||
*
|
||||
/* material.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "material.h"
|
||||
#include "material.hh"
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
@ -36,9 +37,8 @@ Material::SetDiffuseIntensity(const Double& kd)
|
|||
}
|
||||
|
||||
|
||||
const Color&
|
||||
Color&
|
||||
Material::GetDiffuseColor()
|
||||
const
|
||||
{
|
||||
return mDiffuseColor;
|
||||
}
|
||||
|
@ -67,9 +67,8 @@ Material::SetSpecularIntensity(const Double& ks)
|
|||
}
|
||||
|
||||
|
||||
const Color&
|
||||
Color&
|
||||
Material::GetSpecularColor()
|
||||
const
|
||||
{
|
||||
return mSpecularColor;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
/* material.h
|
||||
*
|
||||
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
|
||||
*
|
||||
/* material.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __MATERIAL_H__
|
||||
#define __MATERIAL_H__
|
||||
#ifndef __MATERIAL_HH__
|
||||
#define __MATERIAL_HH__
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
#include "basics.h"
|
||||
#include "types.hh"
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* Materials are applied to shapes and determine color, texture mapping,
|
||||
* shading, etc.
|
||||
*/
|
||||
struct Material
|
||||
{
|
||||
enum class DiffuseShaderModel {
|
||||
|
@ -29,14 +31,14 @@ struct Material
|
|||
Double GetDiffuseIntensity() const;
|
||||
void SetDiffuseIntensity(const Double& kd);
|
||||
|
||||
const Color& GetDiffuseColor() const;
|
||||
void SetDiffuseColor(const Color& c);
|
||||
basics::Color& GetDiffuseColor();
|
||||
void SetDiffuseColor(const basics::Color& c);
|
||||
|
||||
Double GetSpecularIntensity() const;
|
||||
void SetSpecularIntensity(const Double& kd);
|
||||
|
||||
const Color &GetSpecularColor() const;
|
||||
void SetSpecularColor(const Color& c);
|
||||
basics::Color& GetSpecularColor();
|
||||
void SetSpecularColor(const basics::Color& c);
|
||||
|
||||
private:
|
||||
void ClampParameter(Double& param);
|
||||
|
@ -44,12 +46,12 @@ private:
|
|||
// Diffuse parameters.
|
||||
DiffuseShaderModel mDiffuseModel;
|
||||
Double mDiffuseIntensity;
|
||||
Color mDiffuseColor;
|
||||
basics::Color mDiffuseColor;
|
||||
|
||||
// Specular parameters.
|
||||
SpecularShaderModel mSpecularModel;
|
||||
Double mSpecularIntensity;
|
||||
Color mSpecularColor;
|
||||
basics::Color mSpecularColor;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
133
src/object.cc
133
src/object.cc
|
@ -9,54 +9,38 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "basics.h"
|
||||
#include "material.h"
|
||||
#include "object.h"
|
||||
#include "object.hh"
|
||||
|
||||
#include "material.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Matrix4;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
#pragma mark - Objects
|
||||
|
||||
/*
|
||||
* Object::Object --
|
||||
*
|
||||
* Default constructor. Create a new Object with an origin at (0, 0, 0).
|
||||
* charles::Object::Object --
|
||||
*/
|
||||
Object::Object()
|
||||
: Object(Vector3::Zero)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Object::Object --
|
||||
*
|
||||
* Constructor. Create a new Object with an origin at o.
|
||||
*/
|
||||
Object::Object(Vector3 origin)
|
||||
: mOrigin(origin),
|
||||
Object::Object(const Vector4& origin)
|
||||
: mTranslation(Matrix4::Translation(origin)),
|
||||
mMaterial()
|
||||
{ }
|
||||
|
||||
|
||||
Vector3
|
||||
Object::GetOrigin()
|
||||
const
|
||||
{
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::~Object --
|
||||
*/
|
||||
Object::~Object()
|
||||
{ }
|
||||
|
||||
|
||||
void
|
||||
Object::SetOrigin(const Vector3& origin)
|
||||
{
|
||||
mOrigin = origin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::GetMaterial --
|
||||
*/
|
||||
Material&
|
||||
Object::GetMaterial()
|
||||
{
|
||||
|
@ -64,6 +48,19 @@ Object::GetMaterial()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Place --
|
||||
*/
|
||||
void
|
||||
Object::Place(const Vector4 &p)
|
||||
{
|
||||
mTranslation = Matrix4::Translation(p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::SetMaterial --
|
||||
*/
|
||||
void
|
||||
Object::SetMaterial(const Material& material)
|
||||
{
|
||||
|
@ -71,6 +68,67 @@ Object::SetMaterial(const Material& material)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Intersect --
|
||||
*/
|
||||
bool
|
||||
Object::Intersect(const basics::Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
const
|
||||
{
|
||||
return DoIntersect(ToObjectSpace(ray), t, stats);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Normal --
|
||||
*/
|
||||
Vector4
|
||||
Object::Normal(const Vector4& p)
|
||||
const
|
||||
{
|
||||
return FromObjectSpace(DoNormal(ToObjectSpace(p)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::ToObjectSpace --
|
||||
*/
|
||||
Ray
|
||||
Object::ToObjectSpace(Ray ray)
|
||||
const
|
||||
{
|
||||
ray.origin = mTranslation * ray.origin;
|
||||
return ray;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::ToObjectSpace --
|
||||
*/
|
||||
Vector4
|
||||
Object::ToObjectSpace(const Vector4& v)
|
||||
const
|
||||
{
|
||||
return mTranslation * v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::FromObjectSpace --
|
||||
*/
|
||||
Vector4
|
||||
Object::FromObjectSpace(const Vector4& v)
|
||||
const
|
||||
{
|
||||
return Inverse(mTranslation) * v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Write --
|
||||
*/
|
||||
void
|
||||
Object::Write(std::ostream& ost)
|
||||
const
|
||||
|
@ -79,11 +137,16 @@ Object::Write(std::ostream& ost)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& ost,
|
||||
const Object& object)
|
||||
{
|
||||
ost << "[";
|
||||
object.Write(ost);
|
||||
ost << " translate=" << object.mTranslation.Column(3) << "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
|
|
72
src/object.h
72
src/object.h
|
@ -1,72 +0,0 @@
|
|||
/* object.h
|
||||
*
|
||||
* Declaration of abstract, top-level scene objects. The Object class is the top of this hierarchy. All other scene
|
||||
* objects are based on it. The Shape class defines a visible shape in the scene.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __OBJECT_H__
|
||||
#define __OBJECT_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "basics.h"
|
||||
#include "material.h"
|
||||
#include "stats.hh"
|
||||
#include "texture.h"
|
||||
#include "types.hh"
|
||||
|
||||
namespace charles {
|
||||
|
||||
struct Object
|
||||
{
|
||||
typedef std::shared_ptr<Object> Ptr;
|
||||
|
||||
Object();
|
||||
Object(Vector3 o);
|
||||
virtual ~Object();
|
||||
|
||||
Vector3 GetOrigin() const;
|
||||
void SetOrigin(const Vector3& origin);
|
||||
|
||||
Material& GetMaterial();
|
||||
void SetMaterial(const Material& material);
|
||||
|
||||
/**
|
||||
* Determines if the given ray intersects with this object. All intersection
|
||||
* t values are returned in the `t` argument, in increasing order.
|
||||
*
|
||||
* @param [in] ray The ray to test for intersection
|
||||
* @param [out] t A vector of all intersection t values
|
||||
* @return `true` if the ray intersects with this object
|
||||
*/
|
||||
virtual bool DoesIntersect(const Ray& ray, TVector& t, Stats& stats) const = 0;
|
||||
virtual bool point_is_on_surface(const Vector3 &p) const = 0;
|
||||
virtual Vector3 compute_normal(const Vector3 &p) const = 0;
|
||||
|
||||
virtual void Write(std::ostream& ost) const;
|
||||
|
||||
private:
|
||||
/** The location of this object. */
|
||||
Vector3 mOrigin;
|
||||
|
||||
/** This object's material, surface properties, etc. */
|
||||
Material mMaterial;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Write a string representation of the Object to an output stream.
|
||||
*
|
||||
* @param [in] ost The output stream
|
||||
* @param [in] object The object
|
||||
* @returns The output stream
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& ost, const Object& object);
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
89
src/object.hh
Normal file
89
src/object.hh
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* object.h
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __OBJECT_H__
|
||||
#define __OBJECT_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "material.hh"
|
||||
#include "stats.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
struct Object
|
||||
{
|
||||
typedef std::shared_ptr<Object> Ptr;
|
||||
|
||||
Object(const basics::Vector4& origin = basics::Vector4());
|
||||
virtual ~Object();
|
||||
|
||||
Material& GetMaterial();
|
||||
void SetMaterial(const Material& material);
|
||||
|
||||
void Place(const basics::Vector4 &p);
|
||||
|
||||
/**
|
||||
* Determine if the given ray intersects with this object. Converts the
|
||||
* ray's origin and direction to object space before calling the protected
|
||||
* Object::DoIntersect method. All intersection t values are returned in the
|
||||
* `t` argument, in ascending order.
|
||||
*/
|
||||
bool Intersect(const basics::Ray& ray, TVector& t, Stats& stats) const;
|
||||
|
||||
/**
|
||||
* Get the normal vector at the given point p. p is assumed to be on the
|
||||
* surface.
|
||||
*/
|
||||
basics::Vector4 Normal(const basics::Vector4& p) const;
|
||||
|
||||
/** Write a string representation of this object to the stream. */
|
||||
virtual void Write(std::ostream& ost) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Do the actual intersection work. Subclasses are expected to override
|
||||
* this.
|
||||
*/
|
||||
virtual bool DoIntersect(const basics::Ray& ray, TVector& t, Stats& stats) const = 0;
|
||||
|
||||
/**
|
||||
* Do the actual work of finding a normal for point p. Subclasses are
|
||||
* expected to override this.
|
||||
*/
|
||||
virtual basics::Vector4 DoNormal(const basics::Vector4& p) const = 0;
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& ost, const Object& object);
|
||||
|
||||
|
||||
/** Convert `ray` to object space from global space. */
|
||||
basics::Ray ToObjectSpace(basics::Ray ray) const;
|
||||
|
||||
/** Convert `v` to object space from global space. */
|
||||
basics::Vector4 ToObjectSpace(const basics::Vector4& v) const;
|
||||
|
||||
/** Convert `v` to global space from object space. */
|
||||
basics::Vector4 FromObjectSpace(const basics::Vector4& v) const;
|
||||
|
||||
|
||||
/** A translation matrix from global coordinates to this object's space. */
|
||||
basics::Matrix4 mTranslation;
|
||||
|
||||
/** This object's material, surface properties, etc. */
|
||||
Material mMaterial;
|
||||
};
|
||||
|
||||
|
||||
/** Write a string representation of the Object to an output stream. */
|
||||
std::ostream& operator<<(std::ostream& ost, const Object& object);
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
192
src/objectBox.cc
192
src/objectBox.cc
|
@ -8,66 +8,153 @@
|
|||
#include "objectBox.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* charles::Box::Box --
|
||||
*/
|
||||
Box::Box()
|
||||
/* A unit box centered on the origin. */
|
||||
: Box(Vector3(-0.5, -0.5, -0.5), Vector3(0.5, 0.5, 0.5))
|
||||
: Box(Vector4(-0.5, -0.5, -0.5), Vector4(0.5, 0.5, 0.5))
|
||||
{ }
|
||||
|
||||
|
||||
Box::Box(const Vector3& near, const Vector3& far)
|
||||
/*
|
||||
* charles::Box::Box --
|
||||
*/
|
||||
Box::Box(const Vector4& near,
|
||||
const Vector4& far)
|
||||
: Object(),
|
||||
mNear(near),
|
||||
mFar(far)
|
||||
{ }
|
||||
|
||||
|
||||
Vector3&
|
||||
/*
|
||||
* charles::Box::GetNear --
|
||||
*/
|
||||
Vector4&
|
||||
Box::GetNear()
|
||||
{
|
||||
return mNear;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::SetNear --
|
||||
*/
|
||||
void
|
||||
Box::SetNear(const Vector3& near)
|
||||
Box::SetNear(const Vector4& near)
|
||||
{
|
||||
mNear = near;
|
||||
}
|
||||
|
||||
|
||||
Vector3&
|
||||
/*
|
||||
* charles::Box::GetFar --
|
||||
*/
|
||||
Vector4&
|
||||
Box::GetFar()
|
||||
{
|
||||
return mFar;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::SetFar --
|
||||
*/
|
||||
void
|
||||
Box::SetFar(const Vector3& far)
|
||||
Box::SetFar(const Vector4& far)
|
||||
{
|
||||
mFar = far;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::DoNormal --
|
||||
*/
|
||||
Vector4
|
||||
Box::DoNormal(const Vector4& p)
|
||||
const
|
||||
{
|
||||
if (NearlyEqual(p.X(), mNear.X())) {
|
||||
return Vector4(-1, 0, 0);
|
||||
} else if (NearlyEqual(p.X(), mFar.X())) {
|
||||
return Vector4(1, 0, 0);
|
||||
} else if (NearlyEqual(p.Y(), mNear.Y())) {
|
||||
return Vector4(0, -1, 0);
|
||||
} else if (NearlyEqual(p.Y(), mFar.Y())) {
|
||||
return Vector4(0, 1, 0);
|
||||
} else if (NearlyEqual(p.Z(), mNear.Z())) {
|
||||
return Vector4(0, 0, -1);
|
||||
} else if (NearlyEqual(p.Z(), mFar.Z())) {
|
||||
return Vector4(0, 0, 1);
|
||||
}
|
||||
|
||||
/* TODO: Eventually, I might want to raise an error here. */
|
||||
return Vector4();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::DoIntersect --
|
||||
*/
|
||||
bool
|
||||
Box::DoesIntersect(const Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
Box::DoIntersect(const Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
const
|
||||
{
|
||||
stats.boxIntersectionTests++;
|
||||
|
||||
/*
|
||||
* XXX: For now, I'm assuming that all boxes are parallel to the coordinate
|
||||
* axes. This is the Kay-Kajiya box intersection algorithm.
|
||||
*/
|
||||
/* This is the Kay-Kajiya box intersection algorithm. */
|
||||
|
||||
//Double t0, t1;
|
||||
Double tNear = -std::numeric_limits<Double>::infinity();
|
||||
Double tFar = std::numeric_limits<Double>::infinity();
|
||||
|
||||
if (!IntersectSlab(mNear.X(), mFar.X(),
|
||||
ray.origin.X(), ray.direction.X(),
|
||||
tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
if (!IntersectSlab(mNear.Y(), mFar.Y(),
|
||||
ray.origin.Y(), ray.direction.Y(),
|
||||
tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
if (!IntersectSlab(mNear.Z(), mFar.Z(),
|
||||
ray.origin.Z(), ray.direction.Z(),
|
||||
tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We have an intersection! */
|
||||
stats.boxIntersections++;
|
||||
t.push_back(tNear);
|
||||
t.push_back(tFar);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::IntersectSlab --
|
||||
*/
|
||||
inline bool
|
||||
Box::IntersectSlab(const Double& slabLow,
|
||||
const Double& slabHigh,
|
||||
const Double& rayOriginComponent,
|
||||
const Double& rayDirectionComponent,
|
||||
Double& tNear,
|
||||
Double& tFar)
|
||||
const
|
||||
{
|
||||
Double t0, t1;
|
||||
|
||||
/*
|
||||
* From the Ray Tracing book:
|
||||
*
|
||||
|
@ -82,77 +169,6 @@ Box::DoesIntersect(const Ray& ray,
|
|||
* planes (X, Y, and Z planes).
|
||||
*/
|
||||
|
||||
if (!IntersectSlab(mNear.x, mFar.x, ray.origin.x, ray.direction.x, tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
if (!IntersectSlab(mNear.y, mFar.y, ray.origin.y, ray.direction.y, tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
if (!IntersectSlab(mNear.z, mFar.z, ray.origin.z, ray.direction.z, tNear, tFar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We have an intersection! */
|
||||
stats.boxIntersections++;
|
||||
t.push_back(tNear);
|
||||
t.push_back(tFar);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Box::point_is_on_surface(const Vector3& p)
|
||||
const
|
||||
{
|
||||
if (p.x == mNear.x || p.x == mFar.x) {
|
||||
return (p.y > mNear.y && p.y < mFar.y)
|
||||
&& (p.z > mNear.z && p.z < mFar.z);
|
||||
} else if (p.y == mNear.y || p.y == mFar.y) {
|
||||
return (p.x > mNear.x && p.x < mFar.x)
|
||||
&& (p.z > mNear.z && p.z < mFar.z);
|
||||
} else if (p.z == mNear.z || p.z == mFar.z) {
|
||||
return (p.x > mNear.x && p.x < mFar.x)
|
||||
&& (p.y > mNear.y && p.y < mFar.y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Vector3
|
||||
Box::compute_normal(const Vector3& p)
|
||||
const
|
||||
{
|
||||
if (NearlyEqual(p.x, mNear.x)) {
|
||||
return Vector3(-1, 0, 0);
|
||||
} else if (NearlyEqual(p.x, mFar.x)) {
|
||||
return Vector3(1, 0, 0);
|
||||
} else if (NearlyEqual(p.y, mNear.y)) {
|
||||
return Vector3(0, -1, 0);
|
||||
} else if (NearlyEqual(p.y, mFar.y)) {
|
||||
return Vector3(0, 1, 0);
|
||||
} else if (NearlyEqual(p.z, mNear.z)) {
|
||||
return Vector3(0, 0, -1);
|
||||
} else if (NearlyEqual(p.z, mFar.z)) {
|
||||
return Vector3(0, 0, 1);
|
||||
}
|
||||
|
||||
/* TODO: Eventually, I might want to raise an error here. */
|
||||
return Vector3();
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
Box::IntersectSlab(const Double& slabLow,
|
||||
const Double& slabHigh,
|
||||
const Double& rayOriginComponent,
|
||||
const Double& rayDirectionComponent,
|
||||
Double& tNear,
|
||||
Double& tFar)
|
||||
const
|
||||
{
|
||||
Double t0, t1;
|
||||
|
||||
if (NearZero(rayDirectionComponent)) {
|
||||
/* The ray is parallel to the X axis. */
|
||||
if (rayOriginComponent < slabLow || rayOriginComponent > slabHigh) {
|
||||
|
@ -170,12 +186,13 @@ Box::IntersectSlab(const Double& slabLow,
|
|||
tNear = t1;
|
||||
tFar = t0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (t0 > t1) {
|
||||
Double tmp = t0;
|
||||
t0 = t1;
|
||||
t1 = tmp;
|
||||
}
|
||||
#endif
|
||||
if (t0 > tNear) {
|
||||
tNear = t0;
|
||||
}
|
||||
|
@ -196,6 +213,9 @@ Box::IntersectSlab(const Double& slabLow,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Box::Write --
|
||||
*/
|
||||
void
|
||||
Box::Write(std::ostream& ost)
|
||||
const
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
#include "types.hh"
|
||||
#ifndef __OBJECTBOX_HH__
|
||||
#define __OBJECTBOX_HH__
|
||||
|
||||
#include "object.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
@ -14,20 +16,21 @@ struct Box
|
|||
: public Object
|
||||
{
|
||||
Box();
|
||||
Box(const Vector3& near, const Vector3& far);
|
||||
Box(const basics::Vector4& near, const basics::Vector4& far);
|
||||
|
||||
Vector3& GetNear();
|
||||
void SetNear(const Vector3& near);
|
||||
Vector3& GetFar();
|
||||
void SetFar(const Vector3& far);
|
||||
basics::Vector4& GetNear();
|
||||
void SetNear(const basics::Vector4& near);
|
||||
|
||||
bool DoesIntersect(const Ray& ray, TVector& t, Stats& stats) const;
|
||||
bool point_is_on_surface(const Vector3 &p) const;
|
||||
Vector3 compute_normal(const Vector3 &p) const;
|
||||
basics::Vector4& GetFar();
|
||||
void SetFar(const basics::Vector4& far);
|
||||
|
||||
/** @see charles::Object::Write */
|
||||
void Write(std::ostream& ost) const;
|
||||
|
||||
protected:
|
||||
bool DoIntersect(const basics::Ray& ray, TVector& t, Stats& stats) const;
|
||||
basics::Vector4 DoNormal(const basics::Vector4& p) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the intersection test on a slab, defined by `slabHigh` and
|
||||
|
@ -49,10 +52,12 @@ private:
|
|||
Double& tFar) const;
|
||||
|
||||
/** The near, lower left corner. */
|
||||
Vector3 mNear;
|
||||
basics::Vector4 mNear;
|
||||
|
||||
/** The far, upper right corner. */
|
||||
Vector3 mFar;
|
||||
basics::Vector4 mFar;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __OBJECTBOX_HH__ */
|
||||
|
|
|
@ -10,22 +10,28 @@
|
|||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
#include "objectPlane.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* charles::Plane::Plane --
|
||||
*/
|
||||
Plane::Plane()
|
||||
: mNormal(Vector3::Y),
|
||||
: mNormal(0, 1, 0),
|
||||
mDistance(0.0)
|
||||
{ }
|
||||
|
||||
|
||||
const Vector3&
|
||||
/*
|
||||
* charles::Plane::GetNormal --
|
||||
*/
|
||||
const Vector4&
|
||||
Plane::GetNormal()
|
||||
const
|
||||
{
|
||||
|
@ -33,13 +39,19 @@ Plane::GetNormal()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Plane::SetNormal --
|
||||
*/
|
||||
void
|
||||
Plane::SetNormal(const Vector3& normal)
|
||||
Plane::SetNormal(const Vector4& normal)
|
||||
{
|
||||
mNormal = normal.normalized();
|
||||
mNormal = basics::Normalized(normal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Plane::GetDistance --
|
||||
*/
|
||||
Double
|
||||
Plane::GetDistance()
|
||||
const
|
||||
|
@ -48,6 +60,9 @@ Plane::GetDistance()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Plane::SetDistance --
|
||||
*/
|
||||
void
|
||||
Plane::SetDistance(Double distance)
|
||||
{
|
||||
|
@ -59,9 +74,9 @@ Plane::SetDistance(Double distance)
|
|||
* charles::Plane::DoesIntersect --
|
||||
*/
|
||||
bool
|
||||
Plane::DoesIntersect(const Ray &ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
Plane::DoIntersect(const Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
const
|
||||
{
|
||||
/*
|
||||
|
@ -94,14 +109,14 @@ Plane::DoesIntersect(const Ray &ray,
|
|||
stats.planeIntersectionTests++;
|
||||
|
||||
/* The denominator for the t equation above. */
|
||||
Double vd = mNormal.dot(ray.direction);
|
||||
Double vd = mNormal.Dot(ray.direction);
|
||||
if (NearZero(vd)) {
|
||||
/* The ray is parallel to the plane. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The numerator of the equation for t above. */
|
||||
Double vo = -(mNormal.dot(ray.origin) + mDistance);
|
||||
Double vo = -(mNormal.Dot(ray.origin) + mDistance);
|
||||
|
||||
Double t0 = vo / vd;
|
||||
if (t0 < 0.0) {
|
||||
|
@ -119,33 +134,14 @@ Plane::DoesIntersect(const Ray &ray,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Plane::point_is_on_surface --
|
||||
*/
|
||||
bool
|
||||
Plane::point_is_on_surface(const Vector3 &p)
|
||||
const
|
||||
{
|
||||
/*
|
||||
* Plug point p into the equation for a plane:
|
||||
*
|
||||
* A * x + B * y + C * z + D = 0
|
||||
*
|
||||
* where (A, B, C) are the coordinates of the normal vector, and D is the
|
||||
* distance along that vector from the origin.
|
||||
*/
|
||||
return NearZero(mNormal.dot(p) + mDistance);
|
||||
}
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
/*
|
||||
* charles::Plane::compute_normal --
|
||||
* charles::Plane::DoNormal --
|
||||
*/
|
||||
Vector3
|
||||
Plane::compute_normal(const Vector3 &p)
|
||||
Vector4
|
||||
Plane::DoNormal(const Vector4& p)
|
||||
const
|
||||
{
|
||||
return mNormal;
|
||||
|
@ -154,6 +150,9 @@ Plane::compute_normal(const Vector3 &p)
|
|||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
/*
|
||||
* charles::Plane::Write --
|
||||
*/
|
||||
void
|
||||
Plane::Write(std::ostream& ost)
|
||||
const
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#ifndef __OBJECT_PLANE_H__
|
||||
#define __OBJECT_PLANE_H__
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
#include "types.hh"
|
||||
#include "object.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
|
@ -21,25 +21,22 @@ public:
|
|||
/** Default constructor. Creates a plane with a normal along the Y axis. */
|
||||
Plane();
|
||||
|
||||
const Vector3& GetNormal() const;
|
||||
void SetNormal(const Vector3& normal);
|
||||
const basics::Vector4& GetNormal() const;
|
||||
void SetNormal(const basics::Vector4& normal);
|
||||
|
||||
Double GetDistance() const;
|
||||
void SetDistance(Double distance);
|
||||
|
||||
/**
|
||||
* @see charles::Object::DoesIntersect
|
||||
*/
|
||||
bool DoesIntersect(const Ray &ray, TVector& t, Stats& stats) const;
|
||||
bool point_is_on_surface(const Vector3 &p) const;
|
||||
Vector3 compute_normal(const Vector3 &p) const;
|
||||
|
||||
/** @see charles::Object::Write */
|
||||
void Write(std::ostream& ost) const;
|
||||
|
||||
protected:
|
||||
bool DoIntersect(const basics::Ray& ray, TVector& t, Stats& stats) const;
|
||||
basics::Vector4 DoNormal(const basics::Vector4& p) const;
|
||||
|
||||
private:
|
||||
/** A normal vector, which specified the orientation of the plane. */
|
||||
Vector3 mNormal;
|
||||
basics::Vector4 mNormal;
|
||||
|
||||
/**
|
||||
* The distance from the origin along the normal vector that this plane is
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* object_sphere.h
|
||||
*
|
||||
* Spheres are Scene objects defined by a center point and a radius.
|
||||
*
|
||||
/* objectSphere.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
|
@ -10,39 +8,28 @@
|
|||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
#include "objectSphere.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* Sphere::Sphere --
|
||||
*
|
||||
* Default constructor. Create a Sphere with radius 1.0.
|
||||
* charles::Sphere::Sphere --
|
||||
*/
|
||||
Sphere::Sphere()
|
||||
: Sphere(1.0)
|
||||
Sphere::Sphere(const Vector4& origin,
|
||||
Double radius)
|
||||
: Object(origin),
|
||||
mRadius(radius)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Sphere::Sphere --
|
||||
*
|
||||
* Constructor. Create a Sphere with the given radius.
|
||||
* charles::Sphere::GetRadius --
|
||||
*/
|
||||
Sphere::Sphere(Double r)
|
||||
: Sphere(Vector3::Zero, r)
|
||||
{ }
|
||||
|
||||
|
||||
Sphere::Sphere(Vector3 o,
|
||||
Double r)
|
||||
: Object(o),
|
||||
mRadius(r)
|
||||
{ }
|
||||
|
||||
|
||||
Double
|
||||
Sphere::GetRadius()
|
||||
const
|
||||
|
@ -51,31 +38,31 @@ Sphere::GetRadius()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Sphere::SetRadius --
|
||||
*/
|
||||
void
|
||||
Sphere::SetRadius(Double r)
|
||||
Sphere::SetRadius(const Double& r)
|
||||
{
|
||||
mRadius = std::fabs(r);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sphere::DoesIntersect --
|
||||
* charles::Sphere::DoesIntersect --
|
||||
*/
|
||||
bool
|
||||
Sphere::DoesIntersect(const Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
Sphere::DoIntersect(const Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
const
|
||||
{
|
||||
stats.sphereIntersectionTests++;
|
||||
|
||||
/* Origin of the vector in object space. */
|
||||
Vector3 rayOriginObj = ray.origin - GetOrigin();
|
||||
|
||||
/* Coefficients for quadratic equation. */
|
||||
Double a = ray.direction.dot(ray.direction);
|
||||
Double b = ray.direction.dot(rayOriginObj) * 2.0;
|
||||
Double c = rayOriginObj.dot(rayOriginObj) - (mRadius * mRadius);
|
||||
Double a = ray.direction.Dot(ray.direction);
|
||||
Double b = ray.direction.Dot(ray.origin) * 2.0;
|
||||
Double c = ray.origin.Dot(ray.origin) - (mRadius * mRadius);
|
||||
|
||||
/* Discriminant for the quadratic equation. */
|
||||
Double discrim = (b * b) - (4.0 * a * c);
|
||||
|
@ -92,7 +79,7 @@ Sphere::DoesIntersect(const Ray& ray,
|
|||
* Compute the intersections, the roots of the quadratic equation. Spheres
|
||||
* have at most two intersections.
|
||||
*/
|
||||
Double sqrtDiscrim = sqrt(discrim);
|
||||
Double sqrtDiscrim = std::sqrt(discrim);
|
||||
Double t0 = (-b - sqrtDiscrim) / (2.0 * a);
|
||||
Double t1 = (-b + sqrtDiscrim) / (2.0 * a);
|
||||
|
||||
|
@ -125,45 +112,28 @@ Sphere::DoesIntersect(const Ray& ray,
|
|||
|
||||
|
||||
/*
|
||||
* Sphere::point_is_on_surface --
|
||||
*
|
||||
* Determine if a point lies on the surface of this Sphere.
|
||||
* charles::Sphere::DoNormal --
|
||||
*/
|
||||
bool
|
||||
Sphere::point_is_on_surface(const Vector3 &p)
|
||||
Vector4
|
||||
Sphere::DoNormal(const Vector4& p)
|
||||
const
|
||||
{
|
||||
Vector3 o = GetOrigin();
|
||||
Double x = p.x - o.x;
|
||||
Double y = p.y - o.y;
|
||||
Double z = p.z - o.z;
|
||||
|
||||
return x*x + y*y + z*z == mRadius*mRadius;
|
||||
/*
|
||||
* The fun thing about sphere is the normal to any point on the sphere is
|
||||
* the point itself. Woo!
|
||||
*/
|
||||
return Normalized(p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sphere::compute_normal --
|
||||
*
|
||||
* Compute the normal for this Sphere at the given point. If the point does not lie on the surface of the sphere, a zero
|
||||
* vector is returned.
|
||||
* charles::Sphere::Write --
|
||||
*/
|
||||
Vector3
|
||||
Sphere::compute_normal(const Vector3 &p)
|
||||
const
|
||||
{
|
||||
// The fun thing about sphere is the normal to any point on the sphere is the point itself. Woo!
|
||||
Vector3 normal = p - GetOrigin();
|
||||
normal.normalize();
|
||||
return normal;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sphere::Write(std::ostream& ost)
|
||||
const
|
||||
{
|
||||
ost << "[Sphere origin=" << GetOrigin() << " r=" << mRadius << "]";
|
||||
ost << "[Sphere r=" << mRadius << "]";
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#ifndef __OBJECTSPHERE_HH__
|
||||
#define __OBJECTSPHERE_HH__
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
#include "object.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
|
@ -17,20 +18,18 @@ class Sphere
|
|||
: public Object
|
||||
{
|
||||
public:
|
||||
Sphere();
|
||||
Sphere(Double r);
|
||||
Sphere(Vector3 o, Double r);
|
||||
Sphere(const basics::Vector4& origin = basics::Vector4(), Double radius = 1.0);
|
||||
|
||||
Double GetRadius() const;
|
||||
void SetRadius(Double r);
|
||||
|
||||
bool DoesIntersect(const Ray& ray, TVector& t, Stats& stats) const;
|
||||
bool point_is_on_surface(const Vector3 &p) const;
|
||||
Vector3 compute_normal(const Vector3 &p) const;
|
||||
void SetRadius(const Double& r);
|
||||
|
||||
/** @see charles::Object::Write */
|
||||
void Write(std::ostream& ost) const;
|
||||
|
||||
protected:
|
||||
bool DoIntersect(const basics::Ray& ray, TVector& t, Stats& stats) const override;
|
||||
basics::Vector4 DoNormal(const basics::Vector4& p) const override;
|
||||
|
||||
private:
|
||||
Double mRadius;
|
||||
};
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Interface for an input file reader.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __READER_HH__
|
||||
#define __READER_HH__
|
||||
|
||||
#include "scene.h"
|
||||
#include "scene.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* Interface for an input file reader.
|
||||
*/
|
||||
struct Reader
|
||||
{
|
||||
Reader(Scene& scene)
|
||||
|
@ -29,4 +30,6 @@ protected:
|
|||
Scene& mScene;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __READER_HH__ */
|
||||
|
|
|
@ -14,11 +14,15 @@
|
|||
#include "yaml.h"
|
||||
|
||||
#include "charles.hh"
|
||||
#include "log.hh"
|
||||
#include "reader_yaml.hh"
|
||||
|
||||
#include "yaml/parsers.hh"
|
||||
#include "yaml/sceneParser.hh"
|
||||
|
||||
#define LOG_NAME "yaml"
|
||||
#include "logModule.hh"
|
||||
|
||||
|
||||
#if 0
|
||||
struct ObjectParser
|
||||
|
@ -58,6 +62,7 @@ private:
|
|||
};
|
||||
#endif
|
||||
|
||||
namespace charles {
|
||||
|
||||
ssize_t
|
||||
YAMLReader::read_file(const std::string& filename)
|
||||
|
@ -86,47 +91,45 @@ YAMLReader::read_file(const std::string& filename)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (verbosity >= 4) {
|
||||
switch (event.type) {
|
||||
case YAML_NO_EVENT:
|
||||
printf("YAML_NO_EVENT\n");
|
||||
break;
|
||||
switch (event.type) {
|
||||
case YAML_NO_EVENT:
|
||||
LOG_TRACE << "YAML_NO_EVENT";
|
||||
break;
|
||||
|
||||
case YAML_STREAM_START_EVENT:
|
||||
printf("YAML_STREAM_START_EVENT\n");
|
||||
break;
|
||||
case YAML_STREAM_END_EVENT:
|
||||
printf("YAML_STREAM_END_EVENT\n");
|
||||
break;
|
||||
case YAML_STREAM_START_EVENT:
|
||||
LOG_TRACE << "YAML_STREAM_START_EVENT";
|
||||
break;
|
||||
case YAML_STREAM_END_EVENT:
|
||||
LOG_TRACE << "YAML_STREAM_END_EVENT";
|
||||
break;
|
||||
|
||||
case YAML_DOCUMENT_START_EVENT:
|
||||
printf("YAML_DOCUMENT_START_EVENT\n");
|
||||
break;
|
||||
case YAML_DOCUMENT_END_EVENT:
|
||||
printf("YAML_DOCUMENT_END_EVENT\n");
|
||||
break;
|
||||
case YAML_DOCUMENT_START_EVENT:
|
||||
LOG_TRACE << "YAML_DOCUMENT_START_EVENT";
|
||||
break;
|
||||
case YAML_DOCUMENT_END_EVENT:
|
||||
LOG_TRACE << "YAML_DOCUMENT_END_EVENT";
|
||||
break;
|
||||
|
||||
case YAML_ALIAS_EVENT:
|
||||
printf("YAML_ALIAS_EVENT\n");
|
||||
break;
|
||||
case YAML_SCALAR_EVENT:
|
||||
printf("YAML_SCALAR_EVENT\n");
|
||||
break;
|
||||
case YAML_ALIAS_EVENT:
|
||||
LOG_TRACE << "YAML_ALIAS_EVENT";
|
||||
break;
|
||||
case YAML_SCALAR_EVENT:
|
||||
LOG_TRACE << "YAML_SCALAR_EVENT";
|
||||
break;
|
||||
|
||||
case YAML_SEQUENCE_START_EVENT:
|
||||
printf("YAML_SEQUENCE_START_EVENT\n");
|
||||
break;
|
||||
case YAML_SEQUENCE_END_EVENT:
|
||||
printf("YAML_SEQUENCE_END_EVENT\n");
|
||||
break;
|
||||
case YAML_SEQUENCE_START_EVENT:
|
||||
LOG_TRACE << "YAML_SEQUENCE_START_EVENT";
|
||||
break;
|
||||
case YAML_SEQUENCE_END_EVENT:
|
||||
LOG_TRACE << "YAML_SEQUENCE_END_EVENT";
|
||||
break;
|
||||
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
printf("YAML_MAPPING_START_EVENT\n");
|
||||
break;
|
||||
case YAML_MAPPING_END_EVENT:
|
||||
printf("YAML_MAPPING_END_EVENT\n");
|
||||
break;
|
||||
}
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
LOG_TRACE << "YAML_MAPPING_START_EVENT";
|
||||
break;
|
||||
case YAML_MAPPING_END_EVENT:
|
||||
LOG_TRACE << "YAML_MAPPING_END_EVENT";
|
||||
break;
|
||||
}
|
||||
|
||||
if (event.type == YAML_DOCUMENT_START_EVENT) {
|
||||
|
@ -152,3 +155,5 @@ error:
|
|||
yaml_parser_delete(&parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __READERYAML_HH__
|
||||
#define __READERYAML_HH__
|
||||
|
||||
#include "reader.hh"
|
||||
#include "scene.hh"
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* An input file reader for YAML files.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __READER_YAML_HH__
|
||||
#define __READER_YAML_HH__
|
||||
|
||||
#include "reader.hh"
|
||||
#include "scene.h"
|
||||
|
||||
|
||||
struct YAMLReader
|
||||
: public Reader
|
||||
{
|
||||
|
@ -21,9 +21,9 @@ struct YAMLReader
|
|||
: Reader(scene)
|
||||
{ }
|
||||
|
||||
~YAMLReader() { }
|
||||
|
||||
ssize_t read_file(const std::string& filename);
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __READER_YAML_HH__ */
|
||||
|
|
315
src/scene.cc
315
src/scene.cc
|
@ -5,84 +5,123 @@
|
|||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <chrono>
|
||||
|
||||
#include "basics.h"
|
||||
#include "light.h"
|
||||
#include "scene.hh"
|
||||
|
||||
#include "light.hh"
|
||||
#include "log.hh"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
#include "object.hh"
|
||||
#include "writer.h"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
#define LOG_NAME "scene"
|
||||
#include "logModule.hh"
|
||||
|
||||
using namespace charles;
|
||||
|
||||
using charles::basics::Color;
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* charles::Scene::Scene --
|
||||
*/
|
||||
Scene::Scene()
|
||||
: width(640), height(480),
|
||||
: mWidth(640),
|
||||
mHeight(480),
|
||||
mCamera(new PerspectiveCamera()),
|
||||
max_depth(5),
|
||||
min_weight(1e-4),
|
||||
ambient(new AmbientLight()),
|
||||
shapes(),
|
||||
lights(),
|
||||
mMaxDepth(5),
|
||||
mMinWeight(1e-6),
|
||||
mAmbient(Color(1, 1, 1), 0.2),
|
||||
mObjects(),
|
||||
mLights(),
|
||||
mStats(),
|
||||
pixels(NULL)
|
||||
mPixels(NULL)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::~Scene --
|
||||
*/
|
||||
Scene::~Scene()
|
||||
{
|
||||
mCamera.reset();
|
||||
|
||||
if (ambient != NULL) {
|
||||
delete ambient;
|
||||
}
|
||||
mObjects.clear();
|
||||
|
||||
shapes.clear();
|
||||
|
||||
for (PointLight *l : lights) {
|
||||
for (PointLight *l : mLights) {
|
||||
delete l;
|
||||
}
|
||||
lights.clear();
|
||||
mLights.clear();
|
||||
|
||||
if (pixels != NULL) {
|
||||
delete[] pixels;
|
||||
_is_rendered = false;
|
||||
if (mPixels != NULL) {
|
||||
delete[] mPixels;
|
||||
mIsRendered = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Scene::is_rendered()
|
||||
const
|
||||
{
|
||||
return _is_rendered;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Scene::get_width()
|
||||
const
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Scene::get_height()
|
||||
const
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scene::GetCamera --
|
||||
* charles::Scene::IsRendered --
|
||||
*/
|
||||
bool
|
||||
Scene::IsRendered()
|
||||
const
|
||||
{
|
||||
return mIsRendered;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::GetWidth --
|
||||
*/
|
||||
UInt
|
||||
Scene::GetWidth()
|
||||
const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::SetWidth --
|
||||
*/
|
||||
void
|
||||
Scene::SetWidth(UInt w)
|
||||
{
|
||||
mWidth = w;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::GetHeight --
|
||||
*/
|
||||
UInt
|
||||
Scene::GetHeight()
|
||||
const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::SetHeight --
|
||||
*/
|
||||
void
|
||||
Scene::SetHeight(UInt h)
|
||||
{
|
||||
mHeight = h;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::GetCamera --
|
||||
*/
|
||||
Camera::Ptr
|
||||
Scene::GetCamera()
|
||||
|
@ -93,63 +132,55 @@ Scene::GetCamera()
|
|||
|
||||
|
||||
/*
|
||||
* Scene::SetCamera --
|
||||
* charles::Scene::SetCamera --
|
||||
*/
|
||||
void
|
||||
Scene::SetCamera(Camera* camera)
|
||||
Scene::SetCamera(Camera::Ptr camera)
|
||||
{
|
||||
mCamera.reset(camera);
|
||||
}
|
||||
|
||||
|
||||
AmbientLight &
|
||||
Scene::get_ambient()
|
||||
const
|
||||
{
|
||||
return *ambient;
|
||||
}
|
||||
|
||||
|
||||
const Color *
|
||||
Scene::get_pixels()
|
||||
const
|
||||
{
|
||||
return pixels;
|
||||
mCamera = camera;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* scene_load --
|
||||
*
|
||||
* Load scene objects into this Scene from the given file.
|
||||
* charles::Scene::GetAmbient --
|
||||
*/
|
||||
void
|
||||
Scene::read(const std::string &filename)
|
||||
{ }
|
||||
AmbientLight&
|
||||
Scene::GetAmbient()
|
||||
{
|
||||
return mAmbient;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* scene_save --
|
||||
*
|
||||
* Write a rendered scene to the given file.
|
||||
* charles::Scene::GetPixels --
|
||||
*/
|
||||
const Color*
|
||||
Scene::GetPixels()
|
||||
const
|
||||
{
|
||||
return mPixels;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::Write --
|
||||
*/
|
||||
void
|
||||
Scene::write(Writer &writer, const std::string &filename)
|
||||
Scene::Write(Writer& writer,
|
||||
const std::string& filename)
|
||||
{
|
||||
writer.write_scene(*this, filename);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scene::render --
|
||||
*
|
||||
* Render the given Scene.
|
||||
* charles::Scene::Render --
|
||||
*/
|
||||
void
|
||||
Scene::render()
|
||||
Scene::Render()
|
||||
{
|
||||
LOG_INFO << "Rendering scene with " << shapes.size() << " objects.";
|
||||
printf("Rendering scene with %lu objects.\n", shapes.size());
|
||||
LOG_INFO << "Rendering scene with " << mObjects.size() << " objects.";
|
||||
printf("Rendering scene with %lu objects.\n", mObjects.size());
|
||||
|
||||
LogCamera();
|
||||
LogObjects();
|
||||
|
@ -157,23 +188,23 @@ Scene::render()
|
|||
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||
start = std::chrono::system_clock::now();
|
||||
|
||||
pixels = new Color[width * height];
|
||||
mPixels = new Color[mWidth * mHeight];
|
||||
|
||||
Ray primary_ray;
|
||||
Vector3 o, d;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
primary_ray = mCamera->compute_primary_ray(x, width, y, height);
|
||||
Ray primaryRay;
|
||||
Vector4 o, d;
|
||||
for (UInt y = 0; y < mHeight; y++) {
|
||||
for (UInt x = 0; x < mWidth; x++) {
|
||||
primaryRay = mCamera->PrimaryRay(x, mWidth, y, mHeight);
|
||||
mStats.primaryRays++;
|
||||
Color c = trace_ray(primary_ray);
|
||||
pixels[y * width + x] = c;
|
||||
Color c = TraceRay(primaryRay);
|
||||
mPixels[y * mWidth + x] = c;
|
||||
}
|
||||
}
|
||||
|
||||
end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<float> seconds = end - start;
|
||||
std::chrono::duration<Double> seconds = end - start;
|
||||
|
||||
_is_rendered = true;
|
||||
mIsRendered = true;
|
||||
|
||||
printf("Rendering completed in %f seconds.\n\n", seconds.count());
|
||||
LOG_INFO << "Rendering completed in " << seconds.count() << " seconds.";
|
||||
|
@ -184,83 +215,77 @@ Scene::render()
|
|||
|
||||
|
||||
/*
|
||||
* Scene::add_shape --
|
||||
*
|
||||
* Add a shape to the scene.
|
||||
* charles::Scene::AddObject --
|
||||
*/
|
||||
void
|
||||
Scene::add_shape(Object::Ptr shape)
|
||||
Scene::AddObject(Object::Ptr obj)
|
||||
{
|
||||
shapes.push_back(shape);
|
||||
mObjects.push_back(obj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scene::add_light --
|
||||
*
|
||||
* Add a light to the scene.
|
||||
* charles::Scene::AddLight --
|
||||
*/
|
||||
void
|
||||
Scene::add_light(PointLight *light)
|
||||
Scene::AddLight(PointLight* light)
|
||||
{
|
||||
lights.push_back(light);
|
||||
mLights.push_back(light);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scene::trace_ray --
|
||||
*
|
||||
* Trace the given ray through the scene, recursing until depth has been reached.
|
||||
* charles::Scene::TraceRay --
|
||||
*/
|
||||
Color
|
||||
Scene::trace_ray(const Ray &ray,
|
||||
const int depth,
|
||||
const float weight)
|
||||
Scene::TraceRay(const Ray &ray,
|
||||
const int depth,
|
||||
const Double weight)
|
||||
{
|
||||
if (depth >= max_depth || weight <= min_weight) {
|
||||
if (depth >= mMaxDepth || weight <= mMinWeight) {
|
||||
return Color::Black;
|
||||
}
|
||||
|
||||
Color out_color = Color::Black;
|
||||
Object::Ptr intersected_shape;
|
||||
Color outColor = Color::Black;
|
||||
Object::Ptr intersectedObj;
|
||||
TVector ts;
|
||||
Double nearest_t = INFINITY;
|
||||
Double nearestT = INFINITY;
|
||||
|
||||
ts.reserve(2);
|
||||
|
||||
// Find intersections of this ray with objects in the scene.
|
||||
for (Object::Ptr s : shapes) {
|
||||
for (Object::Ptr obj : mObjects) {
|
||||
ts.clear();
|
||||
if (s->DoesIntersect(ray, ts, mStats)) {
|
||||
if (ts[0] < nearest_t) {
|
||||
intersected_shape = s;
|
||||
nearest_t = ts[0];
|
||||
if (obj->Intersect(ray, ts, mStats)) {
|
||||
if (ts[0] < nearestT) {
|
||||
intersectedObj = obj;
|
||||
nearestT = ts[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there was no intersection, return black.
|
||||
if (!intersected_shape) {
|
||||
return out_color;
|
||||
if (!intersectedObj) {
|
||||
return outColor;
|
||||
}
|
||||
|
||||
Material& shape_material = intersected_shape->GetMaterial();
|
||||
const Color& shape_color = shape_material.GetDiffuseColor();
|
||||
Material& material = intersectedObj->GetMaterial();
|
||||
const Color& shapeColor = material.GetDiffuseColor();
|
||||
|
||||
Vector3 intersection = ray.parameterize(nearest_t);
|
||||
Vector3 normal = intersected_shape->compute_normal(intersection);
|
||||
Vector4 intersection = ray.Parameterize(nearestT);
|
||||
Vector4 normal = intersectedObj->Normal(intersection);
|
||||
|
||||
/*
|
||||
* Diffuse lighting. (Shading, etc.)
|
||||
*/
|
||||
|
||||
Vector3 light_direction;
|
||||
Double ldotn, diffuse_level, ambient_level;
|
||||
Vector4 lightDirection;
|
||||
Double ldotn, diffuseLevel, ambientLevel;
|
||||
Ray shadowRay;
|
||||
|
||||
for (PointLight *l : lights) {
|
||||
light_direction = (l->GetOrigin() - intersection).normalize();
|
||||
ldotn = light_direction.dot(normal);
|
||||
for (PointLight *l : mLights) {
|
||||
lightDirection = basics::Normalized(l->GetOrigin() - intersection);
|
||||
ldotn = lightDirection.Dot(normal);
|
||||
|
||||
/*
|
||||
* TODO: What is this even for? Removing it makes the darker showers
|
||||
|
@ -270,12 +295,12 @@ Scene::trace_ray(const Ray &ray,
|
|||
ldotn = 0.0;
|
||||
}
|
||||
|
||||
diffuse_level = shape_material.GetDiffuseIntensity();
|
||||
ambient_level = 1.0 - diffuse_level;
|
||||
diffuseLevel = material.GetDiffuseIntensity();
|
||||
ambientLevel = 1.0 - diffuseLevel;
|
||||
|
||||
shadowRay = Ray(intersection, light_direction);
|
||||
for (Object::Ptr s : shapes) {
|
||||
if (s == intersected_shape) {
|
||||
shadowRay = Ray(intersection, lightDirection);
|
||||
for (Object::Ptr obj : mObjects) {
|
||||
if (obj == intersectedObj) {
|
||||
/* Skip the intersected shape. */
|
||||
continue;
|
||||
}
|
||||
|
@ -284,8 +309,8 @@ Scene::trace_ray(const Ray &ray,
|
|||
|
||||
/* Figure out if we're in shadow. */
|
||||
ts.clear();
|
||||
if (s->DoesIntersect(shadowRay, ts, mStats)) {
|
||||
diffuse_level = 0.0;
|
||||
if (obj->Intersect(shadowRay, ts, mStats)) {
|
||||
diffuseLevel = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -293,8 +318,8 @@ Scene::trace_ray(const Ray &ray,
|
|||
/*
|
||||
* Compute basic Lambert diffuse shading for this object.
|
||||
*/
|
||||
out_color += shape_color * ( ambient_level * ambient->compute_color_contribution()
|
||||
+ diffuse_level * ldotn);
|
||||
outColor += shapeColor * ( ambientLevel * mAmbient.Contribution()
|
||||
+ diffuseLevel * ldotn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -328,10 +353,13 @@ Scene::trace_ray(const Ray &ray,
|
|||
out_color += specular_level * specular_color * reflection_color;
|
||||
#endif
|
||||
|
||||
return out_color;
|
||||
return outColor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::LogCamera --
|
||||
*/
|
||||
void
|
||||
Scene::LogCamera()
|
||||
const
|
||||
|
@ -341,7 +369,7 @@ Scene::LogCamera()
|
|||
LOG_DEBUG << "BEGIN CAMERA";
|
||||
LOG_DEBUG << " type = " << c.GetTypeString();
|
||||
LOG_DEBUG << " origin = " << c.GetOrigin();
|
||||
LOG_DEBUG << " direction = " << c.get_direction();
|
||||
LOG_DEBUG << " direction = " << c.GetDirection();
|
||||
LOG_DEBUG << " right = " << c.GetRight();
|
||||
LOG_DEBUG << " up = " << c.GetUp();
|
||||
LOG_DEBUG << " coordinate system is "
|
||||
|
@ -350,15 +378,20 @@ Scene::LogCamera()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Scene::LogObjects --
|
||||
*/
|
||||
void
|
||||
Scene::LogObjects()
|
||||
const
|
||||
{
|
||||
LOG_DEBUG << "BEGIN SCENE OBJECTS";
|
||||
|
||||
for (Object::Ptr obj : shapes) {
|
||||
for (Object::Ptr obj : mObjects) {
|
||||
LOG_DEBUG << " " << *obj;
|
||||
}
|
||||
|
||||
LOG_DEBUG << "END SCENE OBJECTS";
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
84
src/scene.h
84
src/scene.h
|
@ -1,84 +0,0 @@
|
|||
/* scene.h
|
||||
*
|
||||
* Definition of the Scene class.
|
||||
*
|
||||
* Scenes are the top level object in charles. Scenes contain objects, lights, a camera,
|
||||
* etc. and can be rendered to pixel data and written to a file.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __SCENE_H__
|
||||
#define __SCENE_H__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "basics.h"
|
||||
#include "camera.h"
|
||||
#include "object.h"
|
||||
#include "stats.hh"
|
||||
|
||||
|
||||
class AmbientLight;
|
||||
class PointLight;
|
||||
class Writer;
|
||||
|
||||
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
Scene();
|
||||
~Scene();
|
||||
|
||||
bool is_rendered() const;
|
||||
|
||||
int get_width() const;
|
||||
void set_width(int w) { width = w; }
|
||||
int get_height() const;
|
||||
void set_height(int h) { height = h; }
|
||||
|
||||
Camera::Ptr GetCamera() const;
|
||||
void SetCamera(Camera* camera);
|
||||
|
||||
AmbientLight &get_ambient() const;
|
||||
const Color *get_pixels() const;
|
||||
|
||||
void read(const std::string &filename);
|
||||
void write(Writer &writer, const std::string &filename);
|
||||
void render();
|
||||
|
||||
void add_shape(charles::Object::Ptr obj);
|
||||
void add_light(PointLight *light);
|
||||
|
||||
private:
|
||||
Color trace_ray(const Ray &ray, const int depth = 0, const float weight = 1.0);
|
||||
|
||||
void LogCamera() const;
|
||||
void LogObjects() const;
|
||||
|
||||
// Pixel dimensions of the image.
|
||||
int width, height;
|
||||
|
||||
Camera::Ptr mCamera;
|
||||
|
||||
/*
|
||||
* Ray tracing parameters. max_depth indicates the maximum depth of the ray tree. min_weight indicates the minimum
|
||||
* specular weight to apply before giving up.
|
||||
*/
|
||||
int max_depth;
|
||||
float min_weight;
|
||||
|
||||
// Scene objects.
|
||||
AmbientLight *ambient;
|
||||
std::list<charles::Object::Ptr> shapes;
|
||||
std::list<PointLight *> lights;
|
||||
|
||||
// Rendering stats
|
||||
charles::Stats mStats;
|
||||
|
||||
// Rendering output.
|
||||
bool _is_rendered;
|
||||
Color *pixels;
|
||||
};
|
||||
|
||||
#endif
|
87
src/scene.hh
Normal file
87
src/scene.hh
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* scene.hh
|
||||
* vim: tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __SCENE_H__
|
||||
#define __SCENE_H__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "camera.hh"
|
||||
#include "light.hh"
|
||||
#include "lightPoint.hh"
|
||||
#include "object.hh"
|
||||
#include "stats.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
class Writer;
|
||||
|
||||
|
||||
/**
|
||||
* Scenes are the top level object in charles. Scenes contain objects, lights, a
|
||||
* camera, etc. and can be rendered to pixel data and written to a file.
|
||||
*/
|
||||
struct Scene
|
||||
{
|
||||
Scene();
|
||||
~Scene();
|
||||
|
||||
UInt GetWidth() const;
|
||||
void SetWidth(UInt w);
|
||||
UInt GetHeight() const;
|
||||
void SetHeight(UInt h);
|
||||
|
||||
Camera::Ptr GetCamera() const;
|
||||
void SetCamera(Camera::Ptr camera);
|
||||
|
||||
void Write(Writer& writer, const std::string& filename);
|
||||
|
||||
void Render();
|
||||
bool IsRendered() const;
|
||||
const basics::Color* GetPixels() const;
|
||||
|
||||
AmbientLight& GetAmbient();
|
||||
void AddObject(Object::Ptr obj);
|
||||
void AddLight(PointLight* light);
|
||||
|
||||
private:
|
||||
basics::Color TraceRay(const basics::Ray &ray,
|
||||
const int depth = 0,
|
||||
const Double weight = 1.0);
|
||||
|
||||
void LogCamera() const;
|
||||
void LogObjects() const;
|
||||
|
||||
/** Pixel width */
|
||||
UInt mWidth;
|
||||
/** Pixel height */
|
||||
UInt mHeight;
|
||||
|
||||
Camera::Ptr mCamera;
|
||||
|
||||
/** Maximum depth of the ray tree */
|
||||
int mMaxDepth;
|
||||
/** Minimum specular weight to apply before giving up */
|
||||
float mMinWeight;
|
||||
|
||||
// Scene objects.
|
||||
AmbientLight mAmbient;
|
||||
std::list<charles::Object::Ptr> mObjects;
|
||||
std::list<PointLight *> mLights;
|
||||
|
||||
// Rendering stats
|
||||
charles::Stats mStats;
|
||||
|
||||
// Rendering output.
|
||||
bool mIsRendered;
|
||||
basics::Color *mPixels;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
|
@ -11,7 +11,9 @@
|
|||
#include <string>
|
||||
|
||||
|
||||
class Scene;
|
||||
namespace charles {
|
||||
|
||||
struct Scene;
|
||||
|
||||
|
||||
class Writer
|
||||
|
@ -24,4 +26,6 @@ public:
|
|||
virtual int write_scene(const Scene &scene, const std::string &filename) = 0;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,18 +9,24 @@
|
|||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "scene.h"
|
||||
#include "scene.hh"
|
||||
#include "writer_png.h"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
extern "C" {
|
||||
#include <png.h>
|
||||
}
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
|
||||
|
||||
static void png_user_error(png_structp png, png_const_charp msg);
|
||||
static void png_user_warning(png_structp png, png_const_charp msg);
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* PNGWriter::write_scene --
|
||||
*
|
||||
|
@ -29,7 +35,7 @@ static void png_user_warning(png_structp png, png_const_charp msg);
|
|||
int
|
||||
PNGWriter::write_scene(const Scene &scene, const std::string &filename)
|
||||
{
|
||||
if (!scene.is_rendered()) {
|
||||
if (!scene.IsRendered()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -62,7 +68,7 @@ PNGWriter::write_scene(const Scene &scene, const std::string &filename)
|
|||
* - No compression
|
||||
*/
|
||||
png_set_IHDR(png, png_info,
|
||||
scene.get_width(), scene.get_height(),
|
||||
scene.GetWidth(), scene.GetHeight(),
|
||||
8, PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
|
@ -75,21 +81,20 @@ PNGWriter::write_scene(const Scene &scene, const std::string &filename)
|
|||
png_write_info(png, png_info);
|
||||
|
||||
// Write it!
|
||||
const Color *pixels = scene.get_pixels();
|
||||
const Color* pixels = scene.GetPixels();
|
||||
png_byte *row = NULL;
|
||||
int nbytes = 0;
|
||||
for (int y = 0; y < scene.get_height(); y++) {
|
||||
row = new png_byte[scene.get_width() * 3];
|
||||
for (UInt y = 0; y < scene.GetHeight(); y++) {
|
||||
row = new png_byte[scene.GetWidth() * 3];
|
||||
if (row == NULL) {
|
||||
// TODO: DANGER! WILL ROBINSON!
|
||||
}
|
||||
for (int x = 0; x < scene.get_width(); x++) {
|
||||
Color c = pixels[y * scene.get_width() + x];
|
||||
for (UInt x = 0; x < scene.GetWidth(); x++) {
|
||||
Color c = pixels[y * scene.GetWidth() + x];
|
||||
row[x*3+0] = 0xff * c.red;
|
||||
row[x*3+1] = 0xff * c.green;
|
||||
row[x*3+2] = 0xff * c.blue;
|
||||
nbytes += 3;
|
||||
|
||||
}
|
||||
png_write_row(png, row);
|
||||
delete[] row;
|
||||
|
@ -103,6 +108,8 @@ PNGWriter::write_scene(const Scene &scene, const std::string &filename)
|
|||
return nbytes;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
|
@ -130,4 +137,4 @@ png_user_warning(png_structp png,
|
|||
png_const_charp msg)
|
||||
{ }
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
#pragma clang diagnostic pop
|
|
@ -1,16 +1,19 @@
|
|||
/* writer_png.h
|
||||
*
|
||||
* Declaration of the PNG writer.
|
||||
*
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __WRITER_PNG_H__
|
||||
#define __WRITER_PNG_H__
|
||||
#ifndef __WRITERPNG_HH__
|
||||
#define __WRITERPNG_HH__
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* Write for producing PNG files.
|
||||
*/
|
||||
class PNGWriter
|
||||
: public Writer
|
||||
{
|
||||
|
@ -18,4 +21,6 @@ public:
|
|||
int write_scene(const Scene &scene, const std::string &filename);
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,11 +5,15 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
#include "camera.h"
|
||||
#include "camera.hh"
|
||||
#include "yaml/cameraParser.hh"
|
||||
#include "yaml/vectorParser.hh"
|
||||
|
||||
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
CameraParser::CameraParser(Scene& scene,
|
||||
|
@ -86,13 +90,13 @@ CameraParser::HandleDirectionEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 origin) {
|
||||
mCamera->set_direction(origin);
|
||||
auto onDone = [this](Vector4 direction) {
|
||||
mCamera->SetDirection(direction);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -105,13 +109,13 @@ CameraParser::HandleLookAtEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 lookAt) {
|
||||
auto onDone = [this](Vector4 lookAt) {
|
||||
mCamera->LookAt(lookAt);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -124,13 +128,13 @@ CameraParser::HandleOriginEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 origin) {
|
||||
auto onDone = [this](Vector4 origin) {
|
||||
mCamera->SetOrigin(origin);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,13 +147,13 @@ CameraParser::HandleRightEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 right) {
|
||||
auto onDone = [this](Vector4 right) {
|
||||
mCamera->SetRight(right);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,18 +169,14 @@ CameraParser::HandleTypeEvent(yaml_event_t& event)
|
|||
event.data.scalar.length);
|
||||
if (value == "perspective") {
|
||||
if (mType == TypeOrthographic) {
|
||||
Camera *newCamera = new PerspectiveCamera(*mCamera);
|
||||
delete mCamera;
|
||||
mCamera = newCamera;
|
||||
GetScene().SetCamera(newCamera);
|
||||
mCamera.reset(new PerspectiveCamera(*mCamera));
|
||||
GetScene().SetCamera(mCamera);
|
||||
}
|
||||
}
|
||||
else if (value == "orthographic") {
|
||||
if (mType == TypePerspective) {
|
||||
Camera *newCamera = new OrthographicCamera(*mCamera);
|
||||
delete mCamera;
|
||||
mCamera = newCamera;
|
||||
GetScene().SetCamera(newCamera);
|
||||
mCamera.reset(new OrthographicCamera(*mCamera));
|
||||
GetScene().SetCamera(mCamera);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -197,13 +197,14 @@ CameraParser::HandleUpEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 origin) {
|
||||
auto onDone = [this](Vector4 origin) {
|
||||
mCamera->SetUp(origin);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
struct Camera;
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
struct CameraParser
|
||||
|
@ -47,12 +48,13 @@ private:
|
|||
void HandleTypeEvent(yaml_event_t& event);
|
||||
void HandleUpEvent(yaml_event_t& event);
|
||||
|
||||
Camera *mCamera;
|
||||
Camera::Ptr mCamera;
|
||||
Section mSection;
|
||||
Type mType;
|
||||
};
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_CAMERAPARSER_HH__ */
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "material.h"
|
||||
#include "object.h"
|
||||
#include "material.hh"
|
||||
#include "object.hh"
|
||||
#include "objectBox.hh"
|
||||
#include "objectPlane.hh"
|
||||
#include "objectSphere.hh"
|
||||
|
@ -19,9 +19,11 @@
|
|||
#include "yaml/vectorParser.hh"
|
||||
|
||||
|
||||
using namespace charles;
|
||||
using charles::basics::Color;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
ObjectParser::ObjectParser(Scene& scene,
|
||||
|
@ -43,7 +45,7 @@ ObjectParser::ObjectParser(Scene& scene,
|
|||
} else {
|
||||
assert(false);
|
||||
}
|
||||
GetScene().add_shape(mObject);
|
||||
GetScene().AddObject(mObject);
|
||||
}
|
||||
|
||||
|
||||
|
@ -171,13 +173,13 @@ ObjectParser::HandleOriginEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 origin) {
|
||||
mObject->SetOrigin(origin);
|
||||
auto onDone = [this](Vector4 origin) {
|
||||
mObject->Place(origin);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,13 +213,13 @@ ObjectParser::HandleNearEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 near) {
|
||||
auto onDone = [this](Vector4 near) {
|
||||
std::dynamic_pointer_cast<Box>(mObject)->SetNear(near);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,13 +232,13 @@ ObjectParser::HandleFarEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 far) {
|
||||
auto onDone = [this](Vector4 far) {
|
||||
std::dynamic_pointer_cast<Box>(mObject)->SetFar(far);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,13 +251,13 @@ ObjectParser::HandleNormalEvent(yaml_event_t& event)
|
|||
return;
|
||||
}
|
||||
|
||||
auto onDone = [this](Vector3 normal) {
|
||||
auto onDone = [this](Vector4 normal) {
|
||||
std::dynamic_pointer_cast<Plane>(mObject)->SetNormal(normal);
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
};
|
||||
|
||||
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
|
||||
GetParsers().push(new Vector4Parser(GetScene(), GetParsers(), onDone));
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,3 +282,4 @@ ObjectParser::HandleDistanceEvent(yaml_event_t& event)
|
|||
}
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "yaml/scalarMappingParser.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
struct ObjectParser
|
||||
|
@ -66,5 +67,6 @@ private:
|
|||
};
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_OBJECTPARSER_HH__ */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "parsers.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
#pragma mark Parser
|
||||
|
@ -81,3 +82,4 @@ template<>
|
|||
const char* ScalarParserTraits<double>::fmt = "%lf";
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
|
||||
#include "yaml.h"
|
||||
|
||||
#include "scene.h"
|
||||
#include "scene.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
struct Parser;
|
||||
|
@ -144,5 +145,6 @@ ParseScalar(const std::string& scalar,
|
|||
}
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_PARSERS_HH__ */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "scalarMappingParser.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
ScalarMappingParser::ScalarMappingParser(Scene& scene,
|
||||
|
@ -83,3 +84,4 @@ ScalarMappingParser::GetShouldExpectKey()
|
|||
}
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "yaml/parsers.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
struct ScalarMappingParser
|
||||
|
@ -40,5 +41,6 @@ private:
|
|||
};
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_SCALARMAPPINGPARSER_HH__ */
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "vectorParser.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
SceneParser::SceneParser(Scene& scene,
|
||||
|
@ -95,8 +96,8 @@ SceneParser::HandleDimensionsEvent(yaml_event_t& event)
|
|||
}
|
||||
|
||||
Scene& sc = GetScene();
|
||||
sc.set_width(dimensions.at(0));
|
||||
sc.set_height(dimensions.at(1));
|
||||
sc.SetWidth(dimensions.at(0));
|
||||
sc.SetHeight(dimensions.at(1));
|
||||
|
||||
mSection = NoSection;
|
||||
SetShouldExpectKey(true);
|
||||
|
@ -137,3 +138,4 @@ SceneParser::HandleObjectsEvent(yaml_event_t& event)
|
|||
}
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "scalarMappingParser.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
struct SceneParser
|
||||
|
@ -43,5 +44,6 @@ private:
|
|||
};
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_SCENE_PARSER_HH__ */
|
||||
|
|
|
@ -8,9 +8,14 @@
|
|||
#include "yaml/vectorParser.hh"
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
Vector3Parser::Vector3Parser(Scene& scene,
|
||||
Vector4Parser::Vector4Parser(Scene& scene,
|
||||
ParserStack& parsers,
|
||||
CallbackFunction onDone)
|
||||
: ScalarSequenceParser(scene, parsers)
|
||||
|
@ -20,16 +25,12 @@ Vector3Parser::Vector3Parser(Scene& scene,
|
|||
assert(seq.size() != 3);
|
||||
return;
|
||||
}
|
||||
onDone(Vector3(seq[0], seq[1], seq[2]));
|
||||
onDone(Vector4(seq[0], seq[1], seq[2]));
|
||||
};
|
||||
SetCallback(onSeqDone);
|
||||
}
|
||||
|
||||
|
||||
Vector3Parser::~Vector3Parser()
|
||||
{ }
|
||||
|
||||
|
||||
ColorParser::ColorParser(Scene& scene,
|
||||
ParserStack& parsers,
|
||||
CallbackFunction onDone)
|
||||
|
@ -50,8 +51,5 @@ ColorParser::ColorParser(Scene& scene,
|
|||
SetCallback(onSeqDone);
|
||||
}
|
||||
|
||||
|
||||
ColorParser::~ColorParser()
|
||||
{ }
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
#include <vector>
|
||||
|
||||
#include "parsers.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace yaml {
|
||||
|
||||
/**
|
||||
|
@ -82,25 +84,24 @@ private:
|
|||
};
|
||||
|
||||
|
||||
struct Vector3Parser
|
||||
: ScalarSequenceParser<double>
|
||||
struct Vector4Parser
|
||||
: ScalarSequenceParser<Double>
|
||||
{
|
||||
typedef std::function<void (Vector3)> CallbackFunction;
|
||||
typedef std::function<void (basics::Vector4)> CallbackFunction;
|
||||
|
||||
Vector3Parser(Scene& scene, ParserStack& parsers, CallbackFunction onDone);
|
||||
~Vector3Parser();
|
||||
Vector4Parser(Scene& scene, ParserStack& parsers, CallbackFunction onDone);
|
||||
};
|
||||
|
||||
|
||||
struct ColorParser
|
||||
: ScalarSequenceParser<double>
|
||||
: ScalarSequenceParser<Double>
|
||||
{
|
||||
typedef std::function<void (Color)> CallbackFunction;
|
||||
typedef std::function<void (basics::Color)> CallbackFunction;
|
||||
|
||||
ColorParser(Scene& scene, ParserStack& parsers, CallbackFunction onDone);
|
||||
~ColorParser();
|
||||
};
|
||||
|
||||
} /* namespace yaml */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __YAML_VECTOR_PARSER_HH__ */
|
||||
|
|
8
test/testObject.cc
Normal file
8
test/testObject.cc
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* test_object.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "object.hh"
|
|
@ -7,158 +7,319 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "basics.h"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
class Vector3Test
|
||||
using charles::basics::Vector4;
|
||||
using charles::basics::Matrix4;
|
||||
|
||||
|
||||
class Vector4Test
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
virtual void SetUp();
|
||||
|
||||
protected:
|
||||
Vector3 v1, v2;
|
||||
Vector4 v1, v2;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Vector3Test::SetUp()
|
||||
Vector4Test::SetUp()
|
||||
{
|
||||
v1 = Vector3(1, 3, 5);
|
||||
v2 = Vector3(7, 13, 17);
|
||||
v1 = Vector4(1, 3, 5);
|
||||
v2 = Vector4(7, 13, 17);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorEq)
|
||||
TEST_F(Vector4Test, OperatorEq)
|
||||
{
|
||||
v1 = v2;
|
||||
EXPECT_EQ(v2, v1);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorMul)
|
||||
TEST_F(Vector4Test, OperatorMul)
|
||||
{
|
||||
Vector3 out;
|
||||
Vector4 out;
|
||||
|
||||
out = v1 * 5;
|
||||
EXPECT_EQ(5, out.x);
|
||||
EXPECT_EQ(15, out.y);
|
||||
EXPECT_EQ(25, out.z);
|
||||
EXPECT_EQ(5, out.X());
|
||||
EXPECT_EQ(15, out.Y());
|
||||
EXPECT_EQ(25, out.Z());
|
||||
|
||||
out = v1 * -7;
|
||||
EXPECT_EQ(-7, out.x);
|
||||
EXPECT_EQ(-21, out.y);
|
||||
EXPECT_EQ(-35, out.z);
|
||||
EXPECT_EQ(-7, out.X());
|
||||
EXPECT_EQ(-21, out.Y());
|
||||
EXPECT_EQ(-35, out.Z());
|
||||
|
||||
out = v1;
|
||||
out *= 5;
|
||||
EXPECT_EQ(5, out.x);
|
||||
EXPECT_EQ(15, out.y);
|
||||
EXPECT_EQ(25, out.z);
|
||||
EXPECT_EQ(5, out.X());
|
||||
EXPECT_EQ(15, out.Y());
|
||||
EXPECT_EQ(25, out.Z());
|
||||
|
||||
out = v1;
|
||||
out *= -7;
|
||||
EXPECT_EQ(-7, out.x);
|
||||
EXPECT_EQ(-21, out.y);
|
||||
EXPECT_EQ(-35, out.z);
|
||||
EXPECT_EQ(-7, out.X());
|
||||
EXPECT_EQ(-21, out.Y());
|
||||
EXPECT_EQ(-35, out.Z());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorDiv)
|
||||
TEST_F(Vector4Test, OperatorDiv)
|
||||
{
|
||||
Vector3 out;
|
||||
Vector4 out;
|
||||
|
||||
out = v1 / 5.0;
|
||||
EXPECT_FLOAT_EQ(1.0/5.0, out.x);
|
||||
EXPECT_FLOAT_EQ(3.0/5.0, out.y);
|
||||
EXPECT_FLOAT_EQ(5.0/5.0, out.z);
|
||||
EXPECT_FLOAT_EQ(1.0/5.0, out.X());
|
||||
EXPECT_FLOAT_EQ(3.0/5.0, out.Y());
|
||||
EXPECT_FLOAT_EQ(5.0/5.0, out.Z());
|
||||
|
||||
out = v1 / -7.0;
|
||||
EXPECT_FLOAT_EQ(1.0/-7.0, out.x);
|
||||
EXPECT_FLOAT_EQ(3.0/-7.0, out.y);
|
||||
EXPECT_FLOAT_EQ(5.0/-7.0, out.z);
|
||||
EXPECT_FLOAT_EQ(1.0/-7.0, out.X());
|
||||
EXPECT_FLOAT_EQ(3.0/-7.0, out.Y());
|
||||
EXPECT_FLOAT_EQ(5.0/-7.0, out.Z());
|
||||
|
||||
out = v1;
|
||||
out /= 5.0;
|
||||
EXPECT_FLOAT_EQ(1.0/5.0, out.x);
|
||||
EXPECT_FLOAT_EQ(3.0/5.0, out.y);
|
||||
EXPECT_FLOAT_EQ(5.0/5.0, out.z);
|
||||
EXPECT_FLOAT_EQ(1.0/5.0, out.X());
|
||||
EXPECT_FLOAT_EQ(3.0/5.0, out.Y());
|
||||
EXPECT_FLOAT_EQ(5.0/5.0, out.Z());
|
||||
|
||||
out = v1;
|
||||
out /= -7.0;
|
||||
EXPECT_FLOAT_EQ(1.0/-7.0, out.x);
|
||||
EXPECT_FLOAT_EQ(3.0/-7.0, out.y);
|
||||
EXPECT_FLOAT_EQ(5.0/-7.0, out.z);
|
||||
EXPECT_FLOAT_EQ(1.0/-7.0, out.X());
|
||||
EXPECT_FLOAT_EQ(3.0/-7.0, out.Y());
|
||||
EXPECT_FLOAT_EQ(5.0/-7.0, out.Z());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorAdd)
|
||||
TEST_F(Vector4Test, OperatorAdd)
|
||||
{
|
||||
Vector3 out;
|
||||
Vector4 out;
|
||||
|
||||
out = v1 + v2;
|
||||
EXPECT_EQ(8, out.x);
|
||||
EXPECT_EQ(16, out.y);
|
||||
EXPECT_EQ(22, out.z);
|
||||
EXPECT_EQ(8, out.X());
|
||||
EXPECT_EQ(16, out.Y());
|
||||
EXPECT_EQ(22, out.Z());
|
||||
|
||||
out = v1;
|
||||
out += v2;
|
||||
EXPECT_EQ(8, out.x);
|
||||
EXPECT_EQ(16, out.y);
|
||||
EXPECT_EQ(22, out.z);
|
||||
EXPECT_EQ(8, out.X());
|
||||
EXPECT_EQ(16, out.Y());
|
||||
EXPECT_EQ(22, out.Z());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorSub)
|
||||
TEST_F(Vector4Test, OperatorSub)
|
||||
{
|
||||
Vector3 out;
|
||||
Vector4 out;
|
||||
|
||||
out = v1 - v2;
|
||||
EXPECT_EQ(-6, out.x);
|
||||
EXPECT_EQ(-10, out.y);
|
||||
EXPECT_EQ(-12, out.z);
|
||||
EXPECT_EQ(-6, out.X());
|
||||
EXPECT_EQ(-10, out.Y());
|
||||
EXPECT_EQ(-12, out.Z());
|
||||
|
||||
out = v2 - v1;
|
||||
EXPECT_EQ(6, out.x);
|
||||
EXPECT_EQ(10, out.y);
|
||||
EXPECT_EQ(12, out.z);
|
||||
EXPECT_EQ(6, out.X());
|
||||
EXPECT_EQ(10, out.Y());
|
||||
EXPECT_EQ(12, out.Z());
|
||||
|
||||
v1 -= v2;
|
||||
EXPECT_EQ(-6, v1.x);
|
||||
EXPECT_EQ(-10, v1.y);
|
||||
EXPECT_EQ(-12, v1.z);
|
||||
EXPECT_EQ(-6, v1.X());
|
||||
EXPECT_EQ(-10, v1.Y());
|
||||
EXPECT_EQ(-12, v1.Z());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorBoolEq)
|
||||
TEST_F(Vector4Test, OperatorBoolEq)
|
||||
{
|
||||
EXPECT_EQ(v1, v1);
|
||||
EXPECT_EQ(v2, v2);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, OperatorBoolNe)
|
||||
TEST_F(Vector4Test, OperatorBoolNe)
|
||||
{
|
||||
EXPECT_NE(v1, v2);
|
||||
EXPECT_NE(v2, v1);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, Length2)
|
||||
TEST_F(Vector4Test, Length2)
|
||||
{
|
||||
EXPECT_EQ(35.0, v1.length2());
|
||||
EXPECT_EQ(507.0, v2.length2());
|
||||
EXPECT_EQ(35.0, v1.Length2());
|
||||
EXPECT_EQ(507.0, v2.Length2());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, Length)
|
||||
TEST_F(Vector4Test, Length)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(5.916079783099616, v1.length());
|
||||
EXPECT_FLOAT_EQ(22.5166604983954, v2.length());
|
||||
EXPECT_FLOAT_EQ(5.916079783099616, v1.Length());
|
||||
EXPECT_FLOAT_EQ(22.5166604983954, v2.Length());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Vector3Test, DotProduct)
|
||||
TEST_F(Vector4Test, DotProduct)
|
||||
{
|
||||
EXPECT_EQ(131.0, v1.dot(v2));
|
||||
EXPECT_EQ(131.0, v1.Dot(v2));
|
||||
}
|
||||
|
||||
#pragma mark Matrix4 Tests
|
||||
|
||||
class Matrix4Test
|
||||
: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
virtual void SetUp();
|
||||
|
||||
protected:
|
||||
Matrix4 m1, m2;
|
||||
Matrix4 id;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Matrix4Test::SetUp()
|
||||
{
|
||||
const Double m1Cells[] = { 1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16};
|
||||
m1 = Matrix4(m1Cells);
|
||||
|
||||
const Double m2Cells[] = { 1, 1, 2, 3,
|
||||
5, 8, 13, 21,
|
||||
34, 55, 89, 144,
|
||||
233, 377, 610, 987};
|
||||
m2 = Matrix4(m2Cells);
|
||||
|
||||
id = Matrix4::Identity();
|
||||
}
|
||||
|
||||
|
||||
TEST(Matrix4StaticTest, Zero)
|
||||
{
|
||||
Matrix4 zero = Matrix4::Zero();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(zero.CArray()[i], 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Matrix4StaticTest, Identity)
|
||||
{
|
||||
Matrix4 id = Matrix4::Identity();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(id.CArray()[i * 4 + j], ((i == j) ? 1.0 : 0.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, OperatorCall)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(m1(i, j), 4 * i + j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, ScalarMultiplication)
|
||||
{
|
||||
Matrix4 p1 = m1 * 2.0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(p1(i, j), m1(i, j) * 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix4 p2 = 2.0 * m1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(p2(i, j), m1(i, j) * 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, MatrixMatrixMultiplication)
|
||||
{
|
||||
const Double p1Expect[] = {1045, 1690, 2735, 4425,
|
||||
2137, 3454, 5591, 9045,
|
||||
3229, 5218, 8447, 13665,
|
||||
4321, 6982, 11303, 18285};
|
||||
Matrix4 p1 = m1 * m2;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(p1.CArray()[i], p1Expect[i]);
|
||||
}
|
||||
|
||||
const Double p2Expect[] = { 63, 70, 77, 84,
|
||||
435, 482, 529, 576,
|
||||
2982, 3304, 3626, 3948,
|
||||
20439, 22646, 24853, 27060};
|
||||
Matrix4 p2 = m2 * m1;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(p2.CArray()[i], p2Expect[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, MatrixIdentityMultiplication)
|
||||
{
|
||||
Matrix4 p1 = m1 * id;
|
||||
for (UInt i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(p1.CArray()[i], m1.CArray()[i]);
|
||||
}
|
||||
|
||||
Matrix4 p2 = id * m1;
|
||||
for (UInt i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(p2.CArray()[i], m1.CArray()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, IdentityVectorMultiplication)
|
||||
{
|
||||
Vector4 v1(1, 2, 3);
|
||||
|
||||
Vector4 p1 = id * v1;
|
||||
EXPECT_EQ(p1.X(), v1.X());
|
||||
EXPECT_EQ(p1.Y(), v1.Y());
|
||||
EXPECT_EQ(p1.Z(), v1.Z());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, TranslationVectorMultiplication)
|
||||
{
|
||||
Matrix4 tr = Matrix4::Translation(1, 2, 3);
|
||||
Vector4 v1(3, 7, 9);
|
||||
|
||||
Vector4 p1 = tr * v1;
|
||||
EXPECT_EQ(p1.X(), 4.0);
|
||||
EXPECT_EQ(p1.Y(), 9.0);
|
||||
EXPECT_EQ(p1.Z(), 12.0);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, Transpose)
|
||||
{
|
||||
Matrix4 t1 = Transpose(m1);
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(m1(i,j), t1(j,i));
|
||||
}
|
||||
}
|
||||
|
||||
t1.Transpose();
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
EXPECT_EQ(m1(i,j), t1(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/* test_object.c
|
||||
*
|
||||
* Unit tests for the object module.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
#include "object.h"
|
||||
#include "test_asserts.h"
|
||||
#include "test_suites.h"
|
||||
|
||||
|
||||
void check_sphere_intersection(Object *sphere, Ray ray, Vector3 *tvectors, int ntvectors);
|
||||
|
||||
|
||||
START_TEST(test_sphere_does_intersect)
|
||||
{
|
||||
// Create a sphere at the origin of radius 1.
|
||||
Object *sphere = object_init(ObjectTypeSphere);
|
||||
object_sphere_set_radius(sphere, 1.0);
|
||||
|
||||
Vector3 loc, dir;
|
||||
Vector3 tvectors[2];
|
||||
Ray ray;
|
||||
|
||||
loc = vector_init(0, 0, -5);
|
||||
dir = vector_init(0, 0, 1);
|
||||
ray = ray_init(loc, dir);
|
||||
tvectors[0] = vector_init(0, 0, -1);
|
||||
tvectors[1] = vector_init(0, 0, 1);
|
||||
check_sphere_intersection(sphere, ray, tvectors, 2);
|
||||
|
||||
loc = vector_init(0, -5, 0);
|
||||
dir = vector_init(0, 1, 0);
|
||||
ray = ray_init(loc, dir);
|
||||
tvectors[0] = vector_init(0, -1, 0);
|
||||
tvectors[1] = vector_init(0, 1, 0);
|
||||
check_sphere_intersection(sphere, ray, tvectors, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
void
|
||||
check_sphere_intersection(Object *sphere, Ray ray, Vector3 *tvectors, int ntvectors)
|
||||
{
|
||||
float *t;
|
||||
int nints = object_does_intersect(sphere, ray, &t);
|
||||
ck_assert(nints == ntvectors);
|
||||
|
||||
Vector3 rp;
|
||||
for (int i = 0; i < nints; i++) {
|
||||
rp = ray_parameterize(ray, t[i]);
|
||||
test_assert_within_epsilon(rp.x, tvectors[i].x, 1e-4);
|
||||
test_assert_within_epsilon(rp.y, tvectors[i].y, 1e-4);
|
||||
test_assert_within_epsilon(rp.z, tvectors[i].z, 1e-4);
|
||||
}
|
||||
|
||||
if (nints > 0) {
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
START_TEST(test_sphere_point_lies_on_surface)
|
||||
{
|
||||
ck_assert(0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(test_sphere_compute_normal)
|
||||
{
|
||||
ck_assert(0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
Suite *
|
||||
test_object_create_suite()
|
||||
{
|
||||
Suite *s = suite_create("object");
|
||||
|
||||
TCase *tc_sphere = tcase_create("sphere");
|
||||
tcase_add_test(tc_sphere, test_sphere_does_intersect);
|
||||
tcase_add_test(tc_sphere, test_sphere_point_lies_on_surface);
|
||||
tcase_add_test(tc_sphere, test_sphere_compute_normal);
|
||||
suite_add_tcase(s, tc_sphere);
|
||||
|
||||
return s;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue