Skip to content

Instantly share code, notes, and snippets.

@Toqozz
Last active April 3, 2019 08:53
Show Gist options
  • Save Toqozz/21dfc4793d1580fe9f96812ba8fcb1e3 to your computer and use it in GitHub Desktop.
Save Toqozz/21dfc4793d1580fe9f96812ba8fcb1e3 to your computer and use it in GitHub Desktop.
glutin + gfx-rs simple rotating cube
#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);
}
#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);
}
[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 = "*"
#[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();
}
}
@Toqozz
Copy link
Author

Toqozz commented Apr 3, 2019

demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment