Struct thin_engine::prelude::InputMap

source ·
pub struct InputMap<const BINDS: usize> {
    pub binds: [Vec<Input>; BINDS],
    pub pressing: [bool; BINDS],
    pub pressed: [bool; BINDS],
    pub released: [bool; BINDS],
    pub mouse_scroll: f32,
    pub mouse_move: Vec2,
    pub mouse_pos: Vec2,
}
Expand description

input system. define actions and their key binds and then see if their pressing, pressed or released. get mouse position and how much its moved. you can use anythin that implements the Into<usize> trait as an action, but it’s recommended to use an action enum.

enum Actions{
    Debug,
    Left,
    Right,
    Click
}
impl Into<usize> for Actions{
    fn into(self) -> usize {
        self as usize
    }
}
use input::{InputMap, Input};
use Actions::*;

let mut input = Input::new([
    (vec![Input::keycode(KeyCode::Space)], Debug),
    (vec![Input::keycode(KeyCode::ArrowLeft), InputCode::keycode(KeyCode::KeyA)], Left),
    (vec![Input::keycode(KeyCode::ArrowRight), InputCode::keycode(KeyCode::KeyD)], Right),
    (vec![Input::Mouse(MouseButton::Left)], Click)
]);
     
use winit::{event::*, keyboard::KeyCode, window::WindowAttribures};
let event_loop = winit::event_loop::EventLoop::new().unwrap();
event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll);
let _window = event_loop.create_window(WindowAttribures::default()).unwrap();

event_loop.run(|event, target|{
    input.update(&event);
    match &event {
        Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { target.exit() },
        Event::AboutToWait => {
            if input.pressed(Debug) { println!("pressed {:?}", input.binds(Debug)) }
            if input.pressing(Right) || input.pressing(Left) { println!("axis: {}", input.axis(Right, Left)) }
            if input.mouse_move != (0.0, 0.0) { println!("mouse moved: {:?} and is now at {:?}", input.mouse_move, input.mouse_pos) }
            if input.released(Click) { println!("released {:?}", input.binds(Click)) }
             
            std::thread::sleep(std::time::Duration::from_millis(100));
            //put at end of loop because were done with inputs this frame.
            input.init(;
        }
        _ => ()
    }
}).unwrap();

Fields§

§binds: [Vec<Input>; BINDS]§pressing: [bool; BINDS]§pressed: [bool; BINDS]§released: [bool; BINDS]§mouse_scroll: f32

the amount the scroll wheel has changed

§mouse_move: Vec2§mouse_pos: Vec2

Implementations§

source§

impl<const BINDS: usize> InputMap<BINDS>

source

pub fn new(binds: [(Vec<Input>, impl Into<usize>); BINDS]) -> InputMap<BINDS>

create new input system. recommended to use an action enum which implements the Into<usize> trait for the second value.

enum Action{
    Forward,
    Back,
    Left,
    Right
}
impl Into<usize> for Action{
    fn into(self) -> usize{
        self as usize
    }
}

use Action::*;
use input::{Input, InputCode};
use winit::keyboard::KeyCode;
//doesnt have to be the same ordered as the enum.
let mut input = Input::new([
    (vec![Input::keycode(KeyCode::KeyW)], Forward),
    (vec![Input::keycode(KeyCode::KeyA)], Left),
    (vec![Input::keycode(KeyCode::KeyS)], Back),
    (vec![Input::keycode(KeyCode::KeyD)], Right)
]);
Examples found in repository?
examples/simple.rs (lines 22-28)
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("Walk Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::Space)], Jump),
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back)
    ]);

    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#version 140
        out vec4 colour;
        in vec3 v_normal;
        uniform vec3 light;

        const vec3 albedo = vec3(0.1, 1.0, 0.3);
        void main(){
            float light_level = dot(light, v_normal);
            colour = vec4(albedo * light_level, 1.0);
        }", None,
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    let mut gravity = 0.0;

    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        display.resize(window.inner_size().into());
        let mut frame = display.draw();
        let view = Mat4::view_matrix_3d(frame.get_dimensions(), 1.0, 1024.0, 0.1);

        //handle gravity and jump
        gravity += DELTA * 9.5;
        if input.pressed(Jump) {
            gravity = -10.0;
        }

        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view and gravity
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise();
        pos += move_dir.transform(&Mat3::from_rot(rx)).scale(5.0 * DELTA);
        pos.y = (pos.y - gravity * DELTA).max(0.0);

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            (&verts, &norms), &indices,
            &program, &uniform! {
                view: view,
                model: Mat4::from_scale(Vec3::splat(0.1)),
                camera: Mat4::from_inverse_transform(pos, Vec3::ONE, rot),
                light: vec3(1.0, -0.9, -1.0).normalise()
            },
            &draw_parameters,
        ).unwrap();

        frame.finish().unwrap();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}
