summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs4
-rw-r--r--src/n1ck.rs306
-rw-r--r--src/shaders/wave-fs.glsl16
-rw-r--r--src/shaders/wave-vs.glsl11
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;
+}