You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
652 lines
21 KiB
652 lines
21 KiB
#[macro_use]
|
|
extern crate log;
|
|
#[macro_use]
|
|
extern crate glium;
|
|
extern crate nalgebra as na;
|
|
|
|
use glium::glutin;
|
|
use vis_core::analyzer;
|
|
|
|
macro_rules! shader_program {
|
|
// {{{
|
|
($display:expr, $vert_file:expr, $frag_file:expr) => {{
|
|
// Use this for debug
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
let vert_src = {
|
|
use std::io::Read;
|
|
let mut buf = String::new();
|
|
let mut f = std::fs::File::open(format!("src/{}", $vert_file)).unwrap();
|
|
f.read_to_string(&mut buf).unwrap();
|
|
|
|
buf
|
|
};
|
|
|
|
let frag_src = {
|
|
use std::io::Read;
|
|
let mut buf = String::new();
|
|
let mut f = std::fs::File::open(format!("src/{}", $frag_file)).unwrap();
|
|
f.read_to_string(&mut buf).unwrap();
|
|
|
|
buf
|
|
};
|
|
|
|
glium::Program::from_source($display, &vert_src, &frag_src, None).unwrap()
|
|
}
|
|
|
|
// Use this for release
|
|
#[cfg(not(debug_assertions))]
|
|
glium::Program::from_source(
|
|
$display,
|
|
include_str!($vert_file),
|
|
include_str!($frag_file),
|
|
None,
|
|
)
|
|
.unwrap()
|
|
}};
|
|
} // }}}
|
|
|
|
#[derive(Copy, Clone)]
|
|
struct Vertex {
|
|
position: [f32; 4],
|
|
color_id: u16,
|
|
}
|
|
|
|
glium::implement_vertex!(Vertex, position, color_id);
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct VisInfo {
|
|
beat: u64,
|
|
beat_volume: f32,
|
|
volume: f32,
|
|
analyzer: analyzer::FourierAnalyzer,
|
|
spectrum: analyzer::Spectrum<Vec<f32>>,
|
|
}
|
|
|
|
fn main() {
|
|
#[cfg(debug_assertions)]
|
|
vis_core::default_config();
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
vis_core::CONFIG.init(
|
|
[ezconf::Source::Memory(include_str!("../visualizer.toml"))].iter()
|
|
).unwrap();
|
|
|
|
vis_core::default_log();
|
|
|
|
let mut frames = {
|
|
// Analyzer {{{
|
|
let mut beat = analyzer::BeatBuilder::new().build();
|
|
let mut beat_num = 0;
|
|
|
|
let analyzer = analyzer::FourierBuilder::new().plan();
|
|
|
|
vis_core::Visualizer::new(
|
|
VisInfo {
|
|
beat: 0,
|
|
beat_volume: 0.0,
|
|
volume: 0.0,
|
|
spectrum: analyzer::Spectrum::new(vec![0.0; analyzer.buckets()], 0.0, 1.0),
|
|
analyzer,
|
|
},
|
|
move |info, samples| {
|
|
if beat.detect(&samples) {
|
|
beat_num += 1;
|
|
}
|
|
info.beat = beat_num;
|
|
info.beat_volume = beat.last_volume();
|
|
info.volume = samples.volume(0.3);
|
|
|
|
info.analyzer.analyze(&samples);
|
|
info.spectrum.fill_from(&info.analyzer.average());
|
|
|
|
info
|
|
},
|
|
)
|
|
.async_analyzer(vis_core::CONFIG.get_or("audio.conversions", 300))
|
|
.frames()
|
|
// }}}
|
|
};
|
|
|
|
// Config {{{
|
|
// Window
|
|
let window_width = vis_core::CONFIG.get_or("window.width", 1280);
|
|
let window_height = vis_core::CONFIG.get_or("window.height", 720);
|
|
let aspect = window_width as f32 / window_height as f32;
|
|
|
|
// Columns
|
|
let rows = vis_core::CONFIG.get_or("noa.cols.rows", 50);
|
|
let cols = vis_core::CONFIG.get_or("noa.cols.num", 30);
|
|
let nrow = cols * 4;
|
|
let cols_per_note = vis_core::CONFIG.get_or("noa.cols.note_width", 6);
|
|
let notes_num = cols * 2 / cols_per_note;
|
|
let width = vis_core::CONFIG.get_or("noa.cols.width", 10.0);
|
|
let depth = vis_core::CONFIG.get_or("noa.cols.depth", 30.0);
|
|
let rowsize = depth / rows as f32;
|
|
let mid_dist = vis_core::CONFIG.get_or("noa.cols.mid_dist", 0.1);
|
|
let base_height = vis_core::CONFIG.get_or("noa.cols.base_height", 0.2);
|
|
let base_speed = vis_core::CONFIG.get_or("noa.cols.speed", 0.1);
|
|
let slowdown = vis_core::CONFIG.get_or("noa.cols.slowdown", 0.995);
|
|
let speed_deviation = vis_core::CONFIG.get_or("noa.cols.speed_deviation", 50.0);
|
|
let ampli_top = vis_core::CONFIG.get_or("noa.cols.amp_top", 0.7);
|
|
let ampli_bottom = vis_core::CONFIG.get_or("noa.cols.amp_bottom", 0.2);
|
|
|
|
let frame_time =
|
|
std::time::Duration::from_micros(1000000 / vis_core::CONFIG.get_or("noa.fps", 30));
|
|
|
|
// Colors
|
|
let colors: Vec<[f32; 4]> = vis_core::CONFIG.get_or(
|
|
"noa.cols.colors",
|
|
vec![
|
|
[0.30142, 0.01884, 0.00886, 1.0],
|
|
[0.13589, 0.30142, 0.17280, 1.0],
|
|
[0.28444, 0.42378, 0.13589, 1.0],
|
|
[0.56103, 0.49275, 0.12457, 1.0],
|
|
[0.90064, 0.59079, 0.12457, 1.0],
|
|
|
|
[0.90064, 0.59079, 0.12457, 1.0],
|
|
[0.56103, 0.49275, 0.12457, 1.0],
|
|
[0.28444, 0.42378, 0.13589, 1.0],
|
|
[0.13589, 0.30142, 0.17280, 1.0],
|
|
[0.30142, 0.01884, 0.00886, 1.0],
|
|
],
|
|
);
|
|
let note_roll_size = vis_core::CONFIG.get_or("noa.cols.note_roll", 20) as f32;
|
|
|
|
// Camera
|
|
let cam_height = vis_core::CONFIG.get_or("noa.camera.height", 1.0);
|
|
let cam_look = vis_core::CONFIG.get_or("noa.camera.look_height", 0.8);
|
|
|
|
// }}}
|
|
|
|
// Window Initialization {{{
|
|
let mut events_loop = glutin::EventsLoop::new();
|
|
let window = glutin::WindowBuilder::new()
|
|
.with_dimensions(glutin::dpi::LogicalSize::new(
|
|
window_width as f64,
|
|
window_height as f64,
|
|
))
|
|
.with_maximized(true)
|
|
.with_decorations(false)
|
|
.with_fullscreen(Some(events_loop.get_primary_monitor()))
|
|
.with_title("Visualizer2 - NoAmbition");
|
|
|
|
let context = glutin::ContextBuilder::new()
|
|
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (4, 1)))
|
|
.with_gl_profile(glutin::GlProfile::Core)
|
|
.with_multisampling(0);
|
|
|
|
let display = glium::Display::new(window, context, &events_loop).unwrap();
|
|
// }}}
|
|
|
|
// Framebuffer Initialization {{{
|
|
let tex1 = glium::texture::Texture2d::empty_with_format(
|
|
&display,
|
|
glium::texture::UncompressedFloatFormat::F32F32F32F32,
|
|
glium::texture::MipmapsOption::NoMipmap,
|
|
window_width,
|
|
window_height,
|
|
)
|
|
.unwrap();
|
|
let depth1 = glium::texture::DepthTexture2d::empty_with_format(
|
|
&display,
|
|
glium::texture::DepthFormat::F32,
|
|
glium::texture::MipmapsOption::NoMipmap,
|
|
window_width,
|
|
window_height,
|
|
)
|
|
.unwrap();
|
|
let mut framebuffer1 =
|
|
glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, &tex1, &depth1).unwrap();
|
|
|
|
let tex2 = glium::texture::Texture2d::empty_with_format(
|
|
&display,
|
|
glium::texture::UncompressedFloatFormat::F32F32F32F32,
|
|
glium::texture::MipmapsOption::NoMipmap,
|
|
window_width,
|
|
window_height,
|
|
)
|
|
.unwrap();
|
|
let depth2 = glium::texture::DepthTexture2d::empty_with_format(
|
|
&display,
|
|
glium::texture::DepthFormat::F32,
|
|
glium::texture::MipmapsOption::NoMipmap,
|
|
window_width,
|
|
window_height,
|
|
)
|
|
.unwrap();
|
|
let mut framebuffer2 =
|
|
glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, &tex2, &depth2).unwrap();
|
|
// }}}
|
|
|
|
// Shader Initialization {{{
|
|
let prepass_program = shader_program!(&display, "shaders/prepass.vert", "shaders/prepass.frag");
|
|
let background_program =
|
|
shader_program!(&display, "shaders/pp.vert", "shaders/background.frag");
|
|
// let fxaa_program = shader_program!(&display, "shaders/pp.vert", "shaders/fxaa.frag");
|
|
let apply_alpha_program = shader_program!(&display, "shaders/pp.vert", "shaders/apply_alpha.frag");
|
|
let chromatic_program = shader_program!(&display, "shaders/pp.vert", "shaders/chromatic.frag");
|
|
let bokeh_program = shader_program!(&display, "shaders/pp.vert", "shaders/bokeh.frag");
|
|
let color_program = shader_program!(&display, "shaders/pp.vert", "shaders/color.frag");
|
|
// }}}
|
|
|
|
// Buffers {{{
|
|
|
|
// Quad {{{
|
|
let quad_verts = {
|
|
#[derive(Copy, Clone)]
|
|
struct Vertex {
|
|
position: [f32; 4],
|
|
texcoord: [f32; 2],
|
|
}
|
|
|
|
glium::implement_vertex!(Vertex, position, texcoord);
|
|
|
|
glium::VertexBuffer::new(
|
|
&display,
|
|
&[
|
|
Vertex {
|
|
position: [-1.0, -1.0, 0.0, 1.0],
|
|
texcoord: [0.0, 0.0],
|
|
},
|
|
Vertex {
|
|
position: [1.0, -1.0, 0.0, 1.0],
|
|
texcoord: [1.0, 0.0],
|
|
},
|
|
Vertex {
|
|
position: [1.0, 1.0, 0.0, 1.0],
|
|
texcoord: [1.0, 1.0],
|
|
},
|
|
Vertex {
|
|
position: [-1.0, 1.0, 0.0, 1.0],
|
|
texcoord: [0.0, 1.0],
|
|
},
|
|
],
|
|
)
|
|
.unwrap()
|
|
};
|
|
let quad_inds = glium::IndexBuffer::new(
|
|
&display,
|
|
glium::index::PrimitiveType::TrianglesList,
|
|
&[0u16, 1, 2, 0, 2, 3],
|
|
)
|
|
.unwrap();
|
|
// }}}
|
|
|
|
// Lines {{{
|
|
let (mut lines_verts, mut lines_colors) = {
|
|
let colsmax = (cols - 1) as f32 / width * 2.0;
|
|
let rowsmax = (rows - 1) as f32 / depth;
|
|
let h = base_height / 2.0;
|
|
let mut v_buf = Vec::with_capacity(rows * cols * 4);
|
|
|
|
for row in 0..rows {
|
|
let y = row as f32 / rowsmax;
|
|
// Left
|
|
for col in 0..cols {
|
|
let x = -(col as f32 / colsmax) - mid_dist;
|
|
let cid = (cols - col - 1) / cols_per_note;
|
|
v_buf.push(Vertex {
|
|
position: [x, y, -h, 1.0],
|
|
color_id: cid as u16,
|
|
});
|
|
v_buf.push(Vertex {
|
|
position: [x, y, h, 1.0],
|
|
color_id: cid as u16,
|
|
});
|
|
}
|
|
|
|
// Right
|
|
for col in 0..cols {
|
|
let x = (col as f32 / colsmax) + mid_dist;
|
|
let cid = col / cols_per_note + notes_num / 2;
|
|
v_buf.push(Vertex {
|
|
position: [x, y, -h, 1.0],
|
|
color_id: cid as u16,
|
|
});
|
|
v_buf.push(Vertex {
|
|
position: [x, y, h, 1.0],
|
|
color_id: cid as u16,
|
|
});
|
|
}
|
|
}
|
|
|
|
let mut colors_buf = [[1.0, 0.0, 0.0, 1.0]; 32];
|
|
for (buf, color) in colors_buf.iter_mut().zip(colors.iter()) {
|
|
*buf = *color;
|
|
}
|
|
let lines_colors =
|
|
glium::uniforms::UniformBuffer::persistent(&display, colors_buf).unwrap();
|
|
|
|
(
|
|
glium::VertexBuffer::persistent(&display, &v_buf).unwrap(),
|
|
lines_colors,
|
|
)
|
|
};
|
|
// }}}
|
|
|
|
// Points {{{
|
|
let points_colors = {
|
|
let mut colors_buf = [[1.0, 0.0, 0.0, 1.0]; 32];
|
|
for (buf, color) in colors_buf.iter_mut().zip(colors.iter()) {
|
|
*buf = *color;
|
|
}
|
|
glium::uniforms::UniformBuffer::persistent(&display, colors_buf).unwrap()
|
|
};
|
|
// }}}
|
|
|
|
// Lightning {{{
|
|
// }}}
|
|
|
|
// }}}
|
|
|
|
// Image {{{
|
|
let image = image::load(
|
|
std::io::Cursor::new(&include_bytes!("logo.png")[..]),
|
|
image::PNG,
|
|
)
|
|
.unwrap()
|
|
.to_rgba();
|
|
let image_dims = image.dimensions();
|
|
let image = glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dims);
|
|
let c3_texture = glium::texture::CompressedSrgbTexture2d::new(&display, image).unwrap();
|
|
// }}}
|
|
|
|
let mut previous_time = 0.0;
|
|
let mut previous_offset = 0.0;
|
|
let mut rolling_volume = 0.0;
|
|
let mut write_row = rows * 3 / 4;
|
|
let mut last_beat = -100.0;
|
|
|
|
let mut notes_spectrum = analyzer::Spectrum::new(vec![0.0; notes_num], 220.0, 660.0);
|
|
let mut notes_rolling_buf = vec![0.0; notes_num];
|
|
let mut row_buf = Vec::with_capacity(nrow);
|
|
let mut row_spectrum = vec![0.0; cols];
|
|
|
|
let mut beat_rolling = 0.0;
|
|
let mut last_beat_num = 0;
|
|
|
|
let mut maxima_buf = [(0.0, 0.0); 8];
|
|
|
|
'main: for frame in frames.iter() {
|
|
use glium::Surface;
|
|
|
|
let start = std::time::Instant::now();
|
|
let delta = frame.time - previous_time;
|
|
trace!("Delta: {}s", delta);
|
|
|
|
// Audio Info Retrieval {{{
|
|
let (volume, maxima, notes_rolling_spectrum, base_volume) = frame.info(|info| {
|
|
rolling_volume = info.volume.max(rolling_volume * slowdown);
|
|
|
|
if info.beat != last_beat_num {
|
|
last_beat = frame.time;
|
|
last_beat_num = info.beat;
|
|
}
|
|
|
|
let notes_spectrum = info.spectrum.fill_spectrum(&mut notes_spectrum);
|
|
|
|
for (n, s) in notes_rolling_buf.iter_mut().zip(notes_spectrum.iter()) {
|
|
*n = (*n * (note_roll_size - 1.0) + s) / note_roll_size;
|
|
}
|
|
let notes_rolling_spectrum = vis_core::analyzer::Spectrum::new(
|
|
&mut *notes_rolling_buf,
|
|
notes_spectrum.lowest(),
|
|
notes_spectrum.highest(),
|
|
);
|
|
|
|
let maxima = notes_rolling_spectrum.find_maxima(&mut maxima_buf);
|
|
|
|
(
|
|
info.volume,
|
|
maxima,
|
|
notes_rolling_spectrum,
|
|
info.beat_volume,
|
|
)
|
|
});
|
|
// }}}
|
|
|
|
// GL Matrices {{{
|
|
let view = na::Matrix4::look_at_rh(
|
|
&na::Point3::new(0.0, -1.0, cam_height),
|
|
&na::Point3::new(0.0, 10.0, cam_look),
|
|
&na::Vector3::new(0.0, 0.0, 1.0),
|
|
);
|
|
|
|
let perspective =
|
|
na::Matrix4::new_perspective(aspect, std::f32::consts::FRAC_PI_4, 0.001, 100.0);
|
|
// }}}
|
|
|
|
// Grid {{{
|
|
let speed = base_speed + rolling_volume * speed_deviation;
|
|
let offset = (previous_offset + delta * speed) % rowsize;
|
|
let model_grid =
|
|
na::Translation3::from(na::Vector3::new(0.0, -offset, 0.0)).to_homogeneous();
|
|
|
|
// Color Notes {{{
|
|
{
|
|
let mut color_buf = lines_colors.map();
|
|
for color in color_buf.iter_mut() {
|
|
color[3] = 0.05;
|
|
}
|
|
for (f, _) in maxima.iter().take(4) {
|
|
let note = notes_rolling_spectrum.freq_to_id(*f);
|
|
color_buf[note][3] = 1.0;
|
|
}
|
|
}
|
|
// }}}
|
|
|
|
// Spectral Grid {{{
|
|
if previous_offset > offset {
|
|
let mut lines_buf = lines_verts.map();
|
|
// We jumped right here
|
|
// Save last rows y coordinate
|
|
row_buf.clear();
|
|
let last_row_offset = lines_buf.len() - nrow;
|
|
for i in 0..nrow {
|
|
row_buf.push(lines_buf[last_row_offset + i].position[1]);
|
|
}
|
|
// Copy y coordinate of each line to the next
|
|
for i in (nrow..(lines_buf.len())).rev() {
|
|
lines_buf[i].position[1] = lines_buf[i - nrow].position[1];
|
|
}
|
|
// Write saved info to first row (cycle rows)
|
|
for i in 0..nrow {
|
|
lines_buf[i].position[1] = row_buf[i];
|
|
}
|
|
|
|
// Write spectral information
|
|
frame.info(|info| {
|
|
let left = info
|
|
.analyzer
|
|
.left()
|
|
.slice(100.0, 800.0)
|
|
.fill_buckets(&mut row_spectrum[..]);
|
|
let row_offset = nrow * write_row;
|
|
let max = left.max() + 0.0001;
|
|
for (i, v) in left.iter().enumerate() {
|
|
lines_buf[row_offset + i * 2 + 1].position[2] =
|
|
base_height / 2.0 + v / max * ampli_top;
|
|
lines_buf[row_offset + i * 2].position[2] =
|
|
-base_height / 2.0 - v / max * ampli_bottom;
|
|
}
|
|
|
|
let right = info
|
|
.analyzer
|
|
.right()
|
|
.slice(100.0, 800.0)
|
|
.fill_buckets(&mut row_spectrum[..]);
|
|
let row_offset = nrow * write_row + cols * 2;
|
|
let max = right.max() + 0.0001;
|
|
for (i, v) in right.iter().enumerate() {
|
|
lines_buf[row_offset + i * 2 + 1].position[2] =
|
|
base_height / 2.0 + v / max * ampli_top;
|
|
lines_buf[row_offset + i * 2].position[2] =
|
|
-base_height / 2.0 - v / max * ampli_bottom;
|
|
}
|
|
});
|
|
|
|
write_row = (write_row + 1) % rows;
|
|
}
|
|
// }}}
|
|
// }}}
|
|
|
|
// Drawing {{{
|
|
let draw_params = glium::DrawParameters {
|
|
line_width: Some(1.0),
|
|
point_size: Some(2.0),
|
|
blend: glium::Blend {
|
|
color: glium::BlendingFunction::Addition {
|
|
source: glium::LinearBlendingFactor::SourceAlpha,
|
|
destination: glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
|
},
|
|
alpha: glium::BlendingFunction::Addition {
|
|
source: glium::LinearBlendingFactor::One,
|
|
destination: glium::LinearBlendingFactor::One,
|
|
},
|
|
constant_value: (1.0, 1.0, 1.0, 1.0),
|
|
},
|
|
..Default::default()
|
|
};
|
|
|
|
framebuffer1.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
|
|
framebuffer2.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
|
|
|
|
let (ref mut fa, ref mut fb) = (&mut framebuffer1, &mut framebuffer2);
|
|
|
|
// Lines {{{
|
|
let uniforms = uniform! {
|
|
perspective_matrix: Into::<[[f32; 4]; 4]>::into(perspective),
|
|
view_matrix: Into::<[[f32; 4]; 4]>::into(view),
|
|
model_matrix: Into::<[[f32; 4]; 4]>::into(model_grid),
|
|
Colors: &lines_colors,
|
|
volume: rolling_volume,
|
|
};
|
|
fa.draw(
|
|
&lines_verts,
|
|
&glium::index::NoIndices(glium::index::PrimitiveType::LinesList),
|
|
&prepass_program,
|
|
&uniforms,
|
|
&draw_params,
|
|
)
|
|
.unwrap();
|
|
// }}}
|
|
|
|
// Points {{{
|
|
let uniforms = uniform! {
|
|
perspective_matrix: Into::<[[f32; 4]; 4]>::into(perspective),
|
|
view_matrix: Into::<[[f32; 4]; 4]>::into(view),
|
|
model_matrix: Into::<[[f32; 4]; 4]>::into(model_grid),
|
|
Colors: &points_colors,
|
|
volume: rolling_volume,
|
|
};
|
|
fa.draw(
|
|
&lines_verts,
|
|
&glium::index::NoIndices(glium::index::PrimitiveType::Points),
|
|
&prepass_program,
|
|
&uniforms,
|
|
&draw_params,
|
|
)
|
|
.unwrap();
|
|
// }}}
|
|
|
|
// Post-Processing {{{
|
|
beat_rolling = (beat_rolling * 0.95f32).max(base_volume);
|
|
|
|
let (fa, fb) = (fb, fa);
|
|
let ua = uniform! {
|
|
previous: tex1.sampled().wrap_function(glium::uniforms::SamplerWrapFunction::Mirror),
|
|
c3: c3_texture.sampled(),
|
|
aspect: aspect,
|
|
time: frame.time,
|
|
volume: volume,
|
|
last_beat: frame.time - last_beat,
|
|
beat: beat_rolling,
|
|
};
|
|
let ub = uniform! {
|
|
previous: tex2.sampled().wrap_function(glium::uniforms::SamplerWrapFunction::Mirror),
|
|
c3: c3_texture.sampled(),
|
|
aspect: aspect,
|
|
time: frame.time,
|
|
volume: volume,
|
|
last_beat: frame.time - last_beat,
|
|
beat: beat_rolling,
|
|
};
|
|
|
|
fa.draw(&quad_verts, &quad_inds, &background_program, &ua, &draw_params)
|
|
.unwrap();
|
|
// Apply alpha
|
|
let (fa, ua, fb, ub) = (fb, ub, fa, ua);
|
|
fa.draw(&quad_verts, &quad_inds, &apply_alpha_program, &ua, &draw_params)
|
|
.unwrap();
|
|
// Do final passes which don't require alpha information anymore
|
|
let (fa, ua, fb, ub) = (fb, ub, fa, ua);
|
|
fa.draw(&quad_verts, &quad_inds, &bokeh_program, &ua, &draw_params)
|
|
.unwrap();
|
|
let (fa, ua, fb, ub) = (fb, ub, fa, ua);
|
|
fa.draw(&quad_verts, &quad_inds, &color_program, &ua, &draw_params)
|
|
.unwrap();
|
|
let (fa, ua, fb, ub) = (fb, ub, fa, ua);
|
|
fa.draw(&quad_verts, &quad_inds, &chromatic_program, &ua, &draw_params)
|
|
.unwrap();
|
|
#[allow(unused_variables)]
|
|
let (fa, ua, fb, ub) = (fb, ub, fa, ua);
|
|
// }}}
|
|
|
|
// Finalizing / Draw to screen {{{
|
|
let target = display.draw();
|
|
let dims = target.get_dimensions();
|
|
target.blit_from_simple_framebuffer(
|
|
&fb,
|
|
&glium::Rect {
|
|
left: 0,
|
|
bottom: 0,
|
|
width: window_width,
|
|
height: window_height,
|
|
},
|
|
&glium::BlitTarget {
|
|
left: 0,
|
|
bottom: 0,
|
|
width: dims.0 as i32,
|
|
height: dims.1 as i32,
|
|
},
|
|
glium::uniforms::MagnifySamplerFilter::Linear,
|
|
);
|
|
target.finish().unwrap();
|
|
// }}}
|
|
// }}}
|
|
|
|
// Events {{{
|
|
let mut closed = false;
|
|
events_loop.poll_events(|ev| match ev {
|
|
glutin::Event::WindowEvent { event, .. } => match event {
|
|
glutin::WindowEvent::CloseRequested => closed = true,
|
|
glutin::WindowEvent::KeyboardInput {
|
|
input:
|
|
glutin::KeyboardInput {
|
|
virtual_keycode: Some(glutin::VirtualKeyCode::Escape),
|
|
..
|
|
},
|
|
..
|
|
} => closed = true,
|
|
_ => (),
|
|
},
|
|
_ => (),
|
|
});
|
|
if closed {
|
|
break 'main;
|
|
}
|
|
// }}}
|
|
|
|
previous_time = frame.time;
|
|
previous_offset = offset;
|
|
|
|
let end = std::time::Instant::now();
|
|
let dur = end - start;
|
|
if dur < frame_time {
|
|
let sleep = frame_time - dur;
|
|
std::thread::sleep(sleep);
|
|
}
|
|
}
|
|
}
|