piston2d-opengl_graphics 0.89.0

An OpenGL 2D back-end for the Piston game engine
Documentation
extern crate graphics;
extern crate opengl_graphics;
extern crate piston;
extern crate sdl2_window;

use opengl_graphics::*;
use piston::event_loop::*;
use piston::input::*;
use piston::window::Window;
use piston::window::WindowSettings;
use piston::Size;
use sdl2_window::Sdl2Window;

use futures::stream::FuturesUnordered;
use futures::StreamExt;

#[tokio::main]
async fn main() {
    let opengl = OpenGL::V3_2;
    let mut window: Sdl2Window = WindowSettings::new("opengl_graphics: async test", [300, 300])
        .exit_on_esc(true)
        .graphics_api(opengl)
        .build()
        .unwrap();

    let mut gl = GlGraphics::new(opengl);
    let mut events = Events::new(EventSettings::new());
    events.set_ups(10);

    let n = 100_000;
    let size = window.size();
    let mut ps: Vec<[f64; 2]> = (0..n)
        .map(|_| {
            [
                rand::random::<f64>() * size.width,
                rand::random::<f64>() * size.height,
            ]
        })
        .collect();
    let mut task: FuturesUnordered<_> = FuturesUnordered::new();
    let mut cursor = [0.0, 0.0];
    let mut time = 0.0;
    while let Some(e) = events.async_next(&mut window).await {
        use graphics::*;

        while let Some(pos) = task.next().await {
            ps.push(pos);
        }

        if let Some(args) = e.render_args() {
            gl.draw(args.viewport(), |c, g| {
                clear([1.0; 4], g);
                for pos in &ps {
                    Rectangle::new([1.0, 0.0, 0.0, 0.05]).draw(
                        [pos[0], pos[1], 2.0, 2.0],
                        &c.draw_state,
                        c.transform,
                        g,
                    );
                }
            });
        }

        if let Some(args) = e.update_args() {
            time += args.dt;
            let size = window.size();
            task.extend(
                ps.into_iter()
                    .map(|pos| update(time, args.dt, cursor, pos, size)),
            );
            ps = vec![];
        }

        if let Some(pos) = e.mouse_cursor_args() {
            cursor = pos;
        }
    }
}

async fn update(time: f64, dt: f64, cursor: [f64; 2], pos: [f64; 2], size: Size) -> [f64; 2] {
    let old_pos = pos;
    let mut pos = pos;

    let dir = [pos[0] - cursor[0], pos[1] - cursor[1]];
    let dir_len = (dir[0] * dir[0] + dir[1] * dir[1]).sqrt();
    let dir_len = if dir_len <= 0.001 { 1.0 } else { dir_len };
    let trigger = if (0.1 * (dir_len + time)).sin() < 0.1 {
        0.1
    } else {
        -0.1
    };
    let speed = 10.0;

    pos[0] += speed
        * dt
        * (2.0 * rand::random::<f64>() - 1.0 + trigger * rand::random::<f64>() * dir[0] / dir_len);
    pos[1] += speed
        * dt
        * (2.0 * rand::random::<f64>() - 1.0 + trigger * rand::random::<f64>() * dir[1] / dir_len);
    if pos[0] <= 0.0 || pos[0] >= size.width {
        pos[0] = old_pos[0];
    }
    if pos[1] <= 0.0 || pos[1] >= size.height {
        pos[1] = old_pos[1];
    }
    pos
}