diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | src/n1ck.rs | 306 | ||||
| -rw-r--r-- | src/shaders/wave-fs.glsl | 16 | ||||
| -rw-r--r-- | src/shaders/wave-vs.glsl | 11 | 
4 files changed, 281 insertions, 56 deletions
diff --git a/src/main.rs b/src/main.rs index 5cb2e3a..320aa8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,7 +65,7 @@ fn main() {      stream.play();      let mut tom = Tom::new(waveform); -    let mut n1ck = N1ck::new(); +    let mut n1ck = N1ck::new(&mut surface);      let viewports = gen_viewports(); @@ -93,7 +93,7 @@ fn main() {              if i == 0 || i == 3 {                  surface = tom.draw(surface, &back_buffer, &program, &pipeline_state);              } else if i == 1 || i == 2 { -                surface = n1ck.draw(surface, &back_buffer, &program, &pipeline_state); +                surface = n1ck.draw(surface, &back_buffer, &pipeline_state);              }          } diff --git a/src/n1ck.rs b/src/n1ck.rs index 721e755..8046b2a 100644 --- a/src/n1ck.rs +++ b/src/n1ck.rs @@ -1,68 +1,229 @@ +  use luminance::context::GraphicsContext;  use luminance::framebuffer::Framebuffer; -use luminance::pipeline::PipelineState; +use luminance::pipeline::{BoundTexture, PipelineState};  use luminance::render_state::RenderState; -use luminance::shader::program::Program; -use luminance::tess::{Mode, Tess, TessBuilder, TessSliceIndex}; -use luminance::texture::Dim2; - -use crate::vertex::{Vertex, VertexPosition, VertexRGB, VertexSemantics}; - -fn gen_vertices() -> Vec<Vertex> { -    let mut vertices: Vec<Vertex> = Vec::new(); - -    vertices.push(Vertex { -        position: VertexPosition::new([-0.5, -0.5]), -        color: VertexRGB::new([255, 0, 0]), -    }); -    vertices.push(Vertex { -        position: VertexPosition::new([0.5, -0.5]), -        color: VertexRGB::new([0, 255, 0]), -    }); -    vertices.push(Vertex { -        position: VertexPosition::new([0.0, 0.5]), -        color: VertexRGB::new([0, 0, 255]), -    }); - -    vertices +use luminance::tess::{Mode, Tess, TessBuilder}; +use luminance::texture::{Dim2, GenMipmaps, Sampler, Texture}; +use luminance::pixel::{NormRGB8UI, NormUnsigned}; +use luminance_derive::UniformInterface; +use luminance_derive::{Semantics, Vertex}; +use luminance::linear::M44; + + +use luminance::shader::program::{Program, Uniform}; +use luminance_glfw::{GlfwSurface}; +use std::time::Instant; +use cgmath::{perspective, EuclideanSpace, Matrix4, Point3, Rad, Vector3}; +use std::path::Path; + +use crate::constants; + + +const VS: &'static str = include_str!("./shaders/wave-vs.glsl"); +const FS: &'static str = include_str!("./shaders/wave-fs.glsl"); + +#[derive(UniformInterface)] +struct ShaderInterface { +  // the 'static lifetime acts as “anything” here +  tex: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>, +  position: Uniform<[f32; 2]>, +  intensity: Uniform<f32>, +  time: Uniform<f32>, + +  #[uniform(unbound)] +  projection: Uniform<M44>, +  #[uniform(unbound)] +  view: Uniform<M44>,  } -fn alter_vertices(vertices: &mut Vec<Vertex>) { -    for vertex in vertices { -        if vertex.color[1] < 255 { -            vertex.color[1] += 1; -        } -    } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Semantics)] +pub enum Semantics { +  #[sem(name = "pos", repr = "[f32; 2]", wrapper = "VertexPosition")] +  Position, +  #[sem(name = "uv", repr = "[f32; 2]", wrapper = "UVCoordinate")] +  UV, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Vertex)] +#[vertex(sem = "Semantics")] +struct Vertex { +  pos: VertexPosition, +  uv: UVCoordinate, +} + +#[repr(C)] +struct Beat { +  time: f32, +  position: [f32; 2], +  intensity: f32  } -#[derive(Default)] +const BEATS: [Beat; 15] = [ +  Beat { +    time: 1.03, +    position: [0.5, -0.5], +    intensity: 0.06, +  }, +  Beat { +    time: 3.47, +    position: [-0.5, -0.5], +    intensity: 0.08, +  }, +  Beat{ +    time: 5.84, +    position: [0.5, 0.5], +    intensity: 0.03, +  }, +  Beat{ +    time: 8.30, +    position: [0.5, -0.5], +    intensity: 0.04, +  }, +  Beat{ +    time: 10.76, +    position: [-0.5, 0.5], +    intensity: 0.06, +  }, +  Beat{ +    time: 13.17, +    position: [-0.5, -0.5], +    intensity: 0.08, +  }, +  Beat{ +    time: 15.60, +    position: [0.5, -0.5], +    intensity: 0.09, +  }, +  Beat{ +    time: 18.03, +    position: [-0.5, -0.5], +    intensity: 0.03, +  }, +  Beat{ +    time: 20.48, +    position: [-0.5, 0.5], +    intensity: 0.07, +  }, +  Beat{ +    time: 22.9, +    position: [0.5, -0.5], +    intensity: 0.02, +  }, +  Beat{ +    time: 25.30, +    position: [-0.5, -0.5], +    intensity: 0.12, +  }, +  Beat{ +    time: 27.76, +    position: [0.5, 0.5], +    intensity: 0.05, +  }, +  Beat{ +    time: 30.20, +    position: [-0.5, 0.5], +    intensity: 0.07, +  }, +  Beat{ +    time: 32.6, +    position: [0.5, 0.5], +    intensity: 0.08, +  }, +  Beat{ +    time: 35.07, +    position: [0.5, -0.5], +    intensity: 0.04, +  }, +]; + +const TRI_VERTICES: [Vertex; 4] = [ +  // First triangle – an RGB one. +  Vertex::new( +    VertexPosition::new([-1.0, 1.0]), +    UVCoordinate::new([0.0, 1.0]), +  ), +  Vertex::new( +    VertexPosition::new([1.0, 1.0]), +    UVCoordinate::new([1.0, 1.0]), +  ), +  Vertex::new( +    VertexPosition::new([-1.0, -1.0]), +    UVCoordinate::new([0.0, 0.0]), +  ), +  Vertex::new( +    VertexPosition::new([1.0, -1.0]), +    UVCoordinate::new([1.0, 0.0]), +  ), +]; + + + + +//#[derive(Default)]  pub struct N1ck { -    vertices: Vec<Vertex>, -    tessalations: Vec<Tess>, +    index: usize, +    program: Program<Semantics, (), ShaderInterface>, +    projection: Matrix4<f32>, +    start_time: Instant, +    //surface: GraphicsContext, +    tess:  Vec<Tess>, +    tex: Texture<luminance::texture::Dim2, luminance::pixel::NormRGB8UI>, +    view: Matrix4::<f32>,  }  impl N1ck { -    pub fn new() -> N1ck { -        let vertices = gen_vertices(); -        let tessalations = Vec::new(); +    pub fn new(  surface: &mut GlfwSurface, +    ) -> N1ck { +        let img = read_image(Path::new("data/djbt.jpg")).expect("error while reading image on disk"); +        let tex = load_from_disk(surface, img); + +        let program = Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS) +        .expect("program creation") +        .ignore_warnings(); +        const FOVY: Rad<f32> = Rad(std::f32::consts::PI / 2.); +        const Z_NEAR: f32 = 0.1; +        const Z_FAR: f32 = 10.; +       +        let projection = perspective( +          FOVY, +          constants::WIDTH as f32 / constants::WIDTH as f32, +          Z_NEAR, +          Z_FAR, +        ); +       +        let view = Matrix4::<f32>::look_at(Point3::new(0., 0., 1.), Point3::origin(), Vector3::unit_y()); +                N1ck { -            vertices, -            tessalations, +            index: 0, +            program, +            projection, +            start_time: Instant::now(), +            tess: Vec::new(), +            tex, +            view,          }      }      pub fn update<T: GraphicsContext>(&mut self, mut surface: T) -> T { -        alter_vertices(&mut self.vertices); - -        self.tessalations.clear(); -        self.tessalations.push( +        //let elapsed = &self.start_time.elapsed(); +        //let time = elapsed.as_secs() as f64 + (f64::from(elapsed.subsec_millis()) * 1e-3); +        self.tess.clear(); +     +          self.tess.push(              TessBuilder::new(&mut surface) -                .add_vertices(&self.vertices) -                .set_mode(Mode::Triangle) -                .build() -                .unwrap(), +            .add_vertices(TRI_VERTICES) +            .set_mode(Mode::TriangleStrip) +            .build() +            .unwrap()          ); +        let elapsed = self.start_time.elapsed(); +        let time = elapsed.as_secs() as f64 + (f64::from(elapsed.subsec_millis()) * 1e-3); +        if time as f32 > BEATS[self.index].time { +          self.index = if self.index < 14 { self.index + 1 } else {14}; +        }          surface      } @@ -71,23 +232,60 @@ impl N1ck {          &self,          mut surface: T,          back_buffer: &Framebuffer<Dim2, (), ()>, -        program: &Program<VertexSemantics, (), ()>,          pipeline_state: &PipelineState,      ) -> T {          surface.pipeline_builder().pipeline(              &back_buffer,              &pipeline_state,              |_pipeline, mut shd_gate| { -                shd_gate.shade(&program, |_, mut rdr_gate| { -                    rdr_gate.render(&RenderState::default(), |mut tess_gate| { -                        for tessalation in self.tessalations.iter() { -                            tess_gate.render(tessalation.slice(..)); -                        } -                    }); -                }); +              let bound_tex = _pipeline.bind_texture(&self.tex); + +              shd_gate.shade(&self.program, |interface, mut rdr_gate| { + +                let elapsed = self.start_time.elapsed(); +                let time = elapsed.as_secs() as f64 + (f64::from(elapsed.subsec_millis()) * 1e-3); + +                interface.tex.update(&bound_tex); +                interface.position.update(BEATS[self.index].position); +                interface.intensity.update(BEATS[self.index].intensity); +                interface.time.update(time as f32); +                interface.projection.update(self.projection.into()); +                interface.view.update(self.view.into()); + +                rdr_gate.render(&RenderState::default(), |mut tess_gate| { +                  for tesselation in self.tess.iter() { +                    tess_gate.render(tesselation); +                  }                     +                 }); +              });              },          );          surface      }  } + + +// read the texture into memory as a whole bloc (i.e. no streaming) +fn read_image(path: &Path) -> Option<image::RgbImage> { +  image::open(path).map(|img| img.flipv().to_rgb()).ok() +} + +fn load_from_disk( +  surface: &mut GlfwSurface, +  img: image::RgbImage, +) -> Texture<Dim2, NormRGB8UI> { +  let (width, height) = img.dimensions(); +  let texels = img.into_raw(); + +  // create the luminance texture; the third argument is the number of mipmaps we want (leave it +  // to 0 for now) and the latest is the sampler to use when sampling the texels in the +  // shader (we’ll just use the default one) +  let tex = Texture::new(surface, [width, height], 0, Sampler::default()) +    .expect("luminance texture creation"); + +  // the first argument disables mipmap generation (we don’t care so far) +  tex.upload_raw(GenMipmaps::No, &texels).unwrap(); + +  tex +}
\ No newline at end of file diff --git a/src/shaders/wave-fs.glsl b/src/shaders/wave-fs.glsl new file mode 100644 index 0000000..4923f97 --- /dev/null +++ b/src/shaders/wave-fs.glsl @@ -0,0 +1,16 @@ +in vec2 v_uv; +out vec4 frag; + +uniform sampler2D tex; +uniform vec2 position; +uniform float intensity; +uniform float time; + +void main() { +  vec2 p =-1.+2.*v_uv / vec2(1,1)-position; +  float cLength=length(p); +  vec2 uv=v_uv+(p/cLength)*cos(cLength*32.0-time*4.0)*intensity; +  vec3 col=smoothstep(0.1,.91,texture(tex,uv).xyz); + + frag = texture(tex,uv); +}
\ No newline at end of file diff --git a/src/shaders/wave-vs.glsl b/src/shaders/wave-vs.glsl new file mode 100644 index 0000000..c2584f2 --- /dev/null +++ b/src/shaders/wave-vs.glsl @@ -0,0 +1,11 @@ +in vec3 pos; +in vec2 uv; +out vec2 v_uv; + +uniform mat4 projection; +uniform mat4 view; + +void main() { +  gl_Position =  projection * view * vec4(pos, 1.); +  v_uv = uv;  +}  | 
