1use std::{f32::consts::PI, rc::Rc, cell::RefCell};
2use thin_engine::{prelude::*, meshes::teapot};
3#[derive(Hash, PartialEq, Eq, Clone, Copy)]
4enum Action {
5 Jump, Exit,
6 Left, Right, Forward, Back,
7 LookUp, LookDown, LookLeft, LookRight
8}
9fn main() {
10 use Action::*;
11 let event_loop = EventLoop::new().unwrap();
12 event_loop.set_control_flow(ControlFlow::Poll);
13
14 let input = { use base_input_codes::*; input_map!(
15 (Jump, Space, GamepadInput::South),
16 (Exit, [ControlLeft, Escape], GamepadInput::Start),
18 (Left, ArrowLeft, KeyA, LeftStickLeft ),
19 (Right, ArrowRight, KeyD, LeftStickRight),
20 (Forward, ArrowUp, KeyW, LeftStickUp ),
21 (Back, ArrowDown, KeyS, LeftStickDown ),
22 (LookRight, MouseMoveRight, RightStickRight),
23 (LookLeft, MouseMoveLeft, RightStickLeft ),
24 (LookUp, MouseMoveUp, RightStickUp ),
25 (LookDown, MouseMoveDown, RightStickDown )
26 )};
27
28 struct Graphics {
29 program: Program,
30 indices: IndexBuffer<u16>,
31 vertices: VertexBuffer<Vertex>,
32 normals: VertexBuffer<Normal>
33 }
34 let graphics: Rc<RefCell<Option<Graphics>>> = Rc::new(RefCell::new(None));
35 let graphics_setup = graphics.clone();
36
37 let draw_parameters = DrawParameters {
38 backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
39 ..params::alias_3d()
40 };
41
42 let mut pos = vec3(0.0, 0.0, -30.0);
43 let mut rot = vec2(0.0, 0.0);
44 let mut gravity = 0.0;
45
46 let mut frame_start = Instant::now();
47
48 thin_engine::builder(input).with_setup(|display, window, _| {
49 let _ = window.set_cursor_grab(CursorGrabMode::Confined);
50 let _ = window.set_cursor_grab(CursorGrabMode::Locked);
51 window.set_cursor_visible(false);
52 window.set_title("Walk Test");
53
54 let (indices, vertices, normals) = mesh!(
55 display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
56 ).unwrap();
57 let program = Program::from_source(
58 display,
59 "#version 140
60 in vec3 position;
61 in vec3 normal;
62 out vec3 v_normal;
63
64 uniform mat4 camera;
65 uniform mat4 model;
66 uniform mat4 perspective;
67
68 void main() {
69 mat3 norm_mat = transpose(inverse(mat3(camera * model)));
70 v_normal = normalize(norm_mat * normal);
71 gl_Position = perspective * camera * model * vec4(position, 1);
72 }",
73 "#version 140
74 out vec4 colour;
75 in vec3 v_normal;
76
77 uniform vec3 light;
78 const vec3 albedo = vec3(0.1, 1.0, 0.3);
79
80 void main(){
81 float light_level = dot(light, v_normal);
82 colour = vec4(albedo * light_level, 1.0);
83 }", None,
84 ).unwrap();
85 graphics_setup.replace(Some(Graphics { program, indices, vertices, normals }));
86 }).with_update(|input, display, _, target, _| {
87 let graphics = graphics.borrow();
88 let Graphics { vertices, indices, normals, program } = graphics.as_ref().unwrap();
89 let delta_time = frame_start.elapsed().as_secs_f32();
90 frame_start = Instant::now();
91
92 let mut frame = display.draw();
93 let perspective = Mat4::perspective_3d(frame.get_dimensions(), 1.0, 1024.0, 0.1);
94
95 gravity += delta_time * 9.5;
97 if input.pressed(Jump) { gravity = -10.0 }
98
99 let look_move = input.dir(LookRight, LookLeft, LookUp, LookDown);
101 rot += look_move.scale(delta_time * 15.0);
102 rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
103 let rx = Quat::from_y_rot(rot.x);
104 let ry = Quat::from_x_rot(-rot.y);
105 let rot = rx * ry;
106
107 let dir = input.dir_max_len_1(Right, Left, Forward, Back);
109 let move_dir = vec3(dir.x, 0.0, dir.y).scale(5.0*delta_time);
110 pos += Mat3::from_rot(rx) * move_dir;
111 pos.y = (pos.y - gravity * delta_time).max(0.0);
112
113 if input.pressed(Exit) { target.exit() }
114
115 frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
116 frame.draw(
118 (vertices, normals), indices,
119 program, &uniform! {
120 perspective: perspective,
121 model: Mat4::from_scale(Vec3::splat(0.1)),
122 camera: Mat4::from_inverse_transform(pos, Vec3::ONE, rot),
123 light: vec3(1.0, -0.9, -1.0).normalise()
124 },
125 &draw_parameters,
126 ).unwrap();
127
128 frame.finish().unwrap();
129 }).build(event_loop).unwrap();
130}