#[macro_use]
extern crate glium;
use glium::index::PrimitiveType;
use glium::{Display, Surface};
use glutin::surface::WindowSurface;
use support::{ApplicationContext, State};
mod support;
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 2],
}
implement_vertex!(Vertex, position);
struct Application {
pub vertex_buffer: glium::VertexBuffer<Vertex>,
pub index_buffer: glium::IndexBuffer<u16>,
pub program: glium::Program,
pub tess_level: i32,
}
impl ApplicationContext for Application {
const WINDOW_TITLE:&'static str = "Glium tesselation example";
fn new(display: &Display<WindowSurface>) -> Self {
let vertex_buffer = {
glium::VertexBuffer::new(
display,
&[
Vertex {
position: [-0.5, -0.5],
},
Vertex {
position: [0.0, 0.5],
},
Vertex {
position: [0.5, -0.5],
},
],
)
.unwrap()
};
let index_buffer = glium::IndexBuffer::new(
display,
PrimitiveType::Patches {
vertices_per_patch: 3,
},
&[0u16, 1, 2],
)
.unwrap();
let program = glium::Program::new(
display,
glium::program::SourceCode {
vertex_shader: "
#version 140
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
",
fragment_shader: "
#version 140
in vec3 color;
out vec4 f_color;
void main() {
f_color = vec4(color, 1.0);
}
",
geometry_shader: Some(
"
#version 330
uniform mat4 matrix;
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
out vec3 color;
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
void main() {
vec3 all_color = vec3(
rand(gl_in[0].gl_Position.xy + gl_in[1].gl_Position.yz),
rand(gl_in[1].gl_Position.yx + gl_in[2].gl_Position.zx),
rand(gl_in[0].gl_Position.xz + gl_in[2].gl_Position.zy)
);
gl_Position = matrix * gl_in[0].gl_Position;
color = all_color;
EmitVertex();
gl_Position = matrix * gl_in[1].gl_Position;
color = all_color;
EmitVertex();
gl_Position = matrix * gl_in[2].gl_Position;
color = all_color;
EmitVertex();
}
",
),
tessellation_control_shader: Some(
"
#version 400
layout(vertices = 3) out;
uniform int tess_level = 5;
void main() {
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
gl_TessLevelOuter[0] = tess_level;
gl_TessLevelOuter[1] = tess_level;
gl_TessLevelOuter[2] = tess_level;
gl_TessLevelInner[0] = tess_level;
}
",
),
tessellation_evaluation_shader: Some(
"
#version 400
layout(triangles, equal_spacing) in;
void main() {
vec3 position = vec3(gl_TessCoord.x) * gl_in[0].gl_Position.xyz +
vec3(gl_TessCoord.y) * gl_in[1].gl_Position.xyz +
vec3(gl_TessCoord.z) * gl_in[2].gl_Position.xyz;
gl_Position = vec4(position, 1.0);
}
",
),
},
)
.unwrap();
let tess_level: i32 = 5;
println!(
"The current tessellation level is {} ; use the Up and Down keys to change it",
tess_level
);
Self {
vertex_buffer,
index_buffer,
tess_level,
program,
}
}
fn draw_frame(&mut self, display: &Display<WindowSurface>) {
let mut frame = display.draw();
let uniforms = uniform! {
matrix: [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0f32]
],
tess_level: self.tess_level
};
frame.clear_color(0.0, 0.0, 0.0, 0.0);
frame
.draw(
&self.vertex_buffer,
&self.index_buffer,
&self.program,
&uniforms,
&Default::default(),
)
.unwrap();
frame.finish().unwrap();
}
fn handle_window_event(&mut self, event: &glium::winit::event::WindowEvent, _window: &glium::winit::window::Window) {
use glium::winit::keyboard::{PhysicalKey, KeyCode};
match event {
glium::winit::event::WindowEvent::KeyboardInput { event, .. } => match event.state {
glium::winit::event::ElementState::Pressed => match event.physical_key {
PhysicalKey::Code(KeyCode::ArrowUp) => {
self.tess_level += 1;
println!("New tessellation level: {}", self.tess_level);
}
PhysicalKey::Code(KeyCode::ArrowDown) => {
if self.tess_level >= 2 {
self.tess_level -= 1;
println!("New tessellation level: {}", self.tess_level);
}
}
_ => (),
},
_ => (),
},
_ => (),
}
}
}
fn main() {
State::<Application>::run_loop();
}