processing/
lib.rs

1//! # processing-rs
2//!
3//! `processing-rs` is a crate that is designed to make graphics
4//! programming as easy in Rust as it is in the popular Processing
5//! environment, without sacrificing performance or easy access to
6//! other parts of your system. It achieves this by essentially being
7//! a convienence layer built on top of glium and glutin/glfw (either
8//! can be chosen depending on your preference). It mostly mimics Processing,
9//! but diverges in a few areas to either accomodate Rust's and glium's safety
10//! features or to incorporate some ideas from libCinder and openFrameworks. For
11//! instance, there are now `setup` and `draw` loops in `processing-rs`. This is
12//! intended to enable a more flexible and modular workflow for graphics. In addition,
13//! since `processing-rs` is essentialy a thin wrapper, you can use glium, glutin, and
14//! raw OpenGL calls as you see fit. They should usually blend nicely with the
15//! `processing-rs` calls and allow for more opportunities to create fun and
16//! interesting displays.
17//!
18//! Typical usage follows a common pattern:
19//!
20//!     1. Open a screen with processing::Screen::new(). This will return a 
21//!        Screen struct, which is the central struct for coordinating draw calls,
22//!        managing shaders, and maintaining render state.
23//!
24//!     2. Pre-define a few shapes. This allows caching shape data on the CPU and GPU,
25//!        giving some marginal speed boosts and allowing the possibility to store
26//!        shapes in collections, such as Vectors. All shapes (Rect, Ellipse, etc.) in
27//!        this crate implement the Shape trait, which defines a common interface for
28//!        entities that can be drawn to a screen in a meaningful way.
29//!
30//!     3. Draw the shapes to the screen with screen.draw(). This is also where you will
31//!        want to use commands like screen.fill() and screen.stroke() to change the
32//!        colors of objects.
33//!
34//!     4. For any pattern drawn, you will also need to flip the framebuffers, so that
35//!        the pattern is synchronized with your monitor. This is achieved by
36//!        screen.reveal().
37//!
38//!     5. Use commands like screen.key_press() to get input from users, if needed.
39//!
40//!     6. Have fun! :-)
41//!
42//! Basically, all commands follow the same call conventions as those from Processing,
43//! so you can also use the Processing reference as additional documentation and for
44//! some basic examples of what you can do.
45//!
46//! Additionally, `processing-rs` has a number of features that are intended to make
47//! it useful for psychological research, including color vision, material perception,
48//! motion, etc. For example, it tries to enable a 10-bit framebuffer if possible, for
49//! increased color fidelity, which is important in most color vision research. Besides
50//! this, it also aims to make sure that frame draws are as precisely synchronized with 
51//! the monitor refresh as possible. This works better with glutin than with glfw, and 
52//! on Mac, a few Objective-C functions are called to give the program elevated status
53//! for resources and to disable AppNap and such things while the program is running
54//! (code taken from the helpful PsychToolbox). In addition, when the crate is built
55//! on a Mac, it will also compile a C library (called `libpri`, short for "priority
56//! library") that asks the operating system for some additional priorities. The crate
57//! will automatically call the library throguh the C FFI at screen initialization. It
58//! shouldn't interfere with normal operation of the operating system, so you can
59//! probably just accept the default behaviour. With all of this, combined with a change
60//! to a setting on Mac that allows one to quit Finder, one can achieve slightly better 
61//! synchronization than PsychToolbox on Mac, satisfying Psychtoolbox's requirements for
62//! good frame synchronization. However, this has only been tested on a Mac laptop with
63//! 10.13.3 and an Intel graphics card.
64
65#![allow(dead_code)]
66#![allow(unused_mut)]
67#![allow(deprecated)]
68
69#[macro_use]
70extern crate glium;
71extern crate gl;
72extern crate nalgebra;
73//extern crate rand;
74extern crate image as image_ext;
75extern crate owning_ref;
76
77#[cfg(target_os = "macos")]
78#[macro_use]
79extern crate objc;
80#[cfg(target_os = "macos")]
81extern crate cocoa;
82#[cfg(target_os = "macos")]
83use cocoa::foundation::{NSProcessInfo, NSString};
84#[cfg(target_os = "macos")]
85use cocoa::base::nil;
86
87use nalgebra::{Matrix4, Vector3, Unit};
88
89#[cfg(not(feature = "glfw"))]
90pub use glium::*;
91#[cfg(not(feature = "glfw"))]
92pub mod screen;
93
94#[cfg(feature = "glfw")]
95extern crate glfw;
96#[cfg(feature = "glfw")]
97pub mod glfwp5;
98#[cfg(feature = "glfw")]
99pub use glfwp5::screen;
100
101#[macro_use]
102pub mod shaders;
103pub mod color;
104pub mod shapes;
105pub mod textures;
106pub mod framebuffers;
107pub mod transform;
108pub mod rendering;
109pub mod image;
110pub mod errors;
111
112#[cfg(not(feature = "glfw"))]
113pub mod environment;
114#[cfg(feature = "glfw")]
115pub use glfwp5::environment;
116
117#[cfg(not(feature = "glfw"))]
118pub mod input;
119#[cfg(feature = "glfw")]
120pub use glfwp5::input;
121
122#[cfg(not(feature = "glfw"))]
123pub mod constants;
124#[cfg(feature = "glfw")]
125pub use glfwp5::constants;
126
127pub use constants::{Key, MouseButton};
128
129pub use image::load_image;
130
131#[derive(Debug)]
132pub struct GLmatStruct {
133    pub curr_matrix: Matrix4<f32>,
134    matrix_stack: Vec<Matrix4<f32>>,
135}
136
137pub struct FBtexs {
138    fbtex: glium::texture::Texture2d,
139    depthtexture: glium::texture::DepthTexture2d,
140}
141
142#[derive(Copy, Clone)]
143pub struct DFBFDVertex {
144    position: [f32; 2],
145    texcoord: [f32; 2],
146}
147
148implement_vertex!(DFBFDVertex, position, texcoord);
149
150#[cfg(not(feature = "glfw"))]
151enum ScreenType {
152    Window(glium::Display),
153    Headless(glium::HeadlessRenderer),
154}
155
156/// This is essentially the central struct of `processing-rs`. It not only contains the
157/// the display window returned by glutin, but it also has a number of elements that
158/// maintain the render state and that manage a framebuffer for increased color
159/// fidelity. Its internal elements are mostly private and an instance of a Screen
160/// struct should be interacted with through the public functions provided in other
161/// modules, such as the shapes, environment, or textures modules.
162#[cfg(not(feature = "glfw"))]
163pub struct Screen<'a> {
164    fbtexture: glium::texture::Texture2d,
165    fb_shape_buffer: glium::VertexBuffer<DFBFDVertex>,
166    fb_index_buffer: glium::index::IndexBuffer<u16>,
167    fbo: owning_ref::OwningHandle<Box<FBtexs>, Box<glium::framebuffer::SimpleFrameBuffer<'a>>>,
168    display: ScreenType,
169    events_loop: glutin::EventsLoop,
170    draw_params: glium::draw_parameters::DrawParameters<'a>,
171    pub matrices: GLmatStruct,
172    bg_col: Vec<f32>,
173    fill_stuff: bool,
174    fill_col: Vec<f32>,
175    stroke_stuff: bool,
176    stroke_col: Vec<f32>,
177    tint_stuff: bool,
178    tint_col: Vec<f32>,
179    shader_bank: Vec<glium::program::Program>,
180    draw_texture: bool,
181    aspect_ratio: f32,
182    preserve_aspect_ratio: bool,
183    fb_size: Vec<u32>,
184    stroke_weight: f32,
185    font_face: String,
186    text_size: f32,
187    height: u32,
188    width: u32,
189    left: f32,
190    right: f32,
191    top: f32,
192    bottom: f32,
193    c_mode: String,
194    title: String,
195    ellipse_mode: String,
196    rect_mode: String,
197    shape_mode: String,
198    image_mode: String,
199    frame_rate: isize,
200    frame_count: isize,
201    fonts_initialized: bool,
202    curr_shader: usize,
203    curr_cursor: glium::glutin::MouseCursor,
204    wrap: glium::uniforms::SamplerWrapFunction,
205    alternate_shader: usize,
206    curr_texture: Option<glium::texture::Texture2d>,
207    using_alternate_shader: bool,
208    glsl_version: String,
209    drew_points: bool,
210    keypressed: Option<glutin::VirtualKeyCode>,
211    mousepressed: Option<glutin::MouseButton>,
212    mousereleased: Option<glutin::MouseButton>,
213    mousepos: (f64, f64),
214    headless: bool,
215}
216
217#[cfg(feature = "glfw")]
218use std::sync::mpsc::Receiver;
219#[cfg(feature = "glfw")]
220use glfwp5::backend::Display;
221#[cfg(feature = "glfw")]
222enum ScreenType {
223    Window(Display),
224    Headless(Display),
225}
226
227/// This is essentially the central struct of `processing-rs`. It not only contains the
228/// the display window returned by glutin, but it also has a number of elements that
229/// maintain the render state and that manage a framebuffer for increased color
230/// fidelity. Its internal elements are mostly private and an instance of a Screen
231/// struct should be interacted with through the public functions provided in other
232/// modules, such as the shapes, environment, or textures modules.
233#[cfg(feature = "glfw")]
234pub struct Screen<'a> {
235    fbtexture: glium::texture::Texture2d,
236    fb_shape_buffer: glium::VertexBuffer<DFBFDVertex>,
237    fb_index_buffer: glium::index::IndexBuffer<u16>,
238    fbo: owning_ref::OwningHandle<Box<FBtexs>, Box<glium::framebuffer::SimpleFrameBuffer<'a>>>,
239    display: ScreenType,
240    glfw: glfw::Glfw,
241    events_loop: Receiver<(f64, glfw::WindowEvent)>,
242    draw_params: glium::draw_parameters::DrawParameters<'a>,
243    pub matrices: GLmatStruct,
244    bg_col: Vec<f32>,
245    fill_stuff: bool,
246    fill_col: Vec<f32>,
247    stroke_stuff: bool,
248    stroke_col: Vec<f32>,
249    tint_stuff: bool,
250    tint_col: Vec<f32>,
251    shader_bank: Vec<glium::program::Program>,
252    draw_texture: bool,
253    aspect_ratio: f32,
254    preserve_aspect_ratio: bool,
255    fb_size: Vec<u32>,
256    stroke_weight: f32,
257    font_face: String,
258    text_size: f32,
259    height: u32,
260    width: u32,
261    left: f32,
262    right: f32,
263    top: f32,
264    bottom: f32,
265    c_mode: String,
266    title: String,
267    ellipse_mode: String,
268    rect_mode: String,
269    shape_mode: String,
270    image_mode: String,
271    frame_rate: isize,
272    frame_count: isize,
273    fonts_initialized: bool,
274    curr_shader: usize,
275    curr_cursor: glfw::StandardCursor,
276    wrap: glium::uniforms::SamplerWrapFunction,
277    alternate_shader: usize,
278    curr_texture: Option<glium::texture::Texture2d>,
279    using_alternate_shader: bool,
280    glsl_version: String,
281    drew_points: bool,
282    keypressed: Option<glfw::Key>,
283    mousepressed: Option<glfw::MouseButton>,
284    mousereleased: Option<glfw::MouseButton>,
285    mousepos: (f64, f64),
286    headless: bool,
287}
288
289// #[derive(Default)]
290// struct vertexStruct {
291// shapeVertices: Vec<f32>,
292// textureCoords: Vec<f32>,
293// vertexStride: isize,
294// nVertices: isize,
295// shapeType: u32,
296// }
297
298#[cfg(target_os = "macos")]
299#[link(name = "pri")]
300extern "C" {
301    fn setMaxPriority();
302}
303
304#[cfg(target_os = "macos")]
305fn mac_priority() {
306    // Prevent display from sleeping/powering down, prevent system
307    // from sleeping, prevent sudden termination for any reason:
308    let NSActivityIdleDisplaySleepDisabled = (1u64 << 40);
309    let NSActivityIdleSystemSleepDisabled = (1u64 << 20);
310    let NSActivitySuddenTerminationDisabled = (1u64 << 14);
311    let NSActivityAutomaticTerminationDisabled = (1u64 << 15);
312    let NSActivityUserInitiated = (0x00FFFFFFu64 | NSActivityIdleSystemSleepDisabled);
313    let NSActivityLatencyCritical = 0xFF00000000u64;
314
315    let options = NSActivityIdleDisplaySleepDisabled | NSActivityIdleSystemSleepDisabled |
316        NSActivitySuddenTerminationDisabled |
317        NSActivityAutomaticTerminationDisabled;
318    let options = options | NSActivityUserInitiated | NSActivityLatencyCritical;
319
320    unsafe {
321        let pinfo = NSProcessInfo::processInfo(nil);
322        let s = NSString::alloc(nil).init_str("timing");
323        msg_send![pinfo, beginActivityWithOptions:options reason:s];
324
325        setMaxPriority();
326    }
327}