use std::{f32::consts::PI, rc::Rc, cell::RefCell};
use thin_engine::{
ResizableTexture2d, ResizableDepthTexture2d,
prelude::*, glium::framebuffer::*,
meshes::{teapot, screen}
};
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
enum Action {
Left, Right, Forward, Back,
LookLeft, LookRight, LookUp, LookDown,
FXAA
}
fn main() {
use Action::*;
let event_loop = EventLoop::new().unwrap();
event_loop.set_control_flow(ControlFlow::Poll);
let mut colour = ResizableTexture2d::default();
let mut depth = ResizableDepthTexture2d::default();
let input = { use base_input_codes::*; input_map!(
(Left, ArrowLeft, KeyA, LeftStickLeft ),
(Right, ArrowRight, KeyD, LeftStickRight),
(Forward, ArrowUp, KeyW, LeftStickUp ),
(Back, ArrowDown, KeyS, LeftStickDown ),
(LookRight, MouseMoveRight, RightStickRight),
(LookLeft, MouseMoveLeft, RightStickLeft ),
(LookUp, MouseMoveUp, RightStickUp ),
(LookDown, MouseMoveDown, RightStickDown ),
(FXAA, KeyF, GamepadInput::North)
) };
struct Graphics {
screen_indices: IndexBuffer<u32>,
screen_vertices: VertexBuffer<Vertex>,
screen_uvs: VertexBuffer<TextureCoords>,
teapot_indices: IndexBuffer<u16>,
teapot_vertices: VertexBuffer<Vertex>,
teapot_uvs: VertexBuffer<TextureCoords>,
teapot_normals: VertexBuffer<Normal>,
fxaa: Program, normal: Program, program: Program
}
let graphics: Rc<RefCell<Option<Graphics>>> = Rc::default();
let graphics_setup = graphics.clone();
let draw_parameters = DrawParameters {
backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
..params::alias_3d()
};
let mut fxaa_on = true;
let mut pos = vec3(0.0, 0.0, -30.0);
let mut rot = vec2(0.0, 0.0);
let mut frame_start = Instant::now();
thin_engine::builder(input).with_setup(|display, window, _| {
window.set_title("FXAA Test");
let _ = window.set_cursor_grab(CursorGrabMode::Confined);
let _ = window.set_cursor_grab(CursorGrabMode::Locked);
window.set_cursor_visible(false);
let (screen_indices, screen_vertices, screen_uvs) = mesh!(
display, &screen::INDICES, &screen::VERTICES, &screen::UVS
).unwrap();
let (teapot_indices, teapot_vertices, teapot_uvs, teapot_normals) = mesh!(
display, &teapot::INDICES, &teapot::VERTICES, &[] as &[TextureCoords; 0], &teapot::NORMALS
).unwrap();
let program = Program::from_source(
display,
"#version 140
in vec3 position;
in vec3 normal;
out vec3 v_normal;
uniform mat4 model;
uniform mat4 perspective;
uniform mat4 camera;
void main() {
mat3 norm_mat = transpose(inverse(mat3(camera * model)));
v_normal = normalize(norm_mat * normal);
gl_Position = perspective * camera * model * vec4(position, 1);
}",
"#version 140
out vec4 colour;
in vec3 v_normal;
uniform vec3 light;
uniform mat4 camera;
uniform vec3 ambient;
uniform vec3 albedo;
uniform float shine;
void main() {
vec3 camera_dir = inverse(mat3(camera)) * vec3(0, 0, -1);
vec3 half_dir = normalize(camera_dir + light);
float specular = pow(max(dot(half_dir, v_normal), 0.0), shine);
float light_level = max(dot(light, v_normal), 0.0);
colour = vec4(albedo * light_level + ambient + vec3(specular), 1.0);
}", None
).unwrap();
let fxaa = shaders::fxaa_shader(display).unwrap();
let normal = Program::from_source(
display,
"#version 140
in vec2 texture_coords;
out vec2 uv;
in vec3 position;
void main() {
uv = texture_coords;
gl_Position = vec4(position, 1);
}",
"#version 140
in vec2 uv;
uniform sampler2D tex;
out vec4 colour;
void main() {
colour = texture(tex, uv);
}", None
).unwrap();
graphics_setup.replace(Some(Graphics {
screen_indices, screen_vertices, screen_uvs,
teapot_indices, teapot_vertices, teapot_uvs, teapot_normals,
program, normal, fxaa
}));
}).with_update(|input, display, _, _, _| {
let graphics = graphics.borrow();
let Graphics {
screen_indices, screen_vertices, screen_uvs,
teapot_indices, teapot_vertices, teapot_uvs, teapot_normals,
program, normal, fxaa
} = graphics.as_ref().unwrap();
let teapot_mesh = (teapot_vertices, teapot_normals, teapot_uvs);
let screen_mesh = (screen_vertices, screen_uvs);
let delta_time = frame_start.elapsed().as_secs_f32();
frame_start = Instant::now();
let size = (380, 216);
display.resize(size);
depth.resize_to_display(&display);
colour.resize_to_display(&display);
if input.pressed(FXAA) { fxaa_on = !fxaa_on }
let colour = colour.texture();
let depth = depth.texture();
let mut frame = SimpleFrameBuffer::with_depth_buffer(
display, colour, depth
).unwrap();
let perspective = Mat4::perspective_3d(size, 1.0, 1024.0, 0.1);
let look_move = input.dir(LookRight, LookLeft, LookUp, LookDown);
rot += look_move.scale(delta_time * 15.0);
rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
let rx = Quat::from_y_rot(rot.x);
let ry = Quat::from_x_rot(-rot.y);
let rot = rx * ry;
let dir = input.dir_max_len_1(Right, Left, Forward, Back);
let move_dir = vec3(dir.x, 0.0, dir.y).scale(5.0*delta_time);
pos += Mat3::from_rot(rx) * move_dir;
frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
frame.draw(
teapot_mesh, teapot_indices,
program, &uniform! {
perspective: perspective,
model: Mat4::from_scale(Vec3::splat(0.1)),
camera: Mat4::from_inverse_transform(pos, Vec3::ONE, rot),
light: vec3(0.1, 0.25, -1.0).normalise(),
albedo: vec3(0.5, 0.1, 0.4),
ambient: vec3(0.0, 0.05, 0.1),
shine: 50.0f32,
},
&draw_parameters,
).unwrap();
let mut frame = display.draw();
frame.draw(
screen_mesh, screen_indices, if fxaa_on { fxaa } else { normal },
&shaders::fxaa_uniforms(colour), &DrawParameters::default()
).unwrap();
frame.finish().unwrap();
}).build(event_loop).unwrap();
}