summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs38
-rw-r--r--src/sdf.rs119
-rw-r--r--src/win.rs108
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;
diff --git a/src/sdf.rs b/src/sdf.rs
index 52120db..ac38d75 100644
--- a/src/sdf.rs
+++ b/src/sdf.rs
@@ -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()?
}
}
-
-
diff --git a/src/win.rs b/src/win.rs
index 1ccc1c0..eab7b8f 100644
--- a/src/win.rs
+++ b/src/win.rs
@@ -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());