diff options
author | eug-vs <eugene@eug-vs.xyz> | 2021-10-25 15:39:58 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2021-10-25 15:40:23 +0300 |
commit | 67d7492477808dc1765b1a9ed493dee79dff9320 (patch) | |
tree | b472d485c79b164eb472e609d2daaa05258993bf | |
download | pistol-67d7492477808dc1765b1a9ed493dee79dff9320.tar.gz |
feat: initial commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 72 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | src/camera.rs | 93 | ||||
-rw-r--r-- | src/canvas.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 27 | ||||
-rw-r--r-- | src/vector.rs | 83 |
7 files changed, 289 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9515eb1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,72 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ascii-renderer-rust" +version = "0.1.0" +dependencies = [ + "vector3d", +] + +[[package]] +name = "proc-macro2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vector3d" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd7eb407bb0fe64c8abd07288e62029e142815f4c11eb9eba67fa87f07c87e2" +dependencies = [ + "serde", + "serde_derive", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c265707 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ascii-renderer-rust" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +vector3d = "0.2.1" diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..d2fbd5e --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,93 @@ +use crate::vector::Vector; +use std::{cmp::{max, min}, f32::consts::PI, f64::MAX_EXP, fmt}; + +const WIDTH: i32 = 60; +const HEIGHT: i32 = 30; + +#[derive(Debug)] +pub struct Buffer (pub [[char; 60]; 30]); + +impl fmt::Display for Buffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for i in 0..30 { + for j in 0..60 { + write!(f, "{}", self.0[i][j])?; + } + writeln!(f)?; + } + write!(f, "") + } +} + +#[derive(Debug)] +pub struct Camera { + pub position: Vector, + pub direction: Vector, + pub angle: f32, + pub distance: f32, + pub brightness: f32, + pub aspect_ratio: f32, + pub buffer: Buffer, +} + +impl Camera { + pub fn sdf(&self, point: Vector) -> f32 { + let center = Vector { x: 3.0, y: 0.0, z: 0.0 }; + let radius = 1.0; + + return (point - center).magnitude() - radius + } + + pub fn screen(&self) -> (f32, f32) { + let width = self.distance * 2.0 * (self.angle / 2.0).tan(); + let height = width * self.aspect_ratio; + // println!("Screen {}x{} units", width, height); + (width, height) + } + pub fn render(& mut self) { + let palette = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "; + let (screen_width, screen_height) = self.screen(); + + let h_step = self.direction.rotate_z(PI / 2.0).normalized() * screen_width / WIDTH as f32; + let v_step = Vector { x: 0.0, y: 0.0, z: -screen_height / HEIGHT as f32 }; + // println!("Steps: h{}, v{}", h_step, v_step); + + // Initialize with a corner + let point = self.position + (self.direction.normalized() * self.distance) - (h_step * (WIDTH / 2) as f32 + v_step * (HEIGHT / 2) as f32); + // println!("Corner: {}", point); + + let mut ray_dir = point - self.position; + + for i in 0..HEIGHT as usize { + ray_dir = ray_dir + v_step; + for j in 0..WIDTH as usize { + ray_dir = ray_dir + h_step; + + + let brightness = self.shoot_ray(ray_dir); + self.buffer.0[i][j] = palette.chars().nth((brightness * palette.len() as f32) as usize - 1).unwrap(); + // println!("[{}, {}]: {}", i, j, ray_dir); + } + ray_dir = ray_dir - h_step * WIDTH as f32; + } + } + + pub fn shoot_ray(&self, direction: Vector) -> f32 { + let threshold = 0.1; + + let ray = direction.normalized(); + let mut point = self.position; + let mut dist = 0.0; + + while dist < self.brightness { + dist = self.sdf(point); + if dist < threshold { + // println!("Dist: {}, point {}", dist, point); + return (point - self.position).magnitude() / self.brightness + } + point = point + ray * dist; + } + + return 1.0 + } +} diff --git a/src/canvas.rs b/src/canvas.rs new file mode 100644 index 0000000..87413a1 --- /dev/null +++ b/src/canvas.rs @@ -0,0 +1,4 @@ +pub struct Canvas { + pub width: u32, + pub height: u32, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3bf9bb2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,27 @@ +mod vector; +mod camera; +mod canvas; +use std::f32::consts::PI; + +use crate::{camera::{Buffer, Camera}, vector::Vector}; + +trait Object { + fn sdf(&self, point: Vector) -> f32; +} + +fn main() { + let mut cam = Camera { + position: Vector { x: 0.0, y: 0.0, z: 0.0 }, + direction: Vector { x: 1.0, y: 0.0, z: 0.0 }, + angle: PI / 2.0, + distance: 1.0, + aspect_ratio: 1.0, + brightness: 10.0, + buffer: Buffer([['.'; 60]; 30]) + }; + + for _i in 0..60 { + cam.render(); + println!("{}", cam.buffer); + } +} diff --git a/src/vector.rs b/src/vector.rs new file mode 100644 index 0000000..d4e57cc --- /dev/null +++ b/src/vector.rs @@ -0,0 +1,83 @@ +use std::fmt; +use std::ops; + +#[derive(Debug, Clone, Copy)] +pub struct Vector { + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl fmt::Display for Vector { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({:.2}, {:.2}, {:.2})", self.x, self.y, self.z) + } +} + +impl ops::Add for Vector { + type Output = Vector; + fn add(self, rhs: Self) -> Self::Output { + Vector { + x: self.x + rhs.x, + y: self.y + rhs.y, + z: self.z + rhs.z, + } + } +} + +impl ops::Sub for Vector { + type Output = Vector; + fn sub(self, rhs: Self) -> Self::Output { + Vector { + x: self.x - rhs.x, + y: self.y - rhs.y, + z: self.z - rhs.z, + } + } +} + +impl ops::Mul<f32> for Vector { + type Output = Vector; + fn mul(self, rhs: f32) -> Self::Output { + Vector { + x: self.x * rhs, + y: self.y * rhs, + z: self.z * rhs, + } + } +} + +impl ops::Div<f32> for Vector { + type Output = Vector; + fn div(self, rhs: f32) -> Self::Output { + Vector { + x: self.x / rhs, + y: self.y / rhs, + z: self.z / rhs, + } + } +} + +impl Vector { + pub fn magnitude_squared(self) -> f32 { + self.x * self.x + self.y * self.y + self.z * self.z + } + + pub fn magnitude(self) -> f32 { + self.magnitude_squared().sqrt() + } + + pub fn normalized(self) -> Vector { + let mag = self.magnitude(); + self / mag + } + + pub fn rotate_z(self, angle: f32) -> Vector { + // TODO: multiply by a matirx + Vector { + x: self.x * angle.cos() + self.y * angle.sin(), + y: self.y * angle.cos() - self.x * angle.sin(), + z: self.z, + } + } +} |