simple/
simple.rs

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        // square brackets mean that all input codes must be pressed for the bind to be pressed
17        (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        // handle gravity and jump
96        gravity += delta_time * 9.5;
97        if input.pressed(Jump) { gravity = -10.0 }
98
99        // set camera rotation
100        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        // move player based on camera and gravity
108        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        //draw teapot
117        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}