From 68c3728dae3408f6449c78882e36defd2978b716 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 13 Jun 2016 23:50:48 -0400 Subject: exuberantplasma: simple new GLSL hack --- Makefile | 2 +- README.txt | 2 + configs/exuberantplasma.xml | 22 ++++++++ doc/exuberantplasma.6.md | 77 +++++++++++++++++++++++++ src/bin/exuberantplasma.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 configs/exuberantplasma.xml create mode 100644 doc/exuberantplasma.6.md create mode 100644 src/bin/exuberantplasma.rs diff --git a/Makefile b/Makefile index 481ccc3..458c3de 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # This Makefile is self-documenting (via the 'help' target) # see: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html -HACKS=exuberantbovines +HACKS=exuberantbovines exuberantplasma CARGO ?= cargo CARGO_OPTS ?= diff --git a/README.txt b/README.txt index f5003ee..4f33caa 100644 --- a/README.txt +++ b/README.txt @@ -56,6 +56,8 @@ You'll need to create at least three files with the same base name ("$HACK"): - an XML config file (configs/$HACK.xml) - a manpage in Markdown format (doc/$HACK.6.md) +Then just add your HACK to the list in Makefile. + See also XScreensaver's "Writing new XScreenSaver modules" https://github.com/Zygo/xscreensaver/blob/master2/README.hacking diff --git a/configs/exuberantplasma.xml b/configs/exuberantplasma.xml new file mode 100644 index 0000000..9034255 --- /dev/null +++ b/configs/exuberantplasma.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + <_description> +A port of classic GLSL plasma effect to Rust. + +A good template for basic GLSL/shader screensavers. + + diff --git a/doc/exuberantplasma.6.md b/doc/exuberantplasma.6.md new file mode 100644 index 0000000..a04be58 --- /dev/null +++ b/doc/exuberantplasma.6.md @@ -0,0 +1,77 @@ +% exuberantplasma(6) | XScreenSaver manual + +NAME +==== + +**exuberantplasma** — classic GLSL screensaver + +SYNOPSIS +======== + +| **exuberantplasma** \[**-h**|**--help**] \[**--window-id** _id_] \[**--root**] +| \[**--wireframe**] \[**--fps**] + +DESCRIPTION +=========== + +This is a "hack" for the XScreensaver screen locker. It shows a wavey color +background. + +OPTIONS +========= + +_exuberantplasma_ accepts the following options. Note that some long options (like +**root** and **window-id** can be passed with either a single dash (**-root**) +or a double-dash (**--root**) for backwards compatibility with XScreensaver. + +-h, --help + +: Prints brief usage information. + +--wireframe + +: Render in wireframe instead of solid. (UNIMPLEMENTED) + +--fps + +: Display the current frame rate, CPU load, and polygon count. (UNIMPLEMENTED) + + +FILES +===== + +*~/.xscreensaver* + +: Per-user configuration file. If there isn't a line for this hack in the + file, xscreensaver-demo won't find or run this hack. + +*/usr/share/xscreensaver/config/exuberantplasma.xml* + +: Configuration options for this hack + +ENVIRONMENT +=========== + +**XSCREENSAVER_WINDOW** + +: Optional ID number of the X window to draw into. + +Note that **XENVIRONMENT** and **DISPLAY** are *not* implemented. + +BUGS +==== + +A lot of features (like fps, root-window-finding, wireframe, etc) aren't +implemented yet. + +See GitHub Issues: + +AUTHOR +====== + +Bryan Newbold + +SEE ALSO +======== + +**xscreensaver(1)**, **xscreensaver-demo(1)** diff --git a/src/bin/exuberantplasma.rs b/src/bin/exuberantplasma.rs new file mode 100644 index 0000000..5d49a56 --- /dev/null +++ b/src/bin/exuberantplasma.rs @@ -0,0 +1,134 @@ + +extern crate exuberant; +extern crate getopts; + +#[macro_use] +extern crate glium; + +use exuberant::ExuberantHack; +use getopts::Options; +use glium::Surface; + +#[derive(Copy, Clone)] +struct Vertex { + position: [f32; 2], +} +implement_vertex!(Vertex, position); + +struct ExuberantPlasma { + display: glium::Display, + program: glium::Program, +} + +impl ExuberantPlasma { + + pub fn new(display: glium::Display) -> ExuberantPlasma { + + let vertex_shader_src = r#" #version 140 + + in vec2 position; + out vec2 v_coords; + + void main() { + v_coords = position; + gl_Position = vec4(position, 0.0, 1.0); + } + "#; + + // This fragment shader verbatim from: + // http://www.bidouille.org/prog/plasma + let fragment_shader_src = r#" #version 140 + + precision mediump float; + #define PI 3.1415926535897932384626433832795 + + uniform float u_time; + uniform vec2 u_k; + varying vec2 v_coords; + + void main() { + float v = 0.0; + vec2 c = v_coords * u_k - u_k/2.0; + v += sin((c.x+u_time)); + v += sin((c.y+u_time)/2.0); + v += sin((c.x+c.y+u_time)/2.0); + c += u_k/2.0 * vec2(sin(u_time/3.0), cos(u_time/2.0)); + v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+u_time); + v = v/2.0; + vec3 col = vec3(1, sin(PI*v), cos(PI*v)); + gl_FragColor = vec4(col*.5 + .5, 1); + } + "#; + + + let program = glium::Program::from_source( + &display, + vertex_shader_src, + fragment_shader_src, + None).unwrap(); + + ExuberantPlasma { + display: display, + program: program, + } + } +} + +impl ExuberantHack for ExuberantPlasma { + + fn draw_frame(&mut self, t: f64) -> Result<(), String> { + + let vertex1 = Vertex { position: [-1.0, -1.0] }; + let vertex2 = Vertex { position: [ 3.0, -1.0] }; + let vertex3 = Vertex { position: [-1.0, 3.0] }; + let shape = vec![vertex1, vertex2, vertex3]; + + let vertex_buffer = glium::VertexBuffer::new(&self.display, &shape).unwrap(); + + let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList); + + // Drawing Pipeline + let mut target = self.display.draw(); + + let uniforms = uniform! { + u_time: (t % (12.0 * 3.141592)) as f32, + u_k: [10.0 as f32, 10.0 as f32], + }; + + // Set black background + target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0); + + let params = glium::DrawParameters { + .. Default::default() + }; + + target.draw(&vertex_buffer, + &indices, + &self.program, + &uniforms, + ¶ms).unwrap(); + + target.finish().or(Err("Failure rendering".to_string())) + } + + fn get_display(&self) -> &glium::Display { + &self.display + } +} + +fn main() { + + let mut opts = Options::new(); + opts.optopt("c", "count", "how many cows? (1 to 9) (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 = ExuberantPlasma::new(dislpay); + + // Here is where you would configure the hack based on command line options + + // Ok, actually run it (loops forever) + exuberant::run(&mut hack, &conf); +} -- cgit v1.2.3