More examples
Hide additional examples
examples/simple-fxaa.rs (lines 30-37)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("FXAA Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut colour = ResizableTexture2D::default();
    let mut depth = ResizableDepthTexture2D::default();

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back),
        (vec![Input::keycode(KeyCode::KeyF)], FXAA),
        (vec![Input::keycode(KeyCode::Space)], Jump)
    ]);
    let (screen_indices, verts, uvs) = mesh!(
        &display, &screen::INDICES, &screen::VERTICES, &screen::UVS
    );
    let screen_mesh = (&verts, &uvs);
    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let teapot_mesh = (&verts, &norms);
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let mut fxaa_on = true;
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#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, shaders::SCREEN_VERTEX, 
        "#version 140
        in vec2 uv;
        uniform sampler2D tex;
        out vec4 colour;
        void main() {
            colour = texture(tex, uv);
        }", None
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        // using a small resolution to show the effect.
        // `let size = window.inner_size().into();` 
        // can be used isntead to set resolution to window size
        let size = (380, 216);
        display.resize(size);
        depth.resize_to_display(&display);
        colour.resize_to_display(&display);

        //press f to toggle FXAA
        if input.pressed(FXAA) { fxaa_on = !fxaa_on }

        let colour = colour.texture.as_ref().unwrap();
        let depth = depth.texture.as_ref().unwrap();
        let mut frame = SimpleFrameBuffer::with_depth_buffer(
            &display, colour, depth
        ).unwrap();

        let view = Mat4::view_matrix_3d(size, 1.0, 1024.0, 0.1);        
        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise().scale(5.0*DELTA);
        pos += move_dir.transform(&Mat3::from_rot(rx));

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            teapot_mesh, &indices,
            &program, &uniform! {
                view: view,
                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: 10.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();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}
source

pub fn update(&mut self, event: &Event<()>)

updates the input using a winit event. requires input.init() to be used before being updated.

use winit::event::*;
use input::Input;

let mut event_loop = winit::event_loop::EventLoopBuilder::new().build().unwrap();
event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll);

let mut input = Input::new([]);

event_loop.run(|event, target|{
    input.update(&event);
    match &event{
        Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => target.exit(),
        Event::AboutToWait => input.init(),
        _ => ()
    }
});
source

pub fn init(&mut self)

initialise input. required to be called for mouse_move, pressed() and released() to work. required to put input.init() before input.update()

use winit::event::*;
use input::InputMap;

let mut event_loop = winit::event_loop::EventLoopBuilder::new().build().unwrap();
event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll);

let mut input = InputMap::new([]);

event_loop.run(|event, target|{
    input.update(&event);
    match &event{
        Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => target.exit(),
        Event::AboutToWait => input.init(),
        _ => ()
    }
});
source

pub fn binds(&mut self, action: impl Into<usize>) -> &mut Vec<Input>

get binds of action. same as self.binds[action.into()]

source

pub fn pressing(&self, action: impl Into<usize>) -> bool

checks if action is being pressed currently. same as self.pressing[action.into()]

source

pub fn pressed(&self, action: impl Into<usize>) -> bool

checks if action was just pressed. same as self.pressed[action.into()]

