mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 03:41:09 +03:00
importing and simplifying glium teapot example
This commit is contained in:
parent
08db3bf27f
commit
87b885fcd7
@ -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?"
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
170
tmp_gfx/src/camera.rs
Normal 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();
|
||||
}
|
||||
}
|
@ -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(),
|
||||
)
|
||||
.unwrap();
|
||||
fragment: "
|
||||
#version 140
|
||||
|
||||
// The geometry!
|
||||
let vertices = vec![
|
||||
// 0 = Top-left
|
||||
GpuFillVertex {
|
||||
position: [-1.0, 0.7],
|
||||
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);
|
||||
}
|
||||
",
|
||||
},
|
||||
// 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[..]);
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut cmd_queue: gfx::Encoder<_, _> = factory.create_command_buffer().into();
|
||||
let mut camera = camera::CameraState::new();
|
||||
|
||||
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);
|
||||
|
||||
cmd_queue.clear(&main_fbo.clone(), BLACK);
|
||||
cmd_queue.draw(
|
||||
&ibo,
|
||||
&pso,
|
||||
&fill_pipeline::Data {
|
||||
vbo: vbo.clone(),
|
||||
out_color: main_fbo.clone(),
|
||||
},
|
||||
);
|
||||
cmd_queue.flush(&mut device);
|
||||
|
||||
window.swap_buffers().unwrap();
|
||||
|
||||
device.cleanup();
|
||||
thread::sleep(fixed_time_stamp - accumulator);
|
||||
}
|
||||
}
|
||||
|
||||
struct Camera {
|
||||
// Center on some point
|
||||
center_x: f64,
|
||||
center_y: f64,
|
||||
//zoom: f64,
|
||||
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()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
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,
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
target.finish().unwrap();
|
||||
}
|
||||
|
||||
fn handle_input(event_loop: &mut glutin::EventsLoop, cam: &mut Camera) -> bool {
|
||||
use glutin::ElementState::Pressed;
|
||||
use glutin::Event;
|
||||
use glutin::VirtualKeyCode;
|
||||
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);
|
||||
}
|
||||
|
||||
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
53
tmp_gfx/src/support.rs
Normal 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
2090
tmp_gfx/src/teapot.obj
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user