importing and simplifying glium teapot example

This commit is contained in:
Dustin Carlino 2019-01-22 12:22:50 -08:00
parent 08db3bf27f
commit 87b885fcd7
7 changed files with 2430 additions and 163 deletions

View File

@ -14,4 +14,3 @@
- trailer
- show common parts of routes in A/B, point of divergence
- "Two parallel universes sit at your fingertips, and with the flick of a key, you can glide between the two. Buses jumping past traffic in one world, snarly traffic jam in the other. An A/B test revealing what currently is, and what could be, compared meticulously and deterministically. A/B Street -- which world do you prefer?"

View File

@ -62,3 +62,9 @@
- draw as one polygon when fixed
- dashed thickness is way off
- last dash shouldnt appear?
## Switch to OpenGL (for speed)
- simpler geometry, with color per object
- render text
- switch ezgui (could make it generic and have piston or glium support, but maybe not worth it)

View File

@ -5,7 +5,7 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
edition = "2018"
[dependencies]
gfx = "0.17.1"
gfx_device_gl = "0.15.3"
gfx_window_glutin = "0.26.0"
glutin = "0.18.0"
genmesh = "0.6.2"
glium = "0.23.0"
glutin = "0.19.0"
obj = { version = "0.9", features = ["genmesh"] }

170
tmp_gfx/src/camera.rs Normal file
View File

@ -0,0 +1,170 @@
use glutin;
pub struct CameraState {
aspect_ratio: f32,
position: (f32, f32, f32),
direction: (f32, f32, f32),
moving_up: bool,
moving_left: bool,
moving_down: bool,
moving_right: bool,
moving_forward: bool,
moving_backward: bool,
}
impl CameraState {
pub fn new() -> CameraState {
CameraState {
aspect_ratio: 1024.0 / 768.0,
position: (0.1, 0.1, 1.0),
direction: (0.0, 0.0, -1.0),
moving_up: false,
moving_left: false,
moving_down: false,
moving_right: false,
moving_forward: false,
moving_backward: false,
}
}
pub fn get_perspective(&self) -> [[f32; 4]; 4] {
let fov: f32 = 3.141592 / 2.0;
let zfar = 1024.0;
let znear = 0.1;
let f = 1.0 / (fov / 2.0).tan();
// note: remember that this is column-major, so the lines of code are actually columns
[
[f / self.aspect_ratio, 0.0, 0.0, 0.0],
[0.0, f, 0.0, 0.0],
[0.0, 0.0, (zfar + znear) / (zfar - znear), 1.0],
[0.0, 0.0, -(2.0 * zfar * znear) / (zfar - znear), 0.0],
]
}
pub fn get_view(&self) -> [[f32; 4]; 4] {
let f = {
let f = self.direction;
let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
let len = len.sqrt();
(f.0 / len, f.1 / len, f.2 / len)
};
let up = (0.0, 1.0, 0.0);
let s = (
f.1 * up.2 - f.2 * up.1,
f.2 * up.0 - f.0 * up.2,
f.0 * up.1 - f.1 * up.0,
);
let s_norm = {
let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
let len = len.sqrt();
(s.0 / len, s.1 / len, s.2 / len)
};
let u = (
s_norm.1 * f.2 - s_norm.2 * f.1,
s_norm.2 * f.0 - s_norm.0 * f.2,
s_norm.0 * f.1 - s_norm.1 * f.0,
);
let p = (
-self.position.0 * s.0 - self.position.1 * s.1 - self.position.2 * s.2,
-self.position.0 * u.0 - self.position.1 * u.1 - self.position.2 * u.2,
-self.position.0 * f.0 - self.position.1 * f.1 - self.position.2 * f.2,
);
// note: remember that this is column-major, so the lines of code are actually columns
[
[s_norm.0, u.0, f.0, 0.0],
[s_norm.1, u.1, f.1, 0.0],
[s_norm.2, u.2, f.2, 0.0],
[p.0, p.1, p.2, 1.0],
]
}
fn update(&mut self) {
let f = {
let f = self.direction;
let len = f.0 * f.0 + f.1 * f.1 + f.2 * f.2;
let len = len.sqrt();
(f.0 / len, f.1 / len, f.2 / len)
};
let up = (0.0, 1.0, 0.0);
let s = (
f.1 * up.2 - f.2 * up.1,
f.2 * up.0 - f.0 * up.2,
f.0 * up.1 - f.1 * up.0,
);
let s = {
let len = s.0 * s.0 + s.1 * s.1 + s.2 * s.2;
let len = len.sqrt();
(s.0 / len, s.1 / len, s.2 / len)
};
let u = (
s.1 * f.2 - s.2 * f.1,
s.2 * f.0 - s.0 * f.2,
s.0 * f.1 - s.1 * f.0,
);
let speed = 0.1;
if self.moving_up {
self.position.0 += u.0 * speed;
self.position.1 += u.1 * speed;
self.position.2 += u.2 * speed;
}
if self.moving_left {
self.position.0 -= s.0 * speed;
self.position.1 -= s.1 * speed;
self.position.2 -= s.2 * speed;
}
if self.moving_down {
self.position.0 -= u.0 * speed;
self.position.1 -= u.1 * speed;
self.position.2 -= u.2 * speed;
}
if self.moving_right {
self.position.0 += s.0 * speed;
self.position.1 += s.1 * speed;
self.position.2 += s.2 * speed;
}
if self.moving_forward {
self.position.0 += f.0 * speed;
self.position.1 += f.1 * speed;
self.position.2 += f.2 * speed;
}
if self.moving_backward {
self.position.0 -= f.0 * speed;
self.position.1 -= f.1 * speed;
self.position.2 -= f.2 * speed;
}
}
pub fn process_input(&mut self, input: glutin::KeyboardInput) {
let pressed = input.state == glutin::ElementState::Pressed;
match input.virtual_keycode {
Some(glutin::VirtualKeyCode::Up) => self.moving_up = pressed,
Some(glutin::VirtualKeyCode::Down) => self.moving_down = pressed,
Some(glutin::VirtualKeyCode::Left) => self.moving_left = pressed,
Some(glutin::VirtualKeyCode::Right) => self.moving_right = pressed,
Some(glutin::VirtualKeyCode::Q) => self.moving_forward = pressed,
Some(glutin::VirtualKeyCode::A) => self.moving_backward = pressed,
_ => {}
};
self.update();
}
}

