diff options
author | pommicket <pommicket@gmail.com> | 2022-12-16 22:49:18 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-12-16 22:49:18 -0500 |
commit | 2d569091a912568257bb73f1501ac6d9af6c2c6c (patch) | |
tree | a409b9142ddf39b4910419d15376e45a394d91ad /src | |
parent | 7eebf9ff97b5a20605fe153def6273e95b174e4e (diff) |
fmt
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 38 | ||||
-rw-r--r-- | src/sdf.rs | 119 | ||||
-rw-r--r-- | src/win.rs | 108 |
3 files changed, 165 insertions, 100 deletions
diff --git a/src/main.rs b/src/main.rs index a2b7e88..346331c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,7 +77,7 @@ impl View { fn yaw_by(&mut self, yaw: f32) { self.rotation *= Rot3::from_euler_angles(0.0, yaw, 0.0); } - + fn pitch_by(&mut self, pitch: f32) { self.rotation *= Rot3::from_euler_angles(pitch, 0.0, 0.0); } @@ -92,8 +92,11 @@ impl View { } } -fn gen_program_from_scene(window: &mut win::Window, program: &mut win::Program, scene: &sdf::Scene) -> Result<(), String> { - +fn gen_program_from_scene( + window: &mut win::Window, + program: &mut win::Program, + scene: &sdf::Scene, +) -> Result<(), String> { let mut fshader_source = String::new(); fshader_source.push_str( " @@ -130,7 +133,9 @@ float sdf_torus(vec3 p, vec2 t) { ", ); scene.sdf.to_glsl_function("sdf", &mut fshader_source); - scene.color_function.to_glsl_function("get_color_", &mut fshader_source); + scene + .color_function + .to_glsl_function("get_color_", &mut fshader_source); fshader_source.push_str( " @@ -238,7 +243,8 @@ void main() { println!("scene: {}", scene.export_string()); window - .link_program(program, + .link_program( + program, "IN vec2 v_pos; OUT vec2 pos; uniform float u_aspect_ratio; @@ -253,15 +259,19 @@ void main() { Ok(()) } -fn gen_program_with_seed(window: &mut win::Window, program: &mut win::Program, seed: u64) -> Result<(), String> { +fn gen_program_with_seed( + window: &mut win::Window, + program: &mut win::Program, + seed: u64, +) -> Result<(), String> { use rand::SeedableRng; - + let mut rng = rand::rngs::SmallRng::seed_from_u64(seed); let my_sdf = sdf::R3ToR::good_random(&mut rng, 6); let color_function = sdf::R3ToR3::good_random(&mut rng, 7); let scene = sdf::Scene { sdf: my_sdf, - color_function + color_function, }; gen_program_from_scene(window, program, &scene) } @@ -272,14 +282,16 @@ fn gen_program(window: &mut win::Window, program: &mut win::Program) -> Result<( } #[allow(dead_code)] // @TODO @TEMPORARY -fn gen_program_from_string(window: &mut win::Window, program: &mut win::Program, s: &str) -> Result<(), String> { +fn gen_program_from_string( + window: &mut win::Window, + program: &mut win::Program, + s: &str, +) -> Result<(), String> { let scene = sdf::Scene::import_string(s).ok_or_else(|| "bad scene string".to_string())?; gen_program_from_scene(window, program, &scene) } - fn try_main() -> Result<(), String> { - let mut window = win::Window::new("AutoSDF", 1280, 720, true) .map_err(|e| format!("Error creating window: {e}"))?; let mut program = window.new_program(); @@ -320,7 +332,7 @@ fn try_main() -> Result<(), String> { KeyDown(R) => { gen_program(&mut window, &mut program)?; view.level_set = 0.0; - }, + } KeyDown(N0) => view.level_set = 0.0, MouseMotion { xrel, yrel, .. } => { let mouse_sensitivity = 0.05; @@ -364,7 +376,7 @@ fn try_main() -> Result<(), String> { } let mut speed_multiplier = if window.is_shift_down() { 10.0 } else { 1.0 }; speed_multiplier *= if window.is_ctrl_down() { 0.1 } else { 1.0 }; - + let motion = Vec3::new(dx, dy, dz); if let Some(motion) = motion.try_normalize(0.001) { let move_speed = 4.0 * speed_multiplier; @@ -1,13 +1,13 @@ -extern crate serde_cbor; -extern crate serde; extern crate gen_random_proc_macro; extern crate rand; +extern crate serde; +extern crate serde_cbor; use gen_random::GenRandom; use gen_random_proc_macro::GenRandom; -use std::fmt::{self, Display, Formatter, Write}; use rand::Rng; -use serde_derive::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; +use std::fmt::{self, Display, Formatter, Write}; // we're only writing numbers and strings so write! should never fail. macro_rules! write_str { @@ -21,13 +21,13 @@ pub enum Constant { F32(f32), #[prob(0)] Time( - #[scale(0.2)] - #[bias(-0.1)] - f32, f32), + #[scale(0.2)] + #[bias(-0.1)] + f32, + f32, + ), } - - impl From<f32> for Constant { fn from(x: f32) -> Self { Self::F32(x) @@ -120,7 +120,7 @@ pub enum R3ToR3 { SqSin(Constant), // based on 1/x² sin(x²) #[prob(2)] #[bias(0.01)] - Sigmoid //based on sigmoid(x) = 1 / (1 + e^-x) + Sigmoid, //based on sigmoid(x) = 1 / (1 + e^-x) } // note : i dont think R → R transformations really accomplish that much @@ -146,14 +146,14 @@ pub enum R3ToR { #[scale(3.0)] size: Constant, #[scale(0.2)] - thickness: Constant + thickness: Constant, }, #[prob(1)] - Torus { + Torus { #[scale(3.0)] radius: Constant, #[scale(0.2)] - thickness: Constant + thickness: Constant, }, #[prob(8)] Compose(Box<R3ToR3>, Box<R3ToR>, Box<RToR>), @@ -260,7 +260,7 @@ trait Function: Sized + GenRandom { fn input_type() -> GLSLType; /// GLSL type which is the output of this function fn output_type() -> GLSLType; - + /// adds GLSL code for function to `code`. fn to_glsl_function(&self, name: &str, code: &mut String) { let mut var = VarCounter::new(); @@ -272,11 +272,9 @@ trait Function: Sized + GenRandom { Self::input_type() ); let output = self.to_glsl(input, code, &mut var); - write_str!( - code, - "return {output};\n}}\n\n"); + write_str!(code, "return {output};\n}}\n\n"); } - + fn good_random(rng: &mut impl Rng, max_depth: isize) -> Self { // to make sure the function isn't too boring or too slow, // we'll generate a bunch then take the one with the median code length. @@ -287,24 +285,26 @@ trait Function: Sized + GenRandom { let mut var = VarCounter::new(); let _ = f.to_glsl(var.next(), &mut code, &mut var); let len = code.len(); - + functions.push((len, f)); } functions.sort_by_key(|x| x.0); functions.remove(functions.len() / 2).1 } - + fn good_thread_random(max_depth: isize) -> Self { Self::good_random(&mut rand::thread_rng(), max_depth) } } - - impl Function for RToR { - fn input_type() -> GLSLType { GLSLType::Float } - fn output_type() -> GLSLType { GLSLType::Float } - + fn input_type() -> GLSLType { + GLSLType::Float + } + fn output_type() -> GLSLType { + GLSLType::Float + } + fn to_glsl(&self, input: Variable, code: &mut String, var: &mut VarCounter) -> Variable { use RToR::*; @@ -324,9 +324,13 @@ impl Function for RToR { } impl Function for R3ToR3 { - fn input_type() -> GLSLType { GLSLType::Vec3 } - fn output_type() -> GLSLType { GLSLType::Vec3 } - + fn input_type() -> GLSLType { + GLSLType::Vec3 + } + fn output_type() -> GLSLType { + GLSLType::Vec3 + } + fn to_glsl(&self, input: Variable, code: &mut String, var: &mut VarCounter) -> Variable { use R3ToR3::*; @@ -367,7 +371,7 @@ impl Function for R3ToR3 { // we need to scale arctan(cx) so it doesn't break the SDF write_str!(code, "vec3 {output} = (1.0 / {c}) * atan({c} * {input});\n"); output - }, + } Rotate(by) => { // by = euler angles // see https://en.wikipedia.org/wiki/Rotation_matrix#General_rotations @@ -379,11 +383,14 @@ impl Function for R3ToR3 { let output = var.next(); write_str!(code, "vec3 {c} = cos({by});\n"); write_str!(code, "vec3 {s} = sin({by});\n"); - write_str!(code, "mat3 {m} = mat3( + write_str!( + code, + "mat3 {m} = mat3( {c}.y*{c}.z, {s}.x*{s}.y*{c}.z - {c}.x*{s}.z, {c}.x*{s}.y*{c}.z + {s}.x*{s}.z, {c}.y*{s}.z, {s}.x*{s}.y*{s}.z + {c}.x*{c}.z, {c}.x*{s}.y*{s}.z - {s}.x*{c}.z, -{s}.y, {s}.x*{c}.y, {c}.x*{c}.y -);\n"); +);\n" + ); write_str!(code, "vec3 {output} = {m} * {input};\n"); output } @@ -392,12 +399,18 @@ impl Function for R3ToR3 { let a = var.next(); write_str!(code, "vec3 {a} = 0.1 + abs({input});\n"); write_str!(code, "{a} *= {a};\n"); - write_str!(code, "vec3 {output} = 0.7593/(pow({c},1.5)*{a}) * sin({c}*{a});\n"); + write_str!( + code, + "vec3 {output} = 0.7593/(pow({c},1.5)*{a}) * sin({c}*{a});\n" + ); output } Sigmoid => { let output = var.next(); - write_str!(code, "vec3 {output} = 2.0 - abs(4.0 / (1.0 + exp(-{input})) - 2.0);\n"); + write_str!( + code, + "vec3 {output} = 2.0 - abs(4.0 / (1.0 + exp(-{input})) - 2.0);\n" + ); output } } @@ -405,9 +418,13 @@ impl Function for R3ToR3 { } impl Function for R3ToR { - fn input_type() -> GLSLType { GLSLType::Vec3 } - fn output_type() -> GLSLType { GLSLType::Float } - + fn input_type() -> GLSLType { + GLSLType::Vec3 + } + fn output_type() -> GLSLType { + GLSLType::Float + } + fn to_glsl(&self, input: Variable, code: &mut String, var: &mut VarCounter) -> Variable { use R3ToR::*; match self { @@ -430,12 +447,18 @@ impl Function for R3ToR { } BoxFrame { size, thickness } => { let output = var.next(); - write_str!(code, "float {output} = sdf_box_frame({input}, vec3({size}), {thickness});\n"); + write_str!( + code, + "float {output} = sdf_box_frame({input}, vec3({size}), {thickness});\n" + ); output } Torus { radius, thickness } => { let output = var.next(); - write_str!(code, "float {output} = sdf_torus({input}, vec2({radius}, {thickness}));\n"); + write_str!( + code, + "float {output} = sdf_torus({input}, vec2({radius}, {thickness}));\n" + ); output } Mix(a, b, t) => { @@ -492,12 +515,12 @@ fn encode_hex(data: &[u8]) -> String { fn decode_hex(data: &str) -> Option<Vec<u8>> { let data = data.trim(); if data.len() % 2 != 0 { - return None + return None; } - + let mut bytes = Vec::with_capacity(data.len() / 2); for i in 0..data.len() / 2 { - let s = data.get(2*i..2*i+2)?; + let s = data.get(2 * i..2 * i + 2)?; let byte = u8::from_str_radix(s, 16).ok()?; bytes.push(byte); } @@ -508,11 +531,11 @@ impl R3ToR { pub fn good_random(rng: &mut impl Rng, max_depth: isize) -> Self { <Self as Function>::good_random(rng, max_depth) } - + pub fn good_thread_random(max_depth: isize) -> Self { <Self as Function>::good_thread_random(max_depth) } - + pub fn to_glsl_function(&self, name: &str, code: &mut String) { <Self as Function>::to_glsl_function(self, name, code); } @@ -522,11 +545,11 @@ impl R3ToR3 { pub fn good_random(rng: &mut impl Rng, max_depth: isize) -> Self { <Self as Function>::good_random(rng, max_depth) } - + pub fn good_thread_random(max_depth: isize) -> Self { <Self as Function>::good_thread_random(max_depth) } - + pub fn to_glsl_function(&self, name: &str, code: &mut String) { <Self as Function>::to_glsl_function(self, name, code); } @@ -535,7 +558,7 @@ impl R3ToR3 { #[derive(Serialize, Deserialize)] pub struct Scene { pub sdf: R3ToR, - pub color_function: R3ToR3 + pub color_function: R3ToR3, } impl Scene { @@ -546,12 +569,10 @@ impl Scene { let _ = serde_cbor::to_writer(&mut data, self); encode_hex(&data) } - + /// returns None if `s` is not a valid SDF string pub fn import_string(s: &str) -> Option<Self> { let bytes = decode_hex(s)?; serde_cbor::from_reader(&bytes[..]).ok()? } } - - @@ -428,7 +428,10 @@ impl Shader { unsafe fn new_with_id(id: GLuint, r#type: GLenum, source: &str) -> Result<Self, String> { if id == 0 { - return Err(format!("couldn't create shader (GL error {})", gl::GetError())); + return Err(format!( + "couldn't create shader (GL error {})", + gl::GetError() + )); } { @@ -481,7 +484,10 @@ out vec4 o_color; } } - Ok(Self { id, _unused: 0 as _ }) + Ok(Self { + id, + _unused: 0 as _, + }) } } @@ -500,16 +506,18 @@ pub struct Program { impl Program { unsafe fn new() -> Self { let id = gl::CreateProgram(); - Self { id, _unused: 0 as _ } + Self { + id, + _unused: 0 as _, + } } - + unsafe fn new_with_shaders(shaders: &[Shader]) -> Result<Self, String> { let mut program = Self::new(); program.relink(shaders)?; Ok(program) } - unsafe fn relink(&mut self, shaders: &[Shader]) -> Result<(), String> { let id = self.id; for shader in shaders { @@ -535,7 +543,7 @@ impl Program { return Err("failed to link".to_string()); } } - + for shader in shaders { gl::DetachShader(id, shader.id); } @@ -695,12 +703,17 @@ impl Texture { _unused: 0 as _, } } - + unsafe fn bind(&self) { gl::BindTexture(gl::TEXTURE_2D, self.id); } - - unsafe fn set_data<T: Color>(&mut self, data: &[T], width: usize, height: usize) -> Result<(), String> { + + unsafe fn set_data<T: Color>( + &mut self, + data: &[T], + width: usize, + height: usize, + ) -> Result<(), String> { self.width = width; self.height = height; let width: GLsizei = width.try_into().map_err(|_| "width too large")?; @@ -738,27 +751,33 @@ impl Texture { ); Ok(()) } - + pub fn width(&self) -> usize { self.width } - + pub fn height(&self) -> usize { self.height } - + /// panicks if `data` is the wrong length (should be exactly `self.width() * self.height()`). - unsafe fn get_data<T: Color>(&mut self, data: &mut [T]) { - assert_eq!(data.len(), self.width * self.height, "Bad data size."); - self.bind(); - gl::GetTexImage(gl::TEXTURE_2D, 0, T::GL_FORMAT, T::GL_TYPE, data.as_ptr() as *mut GLvoid); - } - - unsafe fn get_data_vec<T: Color>(&mut self) -> Vec<T> { + unsafe fn get_data<T: Color>(&mut self, data: &mut [T]) { + assert_eq!(data.len(), self.width * self.height, "Bad data size."); + self.bind(); + gl::GetTexImage( + gl::TEXTURE_2D, + 0, + T::GL_FORMAT, + T::GL_TYPE, + data.as_ptr() as *mut GLvoid, + ); + } + + unsafe fn get_data_vec<T: Color>(&mut self) -> Vec<T> { let mut data = vec![T::default(); self.width * self.height]; - self.get_data(&mut data); - data - } + self.get_data(&mut data); + data + } } impl Drop for Texture { @@ -811,7 +830,7 @@ pub enum FramebufferAttachment { Color7, Depth, Stencil, - DepthStencil + DepthStencil, } impl FramebufferAttachment { @@ -842,24 +861,32 @@ impl Framebuffer { unsafe fn new() -> Self { let mut id: GLuint = 0; gl::GenFramebuffers(1, (&mut id) as *mut GLuint); - Self { id, _unused: 0 as _ } + Self { + id, + _unused: 0 as _, + } } - + unsafe fn bind(&self) { gl::BindTexture(gl::FRAMEBUFFER, self.id); } - + unsafe fn unbind() { gl::BindTexture(gl::FRAMEBUFFER, 0); } - + unsafe fn set_texture(&mut self, attachment: FramebufferAttachment, texture: &Texture) { self.bind(); texture.bind(); - gl::FramebufferTexture2D(gl::FRAMEBUFFER, attachment.to_gl(), gl::TEXTURE_2D, texture.id, 0); + gl::FramebufferTexture2D( + gl::FRAMEBUFFER, + attachment.to_gl(), + gl::TEXTURE_2D, + texture.id, + 0, + ); Self::unbind(); } - } impl Drop for Framebuffer { @@ -935,7 +962,7 @@ impl Window { sdl::set_relative_mouse_mode(relative); } } - + /// new empty shader program pub fn new_program(&mut self) -> Program { unsafe { Program::new() } @@ -950,7 +977,7 @@ impl Window { let fshader = unsafe { Shader::new(gl::FRAGMENT_SHADER, source_fshader) }?; unsafe { Program::new_with_shaders(&[vshader, fshader]) } } - + pub fn link_program( &mut self, program: &mut Program, @@ -995,18 +1022,23 @@ impl Window { pub fn array_attrib4f(&mut self, array: &mut VertexArray, name: &str, offset: usize) -> bool { self.array_attribnf(array, 4, name, offset) } - + pub fn create_framebuffer(&mut self) -> Framebuffer { unsafe { Framebuffer::new() } } - + /// Attach texture to framebuffer. /// In theory this should check that `framebuffer` does not outlive `texture`, /// but that would be difficult to do in a nice way. - pub fn set_framebuffer_texture(&mut self, framebuffer: &mut Framebuffer, attachment: FramebufferAttachment, texture: &Texture) { + pub fn set_framebuffer_texture( + &mut self, + framebuffer: &mut Framebuffer, + attachment: FramebufferAttachment, + texture: &Texture, + ) { unsafe { framebuffer.set_texture(attachment, texture) }; } - + pub fn set_draw_framebuffer(&mut self, framebuffer: Option<&Framebuffer>) { match framebuffer { Some(f) => unsafe { f.bind() }, @@ -1086,19 +1118,19 @@ impl Window { unsafe { texture.set_data(data, width, height) }?; Ok(()) } - + /// get texture image /// /// panicks if `data.len() != texture.width() * texture.height()` pub fn get_texture_data<T: Color>(&mut self, texture: &mut Texture, data: &mut [T]) { unsafe { texture.get_data(data) }; } - + /// get texture image as a newly-allocated `Vec` pub fn get_texture_data_vec<T: Color>(&mut self, texture: &mut Texture) -> Vec<T> { unsafe { texture.get_data_vec() } } - + pub fn set_audio_callback(&mut self, callback: AudioCallback) -> Result<(), String> { if self.audio_data.is_some() { return Err("audio callback already set.".into()); |