summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock182
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs132
-rw-r--r--src/sdf.rs82
-rw-r--r--src/win.rs78
5 files changed, 468 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2f5d73f..ad36445 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,13 +3,35 @@
version = 3
[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
name = "autosdf"
version = "0.1.0"
dependencies = [
"gl",
+ "nalgebra",
]
[[package]]
+name = "bytemuck"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f"
+
+[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -51,6 +73,166 @@ dependencies = [
]
[[package]]
+name = "matrixmultiply"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
+dependencies = [
+ "rawpointer",
+]
+
+[[package]]
+name = "nalgebra"
+version = "0.31.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20bd243ab3dbb395b39ee730402d2e5405e448c75133ec49cc977762c4cba3d1"
+dependencies = [
+ "approx",
+ "matrixmultiply",
+ "nalgebra-macros",
+ "num-complex",
+ "num-rational",
+ "num-traits",
+ "simba",
+ "typenum",
+]
+
+[[package]]
+name = "nalgebra-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "safe_arch"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "simba"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176"
+dependencies = [
+ "approx",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "wide",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "typenum"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "wide"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c"
+dependencies = [
+ "bytemuck",
+ "safe_arch",
+]
+
+[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index e351af7..afac22e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2021"
[dependencies]
gl = "0.14.0"
+nalgebra = "0.31.4"
diff --git a/src/main.rs b/src/main.rs
index fdd2f54..dc29e2b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,18 +1,134 @@
+extern crate nalgebra;
+
mod sdl;
pub mod win;
+pub mod sdf;
+
+use nalgebra::{Vector3, Matrix3, Rotation3};
+type Vec3 = Vector3<f32>;
+type Mat3 = Matrix3<f32>;
+type Rot3 = Rotation3<f32>;
+
+struct View {
+ pos: Vec3,
+ yaw: f32,
+ pitch: f32
+}
+
+impl Default for View {
+ fn default() -> Self {
+ Self {
+ pos: Vec3::zeros(),
+ yaw: 0.0,
+ pitch: 0.0
+ }
+ }
+}
+
+impl View {
+ /// `camera_rotation() * vec3(0, 0, -1)` is the direction the camera is pointing
+ fn camera_rotation(&self) -> Mat3 {
+ *Rot3::from_euler_angles(self.pitch, self.yaw, 0.0).matrix()
+ }
+}
+
fn try_main() -> Result<(), String> {
+ let my_sdf = sdf::Sdf::sphere();
+
let mut window = win::Window::new("AutoSDF", 1280, 720, true)
.map_err(|e| format!("Error creating window: {e}"))?;
+ let mut fshader_source = String::new();
+ fshader_source.push_str("
+IN vec2 pos;
+uniform vec3 u_camera_position;
+uniform mat3 u_camera_rotation;
+");
+ my_sdf.to_glsl(&mut fshader_source);
+ fshader_source.push_str("
+#define ITERATIONS 30
+#define AA_X 2
+#define AA_Y 2
+
+
+
+float fbm(vec3 p) {
+ float t = 0.0;
+ float freq = 24.0;
+ mat3 m = mat3(cos(1.),sin(1.),0,
+ -sin(1.),cos(1.),0,
+ 0, 0, 1) * mat3(
+ 1, 0, 0,
+ 0, cos(1.),sin(1.),
+ 0, -sin(1.),cos(1.)
+ );
+ for(int i = 0; i < 5; i++)
+ {
+ p = m * p;
+ t += pow(0.6, float(i)) * sin(freq*p.x)*sin(freq*p.y)*sin(freq*p.z);
+ freq *= 2.0;
+ }
+ return t;
+}
+
+vec3 normal(vec3 p)
+{
+// thanks to https://iquilezles.org/articles/normalsSDF/
+ float h = 0.0001;
+ vec2 k = vec2(1.,-1.);
+ vec3 sdf_normal = k.xyy*sdf(p + k.xyy*h) +
+ k.yyx*sdf(p + k.yyx*h) +
+ k.yxy*sdf(p + k.yxy*h) +
+ k.xxx*sdf(p + k.xxx*h);
+ vec3 noise_normal = k.xyy*fbm(p + k.xyy*h) +
+ k.yyx*fbm(p + k.yyx*h) +
+ k.yxy*fbm(p + k.yxy*h) +
+ k.xxx*fbm(p + k.xxx*h);
+ return normalize(sdf_normal + 0.003 * noise_normal);
+}
+
+void main() {
+ float focal_length = 0.3;
+ float min_dist = 10.;
+ vec2 inv_screen_size = 1.0 / vec2(1280.0, 720.0); // @TODO
+ vec2 aa_delta = inv_screen_size / vec2(AA_X, AA_Y);
+ vec3 final_color = vec3(0);
+ for (int m = 0; m < AA_X; m++) {
+ for (int n = 0; n < AA_Y; n++) {
+ vec3 p = u_camera_position;
+ vec2 aa_offset = vec2(float(m), float(n)) * aa_delta;
+ vec3 delta = normalize(u_camera_rotation * vec3(pos + aa_offset, -focal_length));
+ int i;
+ for (i = 0; i < ITERATIONS; i++) {
+ float dist = sdf(p);
+ min_dist = min(min_dist, dist);
+ if (dist <= 0.01) {
+ float L = 0.3 + max(0., dot(normal(p), normalize(vec3(.8,1,.6))));
+ final_color += L * vec3(1.0, 0.0, 0.0);
+
+ break;
+ }
+ p += dist * delta;
+ }
+ }
+ }
+ final_color *= 1.0 / (AA_X * AA_Y);
+ o_color = vec4(final_color, 1.0);
+}");
+
+ println!("{fshader_source}");
+
let program = window.create_program(
"attribute vec2 v_pos;
+ OUT vec2 pos;
+ uniform float u_aspect_ratio;
+
void main() {
+ pos = v_pos * vec2(u_aspect_ratio, 1.0);
gl_Position = vec4(v_pos, 0.0, 1.0);
}",
- "void main() {
- o_color = vec4(1.0, 0.0, 0.0, 1.0);
- }"
+ &fshader_source
).map_err(|e| format!("Error compiling shader:\n{e}"))?;
let mut buffer = window.create_buffer();
@@ -28,6 +144,8 @@ fn try_main() -> Result<(), String> {
let mut array = window.create_vertex_array(buffer, &program);
window.array_attrib2f(&mut array, "v_pos", 0);
+ let mut view = View::default();
+
'mainloop: loop {
while let Some(event) = window.next_event() {
use win::Event::*;
@@ -35,11 +153,17 @@ fn try_main() -> Result<(), String> {
Quit => break 'mainloop,
_ => {},
}
- println!("{event:?}");
}
+ window.viewport_full_screen();
+
+ view.yaw += 0.002;
+
window.clear_screen(win::ColorF32::BLACK);
window.use_program(&program);
+ window.uniform1f("u_aspect_ratio", window.aspect_ratio());
+ window.uniform3f("u_camera_position", view.pos.x, view.pos.y, view.pos.z);
+ window.uniform3x3f("u_camera_rotation", view.camera_rotation().as_slice());
window.draw_array(&array);
diff --git a/src/sdf.rs b/src/sdf.rs
new file mode 100644
index 0000000..51d85cc
--- /dev/null
+++ b/src/sdf.rs
@@ -0,0 +1,82 @@
+#![allow(dead_code)] // @TODO @TEMPORARY
+
+use std::fmt::Write;
+
+// we're only writing numbers and strings so write! should never fail.
+macro_rules! write_str {
+ ($( $arg:tt )*) => { write!($($arg)*).unwrap() }
+}
+
+enum R3ToR3 {
+ Identity,
+ Translate([f32; 3])
+}
+
+enum RToR {
+ Identity,
+ Add(f32)
+}
+
+pub struct Sdf {
+ pre: R3ToR3,
+ post: RToR
+}
+
+impl RToR {
+ /// treats `v<*initial value of var_idx>` as the input, and puts the output in `v<final value of *var_idx>`.
+ fn to_glsl(&self, code: &mut String, var_idx: &mut u32) {
+ use RToR::*;
+ let input = *var_idx;
+
+ match self {
+ Identity => {}, // no code
+ Add(x) => {
+ *var_idx += 1;
+ let output = *var_idx;
+ write_str!(code, "float v{output} = v{input} + {x};\n");
+ }
+ }
+ }
+}
+
+impl R3ToR3 {
+ /// treats `v<*initial value of var_idx>` as the input, and puts the output in `v<final value of *var_idx>`.
+ fn to_glsl(&self, code: &mut String, var_idx: &mut u32) {
+ use R3ToR3::*;
+ let input = *var_idx;
+
+ match self {
+ Identity => {}, // no code
+ Translate([x, y, z]) => {
+ *var_idx += 1;
+ let output = *var_idx;
+ write_str!(code, "vec3 v{output} = v{input} + vec3({x}, {y}, {z});\n");
+ },
+ }
+ }
+}
+
+impl Sdf {
+ /// test sphere
+ pub fn sphere() -> Self {
+ Self {
+ pre: R3ToR3::Identity,
+ post: RToR::Identity
+ }
+ }
+
+ /// appends some glsl code including a function `float sdf(vec3 p) { ... }`
+ pub fn to_glsl(&self, code: &mut String) {
+ code.push_str("float sdf(vec3 p) {\n");
+ // don't start out right next to the origin, since weird stuff might be happening there
+ let origin_dist: f32 = 2.0;
+ write_str!(code, "vec3 v0 = p - vec3(0,0,-{}.);\n", origin_dist);
+ let mut var_idx = 0;
+ self.pre.to_glsl(code, &mut var_idx);
+ write_str!(code, "float v{} = length(v{}) - 1.0;\n", var_idx + 1, var_idx);
+ var_idx += 1;
+ self.post.to_glsl(code, &mut var_idx);
+ write_str!(code, "return v{var_idx};\n");
+ code.push('}');
+ }
+}
diff --git a/src/win.rs b/src/win.rs
index 781156d..65437d8 100644
--- a/src/win.rs
+++ b/src/win.rs
@@ -664,16 +664,26 @@ impl Window {
self.array_attribnf(array, 4, name, offset)
}
- pub fn size(&mut self) -> (i32, i32) {
+ pub fn size(&self) -> (i32, i32) {
let mut x = 0;
let mut y = 0;
unsafe { sdl::get_window_size(self.sdlwin, &mut x, &mut y) };
(x, y)
}
+
+ pub fn aspect_ratio(&self) -> f32 {
+ let (w, h) = self.size();
+ return w as f32 / h as f32;
+ }
pub fn viewport(&mut self, x: i32, y: i32, w: i32, h: i32) {
unsafe { gl::Viewport(x, y, w, h) };
}
+
+ pub fn viewport_full_screen(&mut self) {
+ let (w, h) = self.size();
+ self.viewport(0, 0, w, h);
+ }
pub fn next_event(&mut self) -> Option<Event> {
loop {
@@ -831,13 +841,75 @@ impl Window {
}
}
- pub fn uniform_texture(&mut self, name: &str, slot: u32) {
+ pub fn uniform1i(&mut self, name: &str, x: i32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform1i(loc, x);
+ }
+ }
+
+ pub fn uniform2i(&mut self, name: &str, x: i32, y: i32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform2i(loc, x, y);
+ }
+ }
+
+ pub fn uniform3i(&mut self, name: &str, x: i32, y: i32, z: i32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform3i(loc, x, y, z);
+ }
+ }
+
+ pub fn uniform4i(&mut self, name: &str, x: i32, y: i32, z: i32, w: i32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform4i(loc, x, y, z, w);
+ }
+ }
+
+ pub fn uniform1f(&mut self, name: &str, x: f32) {
let loc = self.get_uniform_location(name).unwrap_or(-1);
unsafe {
- gl::Uniform1i(loc, slot as i32);
+ gl::Uniform1f(loc, x);
}
}
+ pub fn uniform2f(&mut self, name: &str, x: f32, y: f32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform2f(loc, x, y);
+ }
+ }
+
+ pub fn uniform3f(&mut self, name: &str, x: f32, y: f32, z: f32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform3f(loc, x, y, z);
+ }
+ }
+
+ pub fn uniform4f(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) {
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::Uniform4f(loc, x, y, z, w);
+ }
+ }
+
+ pub fn uniform3x3f(&mut self, name: &str, matrix: &[f32]) {
+ assert_eq!(matrix.len(), 9);
+ let loc = self.get_uniform_location(name).unwrap_or(-1);
+ unsafe {
+ gl::UniformMatrix3fv(loc, 1, 0, matrix.as_ptr());
+ }
+ }
+
+
+ pub fn uniform_texture(&mut self, name: &str, slot: u32) {
+ self.uniform1i(name, slot as i32);
+ }
+
pub fn draw_array(&mut self, array: &VertexArray) {
array.draw();
}