aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-08-05 15:44:40 +0200
committerJulian T <julian@jtle.dk>2021-08-05 15:44:40 +0200
commit3ef8f4d918406eec6bdc29e0ebd883fabfac9b2e (patch)
treeaa4b1aac1e165821c16f222ebfb9212a9740e98b /src/core
parent45119506c0293fdde6cef35f6e6f82d4055b46b6 (diff)
Add picture for c5505ab84820248c6dba35fc06aef9e0ced183derendered
Diffstat (limited to 'src/core')
-rw-r--r--src/core/bound2.rs127
-rw-r--r--src/core/bound3.rs113
-rw-r--r--src/core/mod.rs34
-rw-r--r--src/core/ray.rs35
-rw-r--r--src/core/spectrum.rs88
-rw-r--r--src/core/vector2.rs167
-rw-r--r--src/core/vector3.rs185
7 files changed, 0 insertions, 749 deletions
diff --git a/src/core/bound2.rs b/src/core/bound2.rs
deleted file mode 100644
index bc0e7cd..0000000
--- a/src/core/bound2.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-//! Implements a 2d axis aligned bounding box
-use crate::{Number, Float};
-use super::vector2::Vector2;
-use crate::core;
-use crate::core::{min, max};
-
-/// Implements a region between min and max
-#[derive(Clone)]
-pub struct Bound2<T: Number> {
- pub min: Vector2<T>,
- pub max: Vector2<T>
-}
-
-pub type Bound2i = Bound2<i32>;
-pub type Bound2f = Bound2<Float>;
-
-impl<T: Number> Bound2<T> {
- /// Creates a new bound from two points
- ///
- /// p0 does not have to be smaller than p1
- pub fn new(p0: &Vector2<T>, p1: &Vector2<T>) -> Self {
- let min = Vector2::new_xy(min(p0.x, p1.x), min(p0.y, p1.y));
- let max = Vector2::new_xy(max(p0.x, p1.x), max(p0.y, p1.y));
-
- Self { min, max }
- }
-
- pub fn new_xyxy(x1: T, y1: T, x2: T, y2: T) -> Self {
- Self::new(
- &Vector2::new_xy(x1, y1),
- &Vector2::new_xy(x2, y2),
- )
- }
-
- /// Finds the intersected area between two bounds
- pub fn intersect(&self, b: &Bound2<T>) -> Bound2<T> {
- Bound2::new(
- &Vector2::new_xy(max(self.min.x, b.min.x), max(self.min.y, b.min.y)),
- &Vector2::new_xy(min(self.max.x, b.max.x), min(self.max.y, b.max.y)),
- )
- }
-
-
- /// Calculates the diagonal vector
- ///
- /// Can be used to calculate the size of the bound
- ///
- /// # Examples
- ///
- /// ```
- /// use rendering::core::Bound2i;
- /// let b = Bound2i::new_xyxy(2, 2, 6, 7);
- /// let diag = b.diagonal();
- ///
- /// assert!(diag.x == 4 && diag.y == 5);
- /// ```
- pub fn diagonal(&self) -> Vector2<T> {
- self.max - self.min
- }
-
- /// Calculates the area of of the bounded region
- ///
- /// # Examples
- ///
- /// ```
- /// use rendering::core::Bound2i;
- /// let b = Bound2i::new_xyxy(10, 10, 20, 20);
- ///
- /// assert!(b.area() == 100);
- /// ```
- pub fn area(&self) -> T {
- let diag = self.diagonal();
- diag.x * diag.y
- }
-}
-
-impl From<&Bound2i> for Bound2f {
- fn from(b: &Bound2i) -> Self {
- Self {
- min: core::Vector2f::from(b.min),
- max: core::Vector2f::from(b.max),
- }
- }
-}
-
-impl From<&Bound2f> for Bound2i {
- fn from(b: &Bound2f) -> Self {
- Self {
- min: core::Vector2i::from(b.min),
- max: core::Vector2i::from(b.max),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn create_test() -> Bound2<i32> {
- Bound2::new(
- &Vector2::new_xy(1, 2),
- &Vector2::new_xy(10, 3)
- )
- }
-
- #[test]
- fn area() {
- let b = create_test();
-
- assert!(b.area() == 9);
- }
-
- #[test]
- fn intersect_test() {
- let b1 = Bound2i::new_xyxy(10, 10, 20, 20);
- let b2 = Bound2i::new_xyxy(2, 11, 22, 17);
-
- let b = b1.intersect(&b2);
-
- assert!(
- b.min.x == 10 &&
- b.min.y == 11 &&
- b.max.x == 20 &&
- b.max.y == 17
- )
- }
-}
diff --git a/src/core/bound3.rs b/src/core/bound3.rs
deleted file mode 100644
index ce6bb09..0000000
--- a/src/core/bound3.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-//! Implements 3d axis aligned bounding box
-use crate::{Number, Float};
-use super::vector3::{Vector3, Vector3f};
-use crate::core::{min, max};
-use crate::core::Ray;
-
-#[derive(Clone)]
-pub struct Bound3<T: Number> {
- pub min: Vector3<T>,
- pub max: Vector3<T>
-}
-
-pub type Bound3f = Bound3<Float>;
-
-impl<T: Number> Bound3<T> {
- /// Creates a bound from two points
- pub fn new(p0: Vector3<T>, p1: Vector3<T>) -> Self {
- // Elliminate some code duplication here
- let min = Vector3::new_xyz(
- min(p0.x, p1.x),
- min(p0.y, p1.y),
- min(p0.z, p1.z)
- );
- let max = Vector3::new_xyz(
- max(p0.x, p1.x),
- max(p0.y, p1.y),
- max(p0.z, p1.z)
- );
-
- Self {min, max}
- }
-
- pub fn combine(&self, op: &Self) -> Self {
- let min = Vector3::new_xyz(
- min(self.min.x, op.min.x),
- min(self.min.y, op.min.y),
- min(self.min.z, op.min.z)
- );
- let max = Vector3::new_xyz(
- max(self.max.x, op.max.x),
- max(self.max.y, op.max.y),
- max(self.max.z, op.max.z)
- );
-
- Self {min, max}
- }
-
- pub fn and(&self, op: &Self) -> Self {
- let min_b = Vector3::new_xyz(
- max(self.min.x, op.min.x),
- max(self.min.y, op.min.y),
- max(self.min.z, op.min.z)
- );
- let max_b = Vector3::new_xyz(
- min(self.max.x, op.max.x),
- min(self.max.y, op.max.y),
- min(self.max.z, op.max.z)
- );
-
- Self {min: min_b, max: max_b}
- }
-
- pub fn area(&self) -> T {
- let diag = self.max - self.min;
- diag.x * diag.y * diag.z
- }
-}
-
-impl Bound3f {
- pub const EMPTY: Bound3f = Bound3f{min: Vector3f::ZERO, max: Vector3f::ZERO};
-
- /// Calculate whether there is a intersect between a bounding box and a ray
- ///
- /// # Examples:
- ///
- /// ```
- /// use rendering::core::{Bound3f, Vector3f, Ray};
- /// use rendering::INFTY;
- /// let b = Bound3f::new(Vector3f::new(7.0), Vector3f::new(10.0));
- /// let r1 = Ray::new_to(Vector3f::new(0.0), Vector3f::new(5.0));
- /// let r2 = Ray::new_to(Vector3f::new(-0.0), Vector3f::new(-5.0));
- /// let r3 = Ray::new(Vector3f::new_xyz(-1.0, 0.0, 0.0), Vector3f::new_xyz(1.0, 0.0, 0.0));
- ///
- /// assert!(b.intersect(&r1, 0.0, INFTY));
- /// assert!(!b.intersect(&r2, 0.0, INFTY));
- /// assert!(!b.intersect(&r3, 0.0, INFTY));
- /// ```
- pub fn intersect(&self, ray: &Ray, t_min: Float, t_max: Float) -> bool {
- println!("BIN: {} -> {}", self.min, self.max);
- // Method stolen from Ray tracing the next week.
- // They mention its from pixar
- for i in 0..3 {
- let inv = 1.0 / ray.direction[i];
- let mut t0 = (self.min[i] - ray.origin[i]) * inv;
- let mut t1 = (self.max[i] - ray.origin[i]) * inv;
-
- if inv < 0.0 {
- let tmp = t0;
- t0 = t1;
- t1 = tmp;
- }
-
- let t_min = max(t0, t_min);
- let t_max = min(t1, t_max);
-
- if t_max <= t_min {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/src/core/mod.rs b/src/core/mod.rs
deleted file mode 100644
index 95d450c..0000000
--- a/src/core/mod.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! Contains a collection of core modules used by other modules
-//!
-//! Also creates a shortcut for some common types
-
-mod vector2;
-mod vector3;
-mod bound2;
-mod bound3;
-mod spectrum;
-mod ray;
-
-pub use vector2::{Vector2i, Vector2f};
-pub use vector3::Vector3f;
-pub use bound2::{Bound2i, Bound2f};
-pub use bound3::Bound3f;
-pub use spectrum::Spectrum;
-pub use ray::Ray;
-
-use crate::Number;
-
-pub fn min<T: Number> (a: T, b: T) -> T {
- if b < a {
- return b;
- }
- a
-}
-
-pub fn max<T: Number> (a: T, b: T) -> T {
- if b > a {
- return b;
- }
- a
-}
-
diff --git a/src/core/ray.rs b/src/core/ray.rs
deleted file mode 100644
index 19d3cf1..0000000
--- a/src/core/ray.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-//! The ray class used when probing the 3d scene
-use crate::core::Vector3f;
-use crate::Float;
-
-/// A ray that is sent into the world.
-/// This is the main type used for testing intersections.
-pub struct Ray {
- /// Origin of the ray
- pub origin: Vector3f,
- /// Direction is assumed to be a unit vector.
- pub direction: Vector3f,
-}
-
-impl Ray {
- pub fn new(origin: Vector3f, direction: Vector3f) -> Ray {
- Ray {
- origin,
- direction,
- }
- }
-
- pub fn new_to(origin: Vector3f, target: Vector3f) -> Ray {
- let dir = (target - origin).norm();
- Ray {
- origin,
- direction: dir
- }
- }
-
- /// Resolve a point on the ray at time t
- pub fn at(&self, t: Float) -> Vector3f {
- self.origin + self.direction * t
- }
-}
-
diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs
deleted file mode 100644
index ed3505b..0000000
--- a/src/core/spectrum.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-//! Used to represent color
-//!
-//! Currently only implements RGB colors
-use crate::Float;
-
-// TODO implement SampledSpectrum instead for nicer images
-
-#[derive(Clone, Copy, Default)]
-pub struct Spectrum {
- c: [Float; 3],
-}
-
-impl Spectrum {
- pub const ZERO: Self = Spectrum { c: [0.0; 3] };
- pub const WHITE: Self = Spectrum { c: [1.0; 3] };
-
- pub fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum {
- Spectrum { c: [r, g, b] }
- }
-
- pub fn to_rgb(&self, scale: Float) -> (Float, Float, Float) {
- (self.c[0] * scale, self.c[1] * scale, self.c[2] * scale)
- }
-
- pub fn gamma_correct(&self) -> Self {
- Self::new_rgb(
- self.c[0].sqrt(),
- self.c[1].sqrt(),
- self.c[2].sqrt(),
- )
- }
-}
-
-impl std::ops::Mul<Float> for Spectrum {
- type Output = Spectrum;
-
- fn mul(self, op: Float) -> Self::Output {
- Self::Output::new_rgb(
- self.c[0] * op,
- self.c[1] * op,
- self.c[2] * op,
- )
- }
-}
-
-impl std::ops::Mul for Spectrum {
- type Output = Spectrum;
-
- fn mul(self, op: Self) -> Self::Output {
- Self::Output::new_rgb(
- self.c[0] * op.c[0],
- self.c[1] * op.c[1],
- self.c[2] * op.c[2],
- )
- }
-}
-
-impl std::ops::Div<Float> for Spectrum {
- type Output = Spectrum;
-
- fn div(self, op: Float) -> Self::Output {
- Self::Output::new_rgb(
- self.c[0] / op,
- self.c[1] / op,
- self.c[2] / op,
- )
- }
-}
-
-impl std::ops::Add for Spectrum {
- type Output = Spectrum;
-
- fn add(self, op: Self) -> Self::Output {
- Self::Output::new_rgb(
- self.c[0] + op.c[0],
- self.c[1] + op.c[1],
- self.c[2] + op.c[2],
- )
- }
-}
-
-impl std::ops::AddAssign<&Self> for Spectrum {
- fn add_assign(&mut self, op: &Self) {
- self.c[0] += op.c[0];
- self.c[1] += op.c[1];
- self.c[2] += op.c[2];
- }
-}
diff --git a/src/core/vector2.rs b/src/core/vector2.rs
deleted file mode 100644
index 405b12a..0000000
--- a/src/core/vector2.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-//! Implements 2d vectors
-//!
-//! This is implemented generictly with types that fit in the Number trait
-use crate::{Float, Number};
-use std::ops::{Sub, Add, Mul, Div};
-use std::fmt;
-use std::cmp::min;
-
-#[derive(Clone, Copy)]
-pub struct Vector2<T: Number> {
- pub x: T,
- pub y: T,
-}
-
-pub type Vector2f = Vector2<Float>;
-pub type Vector2i = Vector2<i32>;
-
-
-impl<T: Number> Vector2<T> {
- pub fn new(initial: T) -> Vector2<T> {
- Vector2 { x: initial, y: initial }
- }
-
- pub fn new_xy(x: T, y: T) -> Vector2<T> {
- Vector2 { x, y }
- }
-}
-
-impl<T: Number> Sub for Vector2<T> {
- type Output = Self;
- fn sub(self, op: Self) -> Self::Output {
- Self::new_xy(
- self.x - op.x,
- self.y - op.y,
- )
- }
-}
-
-impl<T: Number> Add for Vector2<T> {
- type Output = Self;
- fn add(self, op: Self) -> Self::Output {
- Self::new_xy(
- self.x + op.x,
- self.y + op.y,
- )
- }
-}
-
-impl<T: Number> Mul for Vector2<T> {
- type Output = Self;
- fn mul(self, op: Self) -> Self::Output {
- Self::new_xy(
- self.x * op.x,
- self.y * op.y,
- )
- }
-}
-
-impl<T: Number> Mul<T> for Vector2<T> {
- type Output = Self;
- fn mul(self, op: T) -> Self::Output {
- Self::new_xy(
- self.x * op,
- self.y * op,
- )
- }
-}
-
-impl<T: Number> Div for Vector2<T> {
- type Output = Self;
- fn div(self, op: Self) -> Self::Output {
- Self::new_xy(
- self.x / op.x,
- self.y / op.y,
- )
- }
-}
-
-impl<T: Number> fmt::Display for Vector2<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_fmt(format_args!("[{}, {}]", self.x, self.y))
- }
-}
-
-impl From<Vector2i> for Vector2f {
- fn from(v: Vector2i) -> Self {
- Self {
- x: v.x as Float,
- y: v.y as Float,
- }
- }
-}
-
-impl From<Vector2f> for Vector2i {
- fn from(v: Vector2f) -> Self {
- Self {
- x: v.x as i32,
- y: v.y as i32,
- }
- }
-}
-
-impl Vector2i {
- pub const ZERO: Self = Vector2i {x: 0, y: 0};
-
- pub fn cap(&self, x: i32, y: i32) -> Self {
- Self::new_xy(
- min(self.x, x),
- min(self.y, y),
- )
- }
-}
-
-impl Vector2f {
- pub fn length(&self) -> Float {
- (self.x*self.x + self.y*self.y).sqrt()
- }
-
- pub fn ceil(&self) -> Self {
- Self::new_xy(
- self.x.ceil(),
- self.y.ceil()
- )
- }
-
- pub fn floor(&self) -> Self {
- Self::new_xy(
- self.x.floor(),
- self.y.floor()
- )
- }
-}
-
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn new_vec2() {
- let v = Vector2::new_xy(2.0, 10.0);
-
- assert!(v.x == 2.0 && v.y == 10.0);
-
- let v = Vector2::new(3);
-
- assert!(v.x == 3 && v.y == 3);
- }
-
- #[test]
- fn sub_vec2() {
- let v1 = Vector2::new_xy(10, 11);
- let v2 = Vector2::new_xy(2, 3);
-
- let v3 = v1-v2;
- assert!(v3.x == 8 && v3.y == 8);
- }
-
- #[test]
- fn add_vec2() {
- let v1 = Vector2::new_xy(10, 11);
- let v2 = Vector2::new_xy(2, 3);
-
- let v3 = v1+v2;
- assert!(v3.x == 12 && v3.y == 14);
- }
-}
diff --git a/src/core/vector3.rs b/src/core/vector3.rs
deleted file mode 100644
index 1cc6f60..0000000
--- a/src/core/vector3.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-//! Implements 3d vectors
-//!
-//! Also add more 3d math things needed for shading and 3d calculations.
-use crate::{Float, Number, NEAR_ZERO};
-use std::ops::{Mul, Sub, Add, DivAssign, Neg, AddAssign, Index};
-use std::fmt;
-
-#[derive(Clone, Copy)]
-pub struct Vector3<T: Number> {
- pub x: T,
- pub y: T,
- pub z: T,
-}
-
-pub type Vector3f = Vector3<Float>;
-
-impl<T: Number> Vector3<T> {
- pub fn new(initial: T) -> Vector3<T> {
- Vector3 {
- x: initial,
- y: initial,
- z: initial,
- }
- }
-
- pub fn new_xyz(x: T, y: T, z: T) -> Vector3<T> {
- Vector3 { x, y, z}
- }
-}
-
-impl<T: Number> Sub for Vector3<T> {
- type Output = Self;
- fn sub(self, op: Self) -> Self::Output {
- Self::new_xyz(
- self.x - op.x,
- self.y - op.y,
- self.z - op.z,
- )
- }
-}
-
-impl<T: Number> Add for Vector3<T> {
- type Output = Self;
- fn add(self, op: Self) -> Self::Output {
- Self::new_xyz(
- self.x + op.x,
- self.y + op.y,
- self.z + op.z,
- )
- }
-}
-
-impl<T: Number> Add<T> for Vector3<T> {
- type Output = Self;
-
- fn add(self, op: T) -> Self::Output {
- Self::new_xyz(
- self.x + op,
- self.y + op,
- self.z + op,
- )
- }
-}
-
-impl<T: Number> Mul<T> for Vector3<T> {
- type Output = Self;
- fn mul(self, op: T) -> Self::Output {
- Self::Output::new_xyz(
- self.x * op,
- self.y * op,
- self.z * op,
- )
- }
-}
-
-impl<T: Number> Neg for Vector3<T> {
- type Output = Self;
-
- fn neg(self) -> Self::Output {
- Self::Output::new_xyz(
- -self.x,
- -self.y,
- -self.z,
- )
- }
-}
-
-impl<T: Number> AddAssign<&Self> for Vector3<T> {
- fn add_assign(&mut self, op: &Self) {
- self.x += op.x;
- self.y += op.y;
- self.z += op.z;
- }
-}
-
-impl<T: Number> DivAssign<T> for Vector3<T> {
- fn div_assign(&mut self, op: T) {
- self.x /= op;
- self.y /= op;
- self.z /= op;
- }
-}
-
-impl<T: Number> fmt::Display for Vector3<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_fmt(format_args!("[{}, {}, {}]", self.x, self.y, self.z))
- }
-}
-
-// Ohh god
-impl<T: Number> Index<u32> for Vector3<T> {
- type Output = T;
-
- fn index(&self, i: u32) -> &Self::Output {
- match i {
- 0 => &self.x,
- 1 => &self.y,
- 2 => &self.z,
- _ => panic!("index out of bounds: index {} is not possible with 3d vector", i)
- }
- }
-}
-
-impl Vector3f {
- pub const ZERO: Self = Vector3f {x: 0.0, y: 0.0, z: 0.0};
-
- /// Calculates the length times itself
- ///
- /// This is faster than using len * len as the square is ommited
- pub fn len_squared(&self) -> Float {
- self.x * self.x + self.y * self.y + self.z * self.z
- }
-
- pub fn length(&self) -> Float {
- self.len_squared().sqrt()
- }
-
- pub fn dot(&self, op: &Self) -> Float {
- self.x * op.x + self.y * op.y + self.z * op.z
- }
-
- /// Inplace normal instead of creating a new vector
- ///
- /// # Example
- ///
- /// ```
- /// use rendering::core::Vector3f;
- /// let mut v = Vector3f::new_xyz(10.0, 0.0, 0.0);
- /// v.norm_in();
- /// assert!(v.x == 1.0);
- /// ```
- pub fn norm_in(&mut self) {
- // TODO Experiment with checking for normality with len_squared
- let len = self.length();
- if len == 0.0 {
- *self = Self::new(0.0);
- }
-
- *self /= len;
- }
-
- pub fn norm(&self) -> Self {
- let mut new = *self;
- new.norm_in();
- new
- }
-
- pub fn cross(&self, op: &Self) -> Self {
- Self::new_xyz(
- self.y * op.z - self.z * op.y,
- self.z * op.x - self.x * op.z,
- self.x * op.y - self.y * op.x,
- )
-
- }
-
- /// Check if vector is close to [0, 0, 0]
- ///
- /// This is based on the NEAR_ZERO constant
- pub fn near_zero(&self) -> bool {
- (self.x.abs() < NEAR_ZERO) &&
- (self.y.abs() < NEAR_ZERO) &&
- (self.z.abs() < NEAR_ZERO)
- }
-}