From 4fb57de0201eaecdafffdcc285e7dc3ef9d4f6d8 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 13 Jun 2016 23:09:21 -0400 Subject: refactor into library --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/bin/cow_model/mod.rs | 1 + src/bin/exuberantbovines.rs | 214 ++++++++++++++++++++++---------------------- src/lib.rs | 59 +++++++++--- 5 files changed, 161 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31505f1..5897394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,5 @@ [root] -name = "exuberantbovines" +name = "exuberant" version = "0.1.0" dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 19775a6..5aa372f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "exuberantbovines" +name = "exuberant" version = "0.1.0" authors = ["bnewbold "] diff --git a/src/bin/cow_model/mod.rs b/src/bin/cow_model/mod.rs index c0fdb01..41e8aab 100644 --- a/src/bin/cow_model/mod.rs +++ b/src/bin/cow_model/mod.rs @@ -7,6 +7,7 @@ mod cow_horns; mod cow_tail; mod cow_udder; +pub use self::cow_vertex::Vertex; pub use self::cow_face::COW_FACE_VERTICES; pub use self::cow_hide::COW_HIDE_VERTICES; pub use self::cow_hoofs::COW_HOOFS_VERTICES; diff --git a/src/bin/exuberantbovines.rs b/src/bin/exuberantbovines.rs index 1fdf7a0..799fff5 100644 --- a/src/bin/exuberantbovines.rs +++ b/src/bin/exuberantbovines.rs @@ -1,109 +1,119 @@ -extern crate exuberantbovines; +extern crate exuberant; extern crate getopts; #[macro_use] extern crate glium; -use exuberantbovines::{generic_main, util}; +use exuberant::ExuberantHack; use getopts::Options; -use glium::glutin::os::unix::WindowBuilderExt; +use glium::Surface; mod cow_model; - -fn run(window_id: Option) { - - use glium::{DisplayBuild, Surface}; - - let mut t: f32 = 0.0; - let mut z: f32; - - let win_builder: glium::glutin::WindowBuilder = match window_id { - Some(id) => - glium::glutin::WindowBuilder::new() - .from_existing_window(id), - None => glium::glutin::WindowBuilder::new() - .with_title(format!("Exuberant Cow!")) - .with_depth_buffer(24), - }; - let display = win_builder.build_glium().unwrap(); - - let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList); - - let face_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_FACE_VERTICES).unwrap(); - let hide_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_HIDE_VERTICES).unwrap(); - let hoofs_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_HOOFS_VERTICES).unwrap(); - let horns_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_HORNS_VERTICES).unwrap(); - let tail_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_TAIL_VERTICES).unwrap(); - let udder_vertices = glium::VertexBuffer::new( - &display, &cow_model::COW_UDDER_VERTICES).unwrap(); - - let vertex_shader_src = r#" - #version 140 - - uniform mat4 perspective; - uniform mat4 view; - uniform mat4 model; - - in vec3 position; - in vec3 normal; - - out vec3 v_normal; - out vec3 v_position; - - void main() { - mat4 modelview = view * model; - v_normal = transpose(inverse(mat3(modelview))) * normal; - gl_Position = perspective * modelview * vec4(position, 1.0); - v_position = gl_Position.xyz / gl_Position.w; - } - "#; - let fragment_shader_src = r#" - #version 140 +struct ExuberantBovines { + t: f64, + display: glium::Display, + program: glium::Program, + model_vertices: Vec>, +} + +impl ExuberantBovines { + + pub fn new(display: glium::Display) -> ExuberantBovines { + + let face_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_FACE_VERTICES).unwrap(); + let hide_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_HIDE_VERTICES).unwrap(); + let hoofs_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_HOOFS_VERTICES).unwrap(); + let horns_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_HORNS_VERTICES).unwrap(); + let tail_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_TAIL_VERTICES).unwrap(); + let udder_vertices = glium::VertexBuffer::new( + &display, &cow_model::COW_UDDER_VERTICES).unwrap(); + + let vertex_shader_src = r#" + #version 140 + + uniform mat4 perspective; + uniform mat4 view; + uniform mat4 model; + + in vec3 position; + in vec3 normal; + + out vec3 v_normal; + out vec3 v_position; + + void main() { + mat4 modelview = view * model; + v_normal = transpose(inverse(mat3(modelview))) * normal; + gl_Position = perspective * modelview * vec4(position, 1.0); + v_position = gl_Position.xyz / gl_Position.w; + } + "#; - uniform vec3 u_light; + let fragment_shader_src = r#" + #version 140 - in vec3 v_normal; - in vec3 v_position; + uniform vec3 u_light; - out vec4 color; + in vec3 v_normal; + in vec3 v_position; - const vec3 ambient_color = vec3(0.63, 0.43, 0.36); - const vec3 diffuse_color = vec3(0.5, 0.5, 0.5); - const vec3 specular_color = vec3(0.0, 0.0, 0.0); + out vec4 color; - void main() { - float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0); + const vec3 ambient_color = vec3(0.63, 0.43, 0.36); + const vec3 diffuse_color = vec3(0.5, 0.5, 0.5); + const vec3 specular_color = vec3(0.0, 0.0, 0.0); - vec3 camera_dir = normalize(-v_position); - vec3 half_direction = normalize(normalize(u_light) + camera_dir); - float specular = pow(max(dot(half_direction, normalize(v_normal)), 0.0), 16.); - color = vec4(ambient_color + - diffuse * diffuse_color + - specular * specular_color, 1.0); - } - "#; + void main() { + float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0); + + vec3 camera_dir = normalize(-v_position); + vec3 half_direction = normalize(normalize(u_light) + camera_dir); + float specular = pow(max(dot(half_direction, normalize(v_normal)), 0.0), 16.); + color = vec4(ambient_color + + diffuse * diffuse_color + + specular * specular_color, 1.0); + } + "#; + + + let program = glium::Program::from_source( + &display, + vertex_shader_src, + fragment_shader_src, + None).unwrap(); + + return ExuberantBovines { + display: display, + program: program, + t: 0.0, + model_vertices: vec![face_vertices, + hide_vertices, + hoofs_vertices, + horns_vertices, + tail_vertices, + udder_vertices], + }; + } +} +impl ExuberantHack for ExuberantBovines { - let program = glium::Program::from_source( - &display, - vertex_shader_src, - fragment_shader_src, - None).unwrap(); + fn draw_frame(&mut self) -> Result<(), String> { - loop { + let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList); - t += 0.03; - z = 0.5 * t.sin(); + self.t += 0.03; + let z: f32 = 0.5 * self.t.sin() as f32; // Drawing Pipeline - let mut target = display.draw(); + let mut target = self.display.draw(); let (width, height) = target.get_dimensions(); let aspect_ratio = height as f32 / width as f32; @@ -124,7 +134,7 @@ fn run(window_id: Option) { let light = [-1.0, 0.4, 0.9f32]; - let view = util::view_matrix(&[2.0, -1.0, 1.0], &[-2.0, 1.0, 1.0], &[0.0, 1.0, 0.0]); + let view = exuberant::util::view_matrix(&[2.0, -1.0, 1.0], &[-2.0, 1.0, 1.0], &[0.0, 1.0, 0.0]); let uniforms = uniform! { model: [ [ 0.3, 0.0, 0.0, 0.0 ], @@ -150,42 +160,36 @@ fn run(window_id: Option) { .. Default::default() }; - for part_vertices in vec![&face_vertices, - &hide_vertices, - &hoofs_vertices, - &horns_vertices, - &tail_vertices, - &udder_vertices] { + for part_vertices in &self.model_vertices { target.draw(part_vertices, &indices, - &program, + &self.program, &uniforms, ¶ms).unwrap(); } - target.finish().unwrap(); - - for ev in display.poll_events() { - match ev { - glium::glutin::Event::Closed => return, - _ => () - } - } - // XXX: sleep here for 10ms + target.finish().or(Err("Failure rendering".to_string())) } + fn get_display(&self) -> &glium::Display { + &self.display + } } fn main() { let mut opts = Options::new(); - opts.optflag("", "wire", "wireframe mode (IGNORED)"); opts.optopt("c", "count", "how many cows? (1 to 9) (IGNORED)", "NUM"); - opts.optopt("", "delay", "inter-frame delay (0 to 100000) (IGNORED)", "NUM"); opts.optopt("s", "speed", "how fast? ratio, with 1.0 as normal (IGNORED)", "NUM"); + opts.optflag("", "wireframe", "wireframe mode (IGNORED)"); + + let conf = exuberant::main_helper(opts); + let dislpay = exuberant::make_display(&conf); + let mut hack = ExuberantBovines::new(dislpay); - let (_, window_id) = generic_main(opts); - run(window_id) + // Here is where you would configure the hack based on command line options + // Ok, actually run it (loops forever) + exuberant::run(&mut hack, &conf); } diff --git a/src/lib.rs b/src/lib.rs index c0f537d..c73fc0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,21 +6,45 @@ extern crate image; extern crate getopts; use std::env; -use std::u64; use std::process::exit; use getopts::{Options, Matches}; use glium::glutin::os::unix::WindowBuilderExt; +use glium::{DisplayBuild, Display}; pub mod util; -fn print_usage(program: &str, opts: Options) { +pub trait ExuberantHack { + fn draw_frame(&mut self) -> Result<(), String>; + fn get_display(&self) -> &Display; +} + +/// Prints usage/help info for an individual hack +pub fn print_usage(opts: &Options) { + let args: Vec = env::args().collect(); + let program = args[0].clone(); let brief = format!("Usage: {} [options]", program); print!("{}", opts.usage(&brief)); } -pub fn generic_main(mut opts: Options) -> (Matches, Option) { +/// Executes a hack +pub fn run(hack: &mut ExuberantHack, conf: &Matches) { + + loop { + hack.draw_frame().ok(); + for ev in hack.get_display().poll_events() { + match ev { + glium::glutin::Event::Closed => return, + _ => () + } + } + // XXX: sleep here for 10ms + } +} + +/// Adds and parses most command-line options. +/// This function handles all the generic stuff, like --window-id and --help. +pub fn main_helper(mut opts: Options) -> Matches { let args: Vec = env::args().collect(); - let program = args[0].clone(); // Turn, eg, "-root" into "--root" let args = util::convert_xscreensaver_args(args); @@ -29,13 +53,14 @@ pub fn generic_main(mut opts: Options) -> (Matches, Option) { opts.optflag("h", "help", "print this help menu"); opts.optflag("", "window", "run in a window (IGNORED)"); opts.optflag("", "root", "run in root window (IGNORED)"); - opts.optflag("", "fps", "show frames per second (IGNORED)"); opts.optopt("", "window-id", "X window id number", "NUM"); + opts.optflag("", "fps", "show frames per second (IGNORED)"); + opts.optopt("", "delay", "inter-frame delay (0 to 100000) (IGNORED)", "NUM"); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(f) => { - print_usage(&program, opts); + print_usage(&opts); println!(""); println!("{}", f.to_string()); exit(-1); @@ -43,14 +68,19 @@ pub fn generic_main(mut opts: Options) -> (Matches, Option) { }; if matches.opt_present("help") { - print_usage(&program, opts); + print_usage(&opts); exit(0); } + matches +} + +pub fn make_display(conf: &Matches) -> glium::Display { + // if no "--window-id", try environment variable (arg has priority though) let window_id_string: Option = - matches.opt_str("window-id") - .or(env::var("XSCREENSAVER_WINDOW").ok()); + conf.opt_str("window-id") + .or(env::var("XSCREENSAVER_WINDOW").ok()); let window_id = window_id_string.map(|id| match util::dechex2u64(&id) { Ok(y) => y, @@ -63,5 +93,14 @@ pub fn generic_main(mut opts: Options) -> (Matches, Option) { println!("Drawing on existing X window: 0x{:07X}", window_id.unwrap()); } - (matches, window_id) + let win_builder: glium::glutin::WindowBuilder = match window_id { + Some(id) => + glium::glutin::WindowBuilder::new() + .from_existing_window(id), + None => glium::glutin::WindowBuilder::new() + .with_title(format!("Exuberant Cow!")) + .with_depth_buffer(24), + }; + let display = win_builder.build_glium().unwrap(); + display } -- cgit v1.2.3