Examples found in repository?
examples/simple.rs (line 64)
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("Walk Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::Space)], Jump),
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back)
    ]);

    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#version 140
        out vec4 colour;
        in vec3 v_normal;
        uniform vec3 light;

        const vec3 albedo = vec3(0.1, 1.0, 0.3);
        void main(){
            float light_level = dot(light, v_normal);
            colour = vec4(albedo * light_level, 1.0);
        }", None,
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    let mut gravity = 0.0;

    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        display.resize(window.inner_size().into());
        let mut frame = display.draw();
        let view = Mat4::view_matrix_3d(frame.get_dimensions(), 1.0, 1024.0, 0.1);

        //handle gravity and jump
        gravity += DELTA * 9.5;
        if input.pressed(Jump) {
            gravity = -10.0;
        }

        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view and gravity
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise();
        pos += move_dir.transform(&Mat3::from_rot(rx)).scale(5.0 * DELTA);
        pos.y = (pos.y - gravity * DELTA).max(0.0);

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            (&verts, &norms), &indices,
            &program, &uniform! {
                view: view,
                model: Mat4::from_scale(Vec3::splat(0.1)),
                camera: Mat4::from_inverse_transform(pos, Vec3::ONE, rot),
                light: vec3(1.0, -0.9, -1.0).normalise()
            },
            &draw_parameters,
        ).unwrap();

        frame.finish().unwrap();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}
More examples
Hide additional examples
examples/simple-fxaa.rs (line 95)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("FXAA Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut colour = ResizableTexture2D::default();
    let mut depth = ResizableDepthTexture2D::default();

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back),
        (vec![Input::keycode(KeyCode::KeyF)], FXAA),
        (vec![Input::keycode(KeyCode::Space)], Jump)
    ]);
    let (screen_indices, verts, uvs) = mesh!(
        &display, &screen::INDICES, &screen::VERTICES, &screen::UVS
    );
    let screen_mesh = (&verts, &uvs);
    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let teapot_mesh = (&verts, &norms);
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let mut fxaa_on = true;
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#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, shaders::SCREEN_VERTEX, 
        "#version 140
        in vec2 uv;
        uniform sampler2D tex;
        out vec4 colour;
        void main() {
            colour = texture(tex, uv);
        }", None
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        // using a small resolution to show the effect.
        // `let size = window.inner_size().into();` 
        // can be used isntead to set resolution to window size
        let size = (380, 216);
        display.resize(size);
        depth.resize_to_display(&display);
        colour.resize_to_display(&display);

        //press f to toggle FXAA
        if input.pressed(FXAA) { fxaa_on = !fxaa_on }

        let colour = colour.texture.as_ref().unwrap();
        let depth = depth.texture.as_ref().unwrap();
        let mut frame = SimpleFrameBuffer::with_depth_buffer(
            &display, colour, depth
        ).unwrap();

        let view = Mat4::view_matrix_3d(size, 1.0, 1024.0, 0.1);        
        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise().scale(5.0*DELTA);
        pos += move_dir.transform(&Mat3::from_rot(rx));

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            teapot_mesh, &indices,
            &program, &uniform! {
                view: view,
                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: 10.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();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}
source

pub fn released(&self, action: impl Into<usize>) -> bool

checks if action was just released. same as self.released[action.into()]

source

pub fn axis(&self, pos: impl Into<usize>, neg: impl Into<usize>) -> f32

returns 1.0 if pos is pressed, -1.0 if neg is pressed or 0.0 if either pos and neg or nothing is pressed. usefull for movement controls. same as input::axis(input.pressing(pos), input.pressing(neg))

let move_dir = (input.axis(Right, Left), input.axis(Up, Down));
Examples found in repository?
examples/simple.rs (line 76)
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("Walk Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::Space)], Jump),
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back)
    ]);

    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#version 140
        out vec4 colour;
        in vec3 v_normal;
        uniform vec3 light;

        const vec3 albedo = vec3(0.1, 1.0, 0.3);
        void main(){
            float light_level = dot(light, v_normal);
            colour = vec4(albedo * light_level, 1.0);
        }", None,
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    let mut gravity = 0.0;

    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        display.resize(window.inner_size().into());
        let mut frame = display.draw();
        let view = Mat4::view_matrix_3d(frame.get_dimensions(), 1.0, 1024.0, 0.1);

        //handle gravity and jump
        gravity += DELTA * 9.5;
        if input.pressed(Jump) {
            gravity = -10.0;
        }

        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view and gravity
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise();
        pos += move_dir.transform(&Mat3::from_rot(rx)).scale(5.0 * DELTA);
        pos.y = (pos.y - gravity * DELTA).max(0.0);

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            (&verts, &norms), &indices,
            &program, &uniform! {
                view: view,
                model: Mat4::from_scale(Vec3::splat(0.1)),
                camera: Mat4::from_inverse_transform(pos, Vec3::ONE, rot),
                light: vec3(1.0, -0.9, -1.0).normalise()
            },
            &draw_parameters,
        ).unwrap();

        frame.finish().unwrap();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}
