aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2021-10-25 15:39:58 +0300
committereug-vs <eugene@eug-vs.xyz>2021-10-25 15:40:23 +0300
commit67d7492477808dc1765b1a9ed493dee79dff9320 (patch)
treeb472d485c79b164eb472e609d2daaa05258993bf
downloadpistol-67d7492477808dc1765b1a9ed493dee79dff9320.tar.gz
feat: initial commit
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock72
-rw-r--r--Cargo.toml9
-rw-r--r--src/camera.rs93
-rw-r--r--src/canvas.rs4
-rw-r--r--src/main.rs27
-rw-r--r--src/vector.rs83
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,
+ }
+ }
+}