Last active
April 3, 2019 08:53
-
-
Save Toqozz/21dfc4793d1580fe9f96812ba8fcb1e3 to your computer and use it in GitHub Desktop.
glutin + gfx-rs simple rotating cube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 150 core | |
in vec4 v_Color; | |
in vec4 v_WorldPos; | |
in vec4 v_Normal; | |
in vec4 a_SunDirection; | |
out vec4 Target0; | |
void main() { | |
vec3 norm = normalize(v_Normal.xyz); | |
vec3 lightDir = normalize(-a_SunDirection.xyz); | |
float diff = max(dot(norm, lightDir), 0.0); | |
vec3 result = v_Color.xyz * (diff + 0.1); | |
Target0 = vec4(result, 1.0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 150 core | |
in vec3 a_Pos; | |
in vec3 a_Normal; | |
in vec3 a_Color; | |
uniform vec4 a_SunDir; | |
uniform mat4 u_Model; | |
uniform mat4 u_iModel; | |
uniform mat4 u_View; | |
uniform mat4 u_Proj; | |
out vec4 v_Color; | |
out vec4 v_WorldPos; | |
out vec4 v_Normal; | |
out vec4 a_SunDirection; | |
void main() { | |
gl_Position = (u_Proj * u_View * u_Model) * vec4(a_Pos, 1.0); | |
v_Normal = u_Model * vec4(a_Normal, 1.0); | |
v_WorldPos = u_Model * vec4(a_Pos, 1.0); | |
a_SunDirection = a_SunDir; | |
v_Color = vec4(a_Color, 1.0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "example" | |
version = "0.1.0" | |
authors = ["Michael Palmos <[email protected]>"] | |
edition = "2018" | |
[dependencies] | |
gfx = "0.18" | |
gfx_core = "*" | |
gfx_device_gl = "*" | |
gfx_window_glutin = "0.30.0" | |
glutin = "*" | |
nalgebra = "*" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] extern crate gfx; | |
extern crate gfx_core; | |
extern crate gfx_device_gl; | |
extern crate gfx_window_glutin; | |
extern crate glutin; | |
extern crate nalgebra; | |
use gfx::Device; | |
use gfx::traits::FactoryExt; | |
use glutin::os::unix::WindowBuilderExt; | |
use gfx_device_gl::{Device as glDevice, Factory, Resources}; | |
use gfx::handle::{RenderTargetView, DepthStencilView}; | |
use gfx::format::{Srgba8, DepthStencil}; | |
use glutin::{WindowedContext, EventsLoop}; | |
use glutin::WindowEvent::*; | |
use nalgebra::base::*; | |
use nalgebra::geometry::{Point3, Rotation3}; | |
gfx_defines! { | |
vertex Vertex { | |
pos: [f32; 3] = "a_Pos", | |
normal: [f32; 3] = "a_Normal", | |
color: [f32; 4] = "a_Color", | |
} | |
pipeline pipe { | |
vbuf: gfx::VertexBuffer<Vertex> = (), | |
sun: gfx::Global<[f32; 4]> = "a_SunDir", | |
model_inverse: gfx::Global<[[f32; 4]; 4]> = "u_iModel", | |
model: gfx::Global<[[f32; 4]; 4]> = "u_Model", | |
view: gfx::Global<[[f32; 4]; 4]> = "u_View", | |
proj: gfx::Global<[[f32; 4]; 4]> = "u_Proj", | |
out: gfx::RenderTarget<gfx::format::Srgba8> = "Target0", | |
out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE, | |
} | |
} | |
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; | |
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 0.5]; | |
const CUBE: [Vertex; 36] = [ | |
// 0 | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, 1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, 1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
// 1 | |
Vertex { pos: [1.0, 1.0, -1.0], normal: [0.0, 0.0, -1.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [0.0, 0.0, -1.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, -1.0], normal: [0.0, 0.0, -1.0], color: WHITE }, | |
// 2 | |
Vertex { pos: [1.0, -1.0, 1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, -1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
// 3 | |
Vertex { pos: [1.0, 1.0, -1.0], normal: [0.0, 0.0, -1.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, -1.0], normal: [-0.0, 0.0, -1.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [-0.0, 0.0, -1.0], color: WHITE }, | |
// 4 | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, 1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, -1.0], normal: [-1.0, 0.0, 0.0], color: WHITE }, | |
// 5 | |
Vertex { pos: [1.0, -1.0, 1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, 1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, -1.0], normal: [0.0, -1.0, 0.0], color: WHITE }, | |
// 6 | |
Vertex { pos: [-1.0, 1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
Vertex { pos: [-1.0, -1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
// 7 | |
Vertex { pos: [1.0, 1.0, 1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, -1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, 1.0, -1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
// 8 | |
Vertex { pos: [1.0, -1.0, -1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, 1.0, 1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, 1.0], normal: [1.0, 0.0, 0.0], color: WHITE }, | |
// 9 | |
Vertex { pos: [1.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0], color: WHITE }, | |
Vertex { pos: [1.0, 1.0, -1.0], normal: [0.0, 1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, -1.0], normal: [0.0, 1.0, 0.0], color: WHITE }, | |
// 10 | |
Vertex { pos: [1.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, -1.0], normal: [-0.0, 1.0, 0.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, 1.0], normal: [-0.0, 1.0, 0.0], color: WHITE }, | |
// 11 | |
Vertex { pos: [1.0, 1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
Vertex { pos: [-1.0, 1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
Vertex { pos: [1.0, -1.0, 1.0], normal: [0.0, 0.0, 1.0], color: WHITE }, | |
]; | |
const INDICES: &[u16] = &[ | |
0, 1, 2, 3, 4, 5, | |
6, 7, 8, 9, 10, 11, | |
12, 13, 14, 15, 16, 17, | |
18, 19, 20, 21, 22, 23, | |
24, 25, 26, 27, 28, 29, | |
30, 31, 32, 33, 34, 35 | |
]; | |
struct GLWindow { | |
context: WindowedContext, | |
events_loop: EventsLoop, | |
device: glDevice, | |
factory: Factory, | |
render_target: RenderTargetView<Resources, Srgba8>, | |
depth_target: DepthStencilView<Resources, DepthStencil> | |
} | |
impl GLWindow { | |
fn build_window() -> GLWindow { | |
// Events loop to caputer window events (clicked, moved, resized, etc). | |
let mut events_loop = glutin::EventsLoop::new(); | |
// Initialize a window and context but don't build them yet. | |
let window_builder = glutin::WindowBuilder::new() | |
.with_title("example") | |
.with_transparency(true) | |
let context_builder = glutin::ContextBuilder::new() | |
.with_vsync(true); | |
// Build the window using the glutin backend for gfx-rs. | |
// window -- obvious, device -- rendering device, factory -- creation?, color_view -- base | |
// color, depth_view -- ? | |
let (window, mut device, mut factory, color_view, mut depth_view) = | |
gfx_window_glutin::init::<Srgba8, DepthStencil>(window_builder, context_builder, &events_loop) | |
.expect("Failed to create a window."); | |
GLWindow { context: window, events_loop, device, factory, render_target: color_view, depth_target: depth_view } | |
} | |
} | |
#[derive(Debug)] | |
struct Mouse { | |
delta: (f64, f64), | |
down: bool, | |
} | |
impl Mouse { | |
fn update_delta(&mut self, delta: (f64, f64)) { | |
self.delta = delta; | |
} | |
fn update_press(&mut self, state: &glutin::ElementState) { | |
self.down = &glutin::ElementState::Pressed == state; | |
} | |
} | |
fn main() { | |
let mut glutin_window = GLWindow::build_window(); | |
// Using an encoder avoids having to use raw OpenGL procedures. | |
let mut encoder: gfx::Encoder<_, _> = glutin_window.factory.create_command_buffer().into(); | |
// To my understanding, pipeline state objects essentially batch shader commands. | |
// TODO: better explanation. | |
let pso = glutin_window.factory.create_pipeline_simple( | |
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/base.glslv")), | |
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/base.glslf")), | |
pipe::new() | |
).unwrap(); | |
let mut model_mat = Matrix4::identity(); | |
let view_mat = Matrix4::look_at_rh( | |
&Point3::new(0.0, 5.0, 0.0), | |
&Point3::new(0.0, 0.0, 0.0), | |
&Vector3::z(), | |
); | |
let proj_mat = nalgebra::Perspective3::new(60.0f32.to_radians(), 1.3, 0.1, 1000.0); | |
// Create vertex buffer and slice from supplied vertices. | |
// A slice dictates what and in what order vertices are processed. | |
let (vertex_buffer, slice) = glutin_window.factory.create_vertex_buffer_with_slice(&CUBE, INDICES); | |
let mut data = pipe::Data { | |
vbuf: vertex_buffer, | |
sun: Vector4::new(1.0, 0.0, -1.0, 1.0).into(), | |
model_inverse: model_mat.into(), | |
model: model_mat.into(), | |
view: view_mat.into(), | |
proj: proj_mat.into_inner().into(), | |
out: glutin_window.render_target, | |
out_depth: glutin_window.depth_target.clone(), | |
}; | |
// Mouse struct to wrap some convenient info. | |
let mut mouse = Mouse { delta: (0.0, 0.0), down: false }; | |
// Run until manual intervention. | |
let mut running = true; | |
while running { | |
mouse.delta = (0.0, 0.0); | |
glutin_window.events_loop.poll_events(|event| { | |
if let glutin::Event::WindowEvent { event, .. } = &event { | |
match event { | |
CloseRequested => running = false, | |
MouseInput { state, .. } => mouse.update_press(state), | |
_ => {} | |
} | |
} | |
if let glutin::Event::DeviceEvent { event, .. } = &event { | |
match event { | |
glutin::DeviceEvent::MouseMotion { delta, .. } => mouse.delta = delta.clone(), | |
_ => {} | |
} | |
} | |
}); | |
let rotationz = Rotation3::from_axis_angle(&Unit::new_normalize(Vector3::z()), mouse.delta.0 as f32 * 0.01); | |
let rotationx = Rotation3::from_axis_angle(&Unit::new_normalize(Vector3::x()), mouse.delta.1 as f32 * -0.01); | |
if mouse.down { | |
model_mat = data.model.into(); | |
model_mat = rotationz.to_homogeneous() * model_mat; | |
model_mat = rotationx.to_homogeneous() * model_mat; | |
data.model = model_mat.into(); | |
} | |
encoder.clear(&data.out, BLACK); | |
encoder.clear_depth(&data.out_depth, 1.0); | |
encoder.draw(&slice, &pso, &data); | |
encoder.flush(&mut glutin_window.device); | |
glutin_window.context.swap_buffers().unwrap(); | |
glutin_window.device.cleanup(); | |
} | |
} |
Author
Toqozz
commented
Apr 3, 2019
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment