考虑two programs,它们之间的差异:
$ diff flashes/src/main.rs doesnt_flash/src/main.rs
22,23c22
<
< let mut i = 0;
---
> let mut cursor_poses: Vec<(f64, f64)> = Vec::new();
28c27
< mx = x; my = y;
---
> cursor_poses.push((x,y));
32,33c31,33
< if i == 0 {
< graphics::clear([1.0; 4], g);
---
> graphics::clear([1.0; 4], g);
> for &(x, y) in cursor_poses.iter() {
> draw_cursor_pos([x, y], &c, g);
35,36d34
< draw_cursor_pos([mx, my], &c, g);
< i+=1;
Video demonstration of the two programs.
该程序是一个extremely basic画图程序,只有一个画笔宽度、画笔笔划 colored颜色 、画布大小、不保存等;哦,要停止画画,请将鼠标移出窗口,因为每次你经过窗口,这都算作画画;-)
flashes.rs
不会在每次达到e.render_args()
时绘制每个像素,第一次除外.doesnt_flash.rs
确实会在每次达到e.render_args()
时绘制每个像素.这是两个项目之间唯一的区别.
虽然在这个程序中生成内容不需要很长时间,所以当鼠标在窗口上移动时,可以接受数百次重新生成内容,但这似乎效率低下.理论上,随着越来越多的点被添加到屏幕上,每次迭代gl.draw
次所需的时间越来越长.实际上,在现代硬件上,一次呼叫graphics::ellipse
与一万次呼叫graphics::ellipse
之间的差异并不显著.
我想写的其他程序不会有这样的奢侈,因为它需要更长的时间才能生成结果并放到屏幕上.
在仔细阅读API时,我没有想到什么明显的方法可以"什么都不做".我假设我必须将屏幕更改写入某个缓冲区对象,然后在调用e.render_args()
但不需要更新屏幕时,将GlGraphics
反馈回这个缓冲区对象.
问题是,我似乎找不到这个缓冲区对象:-(
我怎么能"什么都不做"而不让屏幕闪烁?如果我的理论是正确的,我怎么能画一个GlGraphics
缓冲区而不是屏幕,然后把我的缓冲区反馈给屏幕,当我没有任何新的东西要画的时候?
Cargo.toml
[package]
name = "stackoverflow-piston-example"
version = "0.0.0"
authors = ["Fred"]
description = "Note: This program can be used for both of the programs below. Simply use `cargo new` and save either of the below files as `src/main.rs`"
keywords = []
[dependencies]
piston = "0.35.0"
piston2d-opengl_graphics = "0.50.0"
piston2d-graphics = "0.24.0"
piston2d-touch_visualizer = "0.8.0"
pistoncore-sdl2_window = "0.47.0"
doesnt_flash.rs
extern crate piston;
extern crate opengl_graphics;
extern crate graphics;
extern crate touch_visualizer;
extern crate sdl2_window;
use opengl_graphics::{ GlGraphics, OpenGL };
use graphics::{ Context, Graphics };
use piston::input::*;
use piston::event_loop::*;
use sdl2_window::Sdl2Window as AppWindow;
static CURSOR_POS_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
fn main() {
let opengl = OpenGL::V3_2;
let mut window: AppWindow = piston::window::WindowSettings::new("Example for StackOverflow", [600, 600])
.exit_on_esc(true).opengl(opengl).build().unwrap();
let ref mut gl = GlGraphics::new(opengl);
let (mut mx, mut my) = (0., 0.);
let mut cursor_poses: Vec<(f64, f64)> = Vec::new();
let mut events = Events::new(EventSettings::new().lazy(true));
while let Some(e) = events.next(&mut window) {
e.mouse_cursor(|x, y| {
cursor_poses.push((x,y));
});
if let Some(args) = e.render_args() {
gl.draw(args.viewport(), |c, g| {
graphics::clear([1.0; 4], g);
for &(x, y) in cursor_poses.iter() {
draw_cursor_pos([x, y], &c, g);
}
}
);
}
}
}
fn draw_cursor_pos<G: Graphics>(
cursor: [f64; 2],
c: &Context,
g: &mut G,
) {
graphics::ellipse(
CURSOR_POS_COLOR,
graphics::ellipse::circle(cursor[0], cursor[1], 4.0),
c.transform,
g
);
}
flashes.rs
extern crate piston;
extern crate opengl_graphics;
extern crate graphics;
extern crate touch_visualizer;
extern crate sdl2_window;
use opengl_graphics::{ GlGraphics, OpenGL };
use graphics::{ Context, Graphics };
use piston::input::*;
use piston::event_loop::*;
use sdl2_window::Sdl2Window as AppWindow;
static CURSOR_POS_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
fn main() {
let opengl = OpenGL::V3_2;
let mut window: AppWindow = piston::window::WindowSettings::new("Example for StackOverflow", [600, 600])
.exit_on_esc(true).opengl(opengl).build().unwrap();
let ref mut gl = GlGraphics::new(opengl);
let (mut mx, mut my) = (0., 0.);
let mut i = 0;
let mut events = Events::new(EventSettings::new().lazy(true));
while let Some(e) = events.next(&mut window) {
e.mouse_cursor(|x, y| {
mx = x; my = y;
});
if let Some(args) = e.render_args() {
gl.draw(args.viewport(), |c, g| {
if i == 0 {
graphics::clear([1.0; 4], g);
}
draw_cursor_pos([mx, my], &c, g);
i+=1;
}
);
}
}
}
fn draw_cursor_pos<G: Graphics>(
cursor: [f64; 2],
c: &Context,
g: &mut G,
) {
graphics::ellipse(
CURSOR_POS_COLOR,
graphics::ellipse::circle(cursor[0], cursor[1], 4.0),
c.transform,
g
);
}