View File

@ -1,187 +1,136 @@
// Can't figure out what macros to import using the 2018 use style.
#[macro_use]
extern crate gfx;
use glium::vertex::VertexBufferAny;
use glium::{glutin, program, uniform, Surface};
use std::thread;
use std::time::{Duration, Instant};
use std::{env, process};
use gfx::traits::{Device, FactoryExt};
use glutin::dpi::LogicalSize;
use glutin::GlContext;
type ColorFormat = gfx::format::Rgba8;
type DepthFormat = gfx::format::DepthStencil;
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
gfx_defines! {
vertex GpuFillVertex {
position: [f32; 2] = "a_position",
}
pipeline fill_pipeline {
vbo: gfx::VertexBuffer<GpuFillVertex> = (),
out_color: gfx::RenderTarget<ColorFormat> = "out_color",
}
}
mod camera;
mod support;
fn main() {
// DPI is broken on my system; force the old behavior.
env::set_var("WINIT_HIDPI_FACTOR", "1.0");
let mut events_loop = glutin::EventsLoop::new();
let window = glutin::WindowBuilder::new()
.with_title("testing glium")
.with_dimensions(glutin::dpi::LogicalSize::new(1024.0, 768.0));
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(window, context, &events_loop).unwrap();
let (initial_width, initial_height) = (700.0, 700.0);
// TODO The geometry...
let vertex_buffer = support::load_wavefront(&display, include_bytes!("teapot.obj"));
let glutin_builder = glutin::WindowBuilder::new()
.with_dimensions(LogicalSize::new(initial_width, initial_height))
.with_decorations(true)
.with_title("gfx playground".to_string());
let program = program!(&display,
140 => {
vertex: "
#version 140
let context = glutin::ContextBuilder::new().with_vsync(true);
uniform mat4 persp_matrix;
uniform mat4 view_matrix;
let (window, mut device, mut factory, mut main_fbo, mut main_depth) =
gfx_window_glutin::init::<ColorFormat, DepthFormat>(glutin_builder, context, &events_loop);
in vec3 position;
in vec3 normal;
out vec3 v_position;
out vec3 v_normal;
let shader = factory
.link_program(VERTEX_SHADER.as_bytes(), FRAGMENT_SHADER.as_bytes())
.unwrap();
void main() {
v_position = position;
v_normal = normal;
gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
}
",
let pso = factory
.create_pipeline_from_program(
&shader,
gfx::Primitive::TriangleList,
gfx::state::Rasterizer::new_fill(),
fill_pipeline::new(),
fragment: "
#version 140
in vec3 v_normal;
out vec4 f_color;
const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);
void main() {
float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
f_color = vec4(color, 1.0);
}
",
},
)
.unwrap();
// The geometry!
let vertices = vec![
// 0 = Top-left
GpuFillVertex {
position: [-1.0, 0.7],
},
// 1 = Top-right
GpuFillVertex {
position: [1.0, 1.0],
},
// 2 = Bottom-left
GpuFillVertex {
position: [-1.0, -1.0],
},
// 3 = Bottom-right
GpuFillVertex {
position: [1.0, -1.0],
},
];
let indices: Vec<u16> = vec![0, 1, 2, 1, 2, 3];
let (vbo, ibo) = factory.create_vertex_buffer_with_slice(&vertices, &indices[..]);
let mut camera = camera::CameraState::new();
let mut cmd_queue: gfx::Encoder<_, _> = factory.create_command_buffer().into();
let mut accumulator = Duration::new(0, 0);
let mut previous_clock = Instant::now();
let mut cam = Camera {
center_x: initial_width / 2.0,
center_y: initial_height / 2.0,
//zoom: 1.0,
};
loop {
if !handle_input(&mut events_loop, &mut cam) {
break;
draw(&camera, &display, &program, &vertex_buffer);
handle_events(&mut camera, &mut events_loop);
let now = Instant::now();
accumulator += now - previous_clock;
previous_clock = now;
let fixed_time_stamp = Duration::new(0, 16666667);
while accumulator >= fixed_time_stamp {
accumulator -= fixed_time_stamp;
// TODO send off an update event
}
gfx_window_glutin::update_views(&window, &mut main_fbo, &mut main_depth);
thread::sleep(fixed_time_stamp - accumulator);
}
}
cmd_queue.clear(&main_fbo.clone(), BLACK);
cmd_queue.draw(
&ibo,
&pso,
&fill_pipeline::Data {
vbo: vbo.clone(),
out_color: main_fbo.clone(),
fn draw(
camera: &camera::CameraState,
display: &glium::Display,
program: &glium::Program,
vertex_buffer: &VertexBufferAny,
) {
let uniforms = uniform! {
persp_matrix: camera.get_perspective(),
view_matrix: camera.get_view(),
};
let params = glium::DrawParameters {
depth: glium::Depth {
test: glium::DepthTest::IfLess,
write: true,
..Default::default()
},
);
cmd_queue.flush(&mut device);
..Default::default()
};
window.swap_buffers().unwrap();
device.cleanup();
}
let mut target = display.draw();
target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
target
.draw(
vertex_buffer,
&glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
&program,
&uniforms,
&params,
)
.unwrap();
target.finish().unwrap();
}
struct Camera {
// Center on some point
center_x: f64,
center_y: f64,
//zoom: f64,
fn handle_events(camera: &mut camera::CameraState, events_loop: &mut glutin::EventsLoop) {
events_loop.poll_events(|event| match event {
glutin::Event::WindowEvent { event, .. } => match event {
glutin::WindowEvent::CloseRequested => {
process::exit(0);
}
glutin::WindowEvent::KeyboardInput { input, .. } => {
if input.virtual_keycode == Some(glutin::VirtualKeyCode::Escape) {
process::exit(0);
}
fn handle_input(event_loop: &mut glutin::EventsLoop, cam: &mut Camera) -> bool {
use glutin::ElementState::Pressed;
use glutin::Event;
use glutin::VirtualKeyCode;
let mut keep_running = true;
event_loop.poll_events(|event| match event {
Event::WindowEvent {
event: glutin::WindowEvent::CloseRequested,
..
} => {
println!("Window Closed!");
keep_running = false;
}
Event::WindowEvent {
event:
glutin::WindowEvent::KeyboardInput {
input:
glutin::KeyboardInput {
state: Pressed,
virtual_keycode: Some(key),
..
},
..
},
..
} => match key {
VirtualKeyCode::Escape => {
keep_running = false;
}
VirtualKeyCode::Left => {
cam.center_x -= 1.0;
}
VirtualKeyCode::Right => {
cam.center_x += 1.0;
}
VirtualKeyCode::Up => {
cam.center_y += 1.0;
}
VirtualKeyCode::Down => {
cam.center_y -= 1.0;
camera.process_input(input);
}
_ => {}
},
_ => {}
});
keep_running
}
// Coordinate system is math-like -- Y increases up.
static VERTEX_SHADER: &'static str = "
#version 140
in vec2 a_position;
out vec4 v_color;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
// gl_Position.y *= -1.0;
v_color = vec4(1.0, 0.0, 0.0, 0.5);
}
";
static FRAGMENT_SHADER: &'static str = "
#version 140
in vec4 v_color;
out vec4 out_color;
void main() {
out_color = v_color;
}
";

53
tmp_gfx/src/support.rs Normal file
View File

@ -0,0 +1,53 @@
use genmesh;
use glium::vertex::VertexBufferAny;
use glium::{self, implement_vertex, Display};
use obj;
/// Returns a vertex buffer that should be rendered as `TrianglesList`.
pub fn load_wavefront(display: &Display, data: &[u8]) -> VertexBufferAny {
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
normal: [f32; 3],
texture: [f32; 2],
}
implement_vertex!(Vertex, position, normal, texture);
let mut data = ::std::io::BufReader::new(data);
let data = obj::Obj::load_buf(&mut data).unwrap();
let mut vertex_data = Vec::new();
for object in data.objects.iter() {
for polygon in object.groups.iter().flat_map(|g| g.polys.iter()) {
match polygon {
&genmesh::Polygon::PolyTri(genmesh::Triangle {
x: v1,
y: v2,
z: v3,
}) => {
for v in [v1, v2, v3].iter() {
let position = data.position[v.0];
let texture = v.1.map(|index| data.texture[index]);
let normal = v.2.map(|index| data.normal[index]);
let texture = texture.unwrap_or([0.0, 0.0]);
let normal = normal.unwrap_or([0.0, 0.0, 0.0]);
vertex_data.push(Vertex {
position: position,
normal: normal,
texture: texture,
})
}
}
_ => unimplemented!(),
}
}
}
glium::vertex::VertexBuffer::new(display, &vertex_data)
.unwrap()
.into_vertex_buffer_any()
}

2090
tmp_gfx/src/teapot.obj Normal file

File diff suppressed because it is too large Load Diff