Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
web-experiments-rs/src/bin/waves.rs
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
198 lines (145 sloc)
4.58 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(generators)] | |
extern crate experiments; | |
use experiments::*; | |
use experiments::rendering::*; | |
use std::f32::consts::PI; | |
use rand::{Rng, Rand, thread_rng, random}; | |
use events::Event; | |
#[derive(Copy, Clone)] | |
#[repr(C)] | |
pub struct Vert (Vec2, Vec3); | |
impl rendering::Vertex for Vert { | |
fn get_layout() -> VertexLayout { | |
VertexLayout::new::<Self>() | |
.add_binding(0, 2, 0) | |
.add_binding(1, 3, 8) | |
} | |
} | |
const DT: f32 = 1.0/60.0; | |
fn main() { | |
std::env::set_var("RUST_BACKTRACE", "1"); | |
set_coro_as_main_loop(|| { | |
let webgl = WebGLContext::new(false); | |
let mut events = Vec::new(); | |
unsafe { | |
events::initialise_ems_event_queue(&mut events); | |
} | |
let shader = ShaderBuilder::new() | |
.use_proj() | |
.frag_attribute("color", "vec3") | |
.output("vec4(v_color, 1.0)") | |
.finalize() | |
.unwrap(); | |
// let mut screen_size = Vec2i::zero(); | |
let mut aspect = 4.0/3.0; | |
let mut projection = Mat4::ident(); | |
let mut mesh = Mesh::new(); | |
let mut mb = MeshBuilder::new(); | |
let generate_waves = || { | |
let mut waves = Vec::new(); | |
let mut rng = thread_rng(); | |
let y_offsets = [0.2, -0.1, -0.4]; | |
let base_hue = random::<f32>() * 360.0; | |
let hue_delta = random::<f32>() * 50.0 - 25.0; | |
let hue_variance = hue_delta.abs() / 25.0; | |
let value_dir = if random() { 1.0 } else { -1.0 }; | |
let value_delta = (random::<f32>() * 0.3 + 0.7) * (2.0 - hue_variance.sqrt()*1.5) * 0.1 * value_dir; | |
let base_value = random::<f32>() * 0.1 + 0.8 - value_delta * 1.5; | |
let saturation = 0.9 - (base_value + hue_variance.sqrt() * 0.5) * random::<f32>() * 0.3; | |
let base_color = Color::hsv(base_hue, saturation, base_value); | |
for (i, &y_off) in y_offsets.iter().enumerate() { | |
let i = i as f32 + 1.0; | |
let hue = base_hue + hue_delta * i; | |
let value = base_value + value_delta * i; | |
let target_color = Color::hsv(hue, saturation, value); | |
waves.push(Wave::new(&mut rng, base_color, target_color, y_off)); | |
} | |
(base_color, waves) | |
}; | |
let (base_color, mut waves) = generate_waves(); | |
webgl.set_background(base_color); | |
loop { | |
for e in events.iter() { | |
match *e { | |
Event::Resize(sz) => { | |
// screen_size = sz; | |
webgl.set_viewport(sz); | |
aspect = sz.x as f32 / sz.y as f32; | |
projection = Mat4::scale(Vec3::new(1.0/aspect, 1.0, 1.0)); | |
} | |
Event::Down(_) => { | |
let (base_color, new_waves) = generate_waves(); | |
webgl.set_background(base_color); | |
waves = new_waves; | |
} | |
_ => {} | |
} | |
} | |
events.clear(); | |
for wave in waves.iter_mut() { wave.update() } | |
webgl.clear_all(); | |
shader.use_program(); | |
shader.set_proj(&projection); | |
mb.clear(); | |
for wave in waves.iter() { | |
wave.build(&mut mb, aspect, 0.05); | |
} | |
mb.upload_to(&mut mesh); | |
mesh.bind(); | |
mesh.draw(gl::TRIANGLES); | |
yield; | |
} | |
}); | |
} | |
struct Wave { | |
phase: f32, | |
freq_mod_phase: f32, | |
amp_phase: f32, | |
amp_mod_phase: f32, | |
freq: f32, | |
freq_mod: f32, | |
freq_mod_amt: f32, | |
amp_freq: f32, | |
amp_mod_freq: f32, | |
wave_color: Color, | |
wave_color_target: Color, | |
y_offset: f32, | |
} | |
impl Wave { | |
fn new<R: Rng>(rng: &mut R, wave_color: Color, wave_color_target: Color, y_offset: f32) -> Self { | |
Wave { | |
phase: rng.gen_range(0.0, 2.0 * PI), | |
amp_phase: rng.gen_range(0.0, 2.0 * PI), | |
amp_mod_phase: rng.gen_range(0.0, 2.0 * PI), | |
freq_mod_phase: rng.gen_range(0.0, 2.0 * PI), | |
freq: rng.gen_range(1.0 / 6.0, 1.0 / 3.0) * 2.0 * PI, | |
freq_mod: rng.gen_range(1.0 / 12.0, 1.0 / 6.0) * 2.0 * PI, | |
freq_mod_amt: rng.gen_range(1.0 / 12.0, 1.0 / 6.0) * 2.0 * PI, | |
amp_freq: rng.gen_range(1.0 / 16.0, 1.0 / 9.0) * 2.0 * PI, | |
amp_mod_freq: rng.gen_range(1.0 / 20.0, 1.0 / 8.0) * 2.0 * PI, | |
wave_color, | |
wave_color_target, | |
y_offset | |
} | |
} | |
fn update(&mut self) { | |
self.amp_mod_phase += DT * self.amp_mod_freq; | |
self.amp_phase += DT * (self.amp_freq * (1.0 + self.amp_mod_phase.sin())) * 0.3; | |
self.freq_mod_phase += DT * self.freq_mod; | |
self.phase += DT * (self.freq + self.freq_mod_phase.sin() * self.freq_mod_amt) * 0.4; | |
self.wave_color = DT.ease_linear(self.wave_color, self.wave_color_target); | |
} | |
fn build(&self, mb: &mut MeshBuilder<Vert>, aspect: f32, seg_width: f32) { | |
let samples = (2.0 * aspect / seg_width).ceil() as usize + 1; | |
let mut vs = Vec::with_capacity(samples); | |
let wave_color = self.wave_color.into(); | |
for s in 0..samples { | |
let x = s as f32 * seg_width - aspect; | |
let amp_mod = (x * self.amp_freq + self.amp_phase).sin() * 0.2; | |
let y = (x * self.freq + self.phase).sin() * amp_mod + self.y_offset; | |
vs.push( Vert(Vec2::new(x,-1.0), wave_color) ); | |
vs.push( Vert(Vec2::new(x, y), wave_color) ); | |
} | |
mb.add_tri_strip(&vs); | |
} | |
} |