More examples
Hide additional examples
examples/simple-fxaa.rs (line 112)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn main() {
    use Action::*;
    let (event_loop, window, display) = thin_engine::set_up().unwrap();
    window.set_title("FXAA Test");
    let _ = window.set_cursor_grab(CursorGrabMode::Locked);
    window.set_cursor_visible(false);

    let mut colour = ResizableTexture2D::default();
    let mut depth = ResizableDepthTexture2D::default();

    let mut input = InputMap::new([
        (vec![Input::keycode(KeyCode::ArrowLeft), Input::keycode(KeyCode::KeyA)], Left),
        (vec![Input::keycode(KeyCode::ArrowRight), Input::keycode(KeyCode::KeyD)], Right),
        (vec![Input::keycode(KeyCode::ArrowUp), Input::keycode(KeyCode::KeyW)], Forward),
        (vec![Input::keycode(KeyCode::ArrowDown), Input::keycode(KeyCode::KeyS)], Back),
        (vec![Input::keycode(KeyCode::KeyF)], FXAA),
        (vec![Input::keycode(KeyCode::Space)], Jump)
    ]);
    let (screen_indices, verts, uvs) = mesh!(
        &display, &screen::INDICES, &screen::VERTICES, &screen::UVS
    );
    let screen_mesh = (&verts, &uvs);
    let (indices, verts, norms) = mesh!(
        &display, &teapot::INDICES, &teapot::VERTICES, &teapot::NORMALS
    );
    let teapot_mesh = (&verts, &norms);
    let draw_parameters = DrawParameters {
        backface_culling: draw_parameters::BackfaceCullingMode::CullClockwise,
        ..params::alias_3d()
    };
    let mut fxaa_on = true;
    let program = Program::from_source(
        &display, shaders::VERTEX,
        "#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, shaders::SCREEN_VERTEX, 
        "#version 140
        in vec2 uv;
        uniform sampler2D tex;
        out vec4 colour;
        void main() {
            colour = texture(tex, uv);
        }", None
    ).unwrap();

    let mut pos = vec3(0.0, 0.0, -30.0);
    let mut rot = vec2(0.0, 0.0);
    const DELTA: f32 = 0.016;

    thin_engine::run(event_loop, &mut input, |input| {
        // using a small resolution to show the effect.
        // `let size = window.inner_size().into();` 
        // can be used isntead to set resolution to window size
        let size = (380, 216);
        display.resize(size);
        depth.resize_to_display(&display);
        colour.resize_to_display(&display);

        //press f to toggle FXAA
        if input.pressed(FXAA) { fxaa_on = !fxaa_on }

        let colour = colour.texture.as_ref().unwrap();
        let depth = depth.texture.as_ref().unwrap();
        let mut frame = SimpleFrameBuffer::with_depth_buffer(
            &display, colour, depth
        ).unwrap();

        let view = Mat4::view_matrix_3d(size, 1.0, 1024.0, 0.1);        
        //set camera rotation
        rot += input.mouse_move.scale(DELTA * 2.0);
        rot.y = rot.y.clamp(-PI / 2.0, PI / 2.0);
        let rx = Quaternion::from_y_rotation(rot.x);
        let ry = Quaternion::from_x_rotation(rot.y);
        let rot = rx * ry;

        //move player based on view
        let x = input.axis(Right, Left);
        let y = input.axis(Forward, Back);
        let move_dir = vec3(x, 0.0, y).normalise().scale(5.0*DELTA);
        pos += move_dir.transform(&Mat3::from_rot(rx));

        frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        //draw teapot
        frame.draw(
            teapot_mesh, &indices,
            &program, &uniform! {
                view: view,
                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: 10.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();
        thread::sleep(Duration::from_millis(16));
    }).unwrap();
}

Auto Trait Implementations§

§

impl<const BINDS: usize> Freeze for InputMap<BINDS>

§

impl<const BINDS: usize> RefUnwindSafe for InputMap<BINDS>

§

impl<const BINDS: usize> Send for InputMap<BINDS>

§

impl<const BINDS: usize> Sync for InputMap<BINDS>

§

impl<const BINDS: usize> Unpin for InputMap<BINDS>

§

impl<const BINDS: usize> UnwindSafe for InputMap<BINDS>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Downcast for T
where T: Any,

source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more