1use pfx_core::clock::Tick;
2use pfx_input::{ActionSpec, Binding, Input, Key};
3use pfx_load::scene::{Camera, Matrix};
4use pfx_play::{Game, SceneGame, World};
5
6pub const MOVE_SPEED: f32 = 2.0;
7pub const TURN_SPEED: f32 = 60.0;
8
9pub fn actions() -> Vec<ActionSpec> {
10 vec![
11 ActionSpec::axis("walk").key(Binding::keys(Key::S, Key::W)),
12 ActionSpec::axis("strafe").key(Binding::keys(Key::A, Key::D)),
13 ActionSpec::axis("lift").key(Binding::keys(Key::Q, Key::E)),
14 ActionSpec::axis("turn").key(Binding::keys(Key::Left, Key::Right)),
15 ActionSpec::axis("tilt").key(Binding::keys(Key::Down, Key::Up)),
16 ]
17}
18
19fn add(a: [f32; 3], b: [f32; 3], scale: f32) -> [f32; 3] {
20 [
21 a[0] + b[0] * scale,
22 a[1] + b[1] * scale,
23 a[2] + b[2] * scale,
24 ]
25}
26
27fn forward(yaw: f32, pitch: f32) -> [f32; 3] {
28 let (sy, cy) = yaw.sin_cos();
29 let (sp, cp) = pitch.sin_cos();
30 [cp * sy, sp, -cp * cy]
31}
32
33pub struct BenchGame {
34 scene: SceneGame,
35 camera: Option<String>,
36 yaw: f32,
37 pitch: f32,
38}
39
40impl BenchGame {
41 pub fn new(camera: Option<String>) -> Self {
42 Self {
43 scene: SceneGame,
44 camera,
45 yaw: 0.0,
46 pitch: 0.0,
47 }
48 }
49
50 fn aim(&mut self, world: &World) {
51 let camera = world.camera;
52 let (direction, _, _) = camera.axes();
53 self.yaw = direction[0].atan2(-direction[2]);
54 self.pitch = direction[1].clamp(-1.0, 1.0).asin();
55 }
56
57 fn look(&self, world: &mut World) {
58 let at = world.camera.at;
59 world.camera.look_at = add(at, forward(self.yaw, self.pitch), 1.0);
60 }
61}
62
63fn placed(model: Matrix, base: Camera) -> Camera {
64 let at = [model[3][0], model[3][1], model[3][2]];
65 let ahead = [-model[2][0], -model[2][1], -model[2][2]];
66 let up = [model[1][0], model[1][1], model[1][2]];
67 Camera {
68 at,
69 look_at: add(at, ahead, 1.0),
70 up,
71 ..base
72 }
73}
74
75impl Game for BenchGame {
76 fn actions(&self) -> Vec<ActionSpec> {
77 actions()
78 }
79
80 fn start(&mut self, world: &mut World) {
81 self.scene.start(world);
82 if let Some(id) = self.camera.as_deref().and_then(|name| world.object(name)) {
83 world.camera = placed(world.model(id), world.camera);
84 }
85 self.aim(world);
86 }
87
88 fn tick(&mut self, world: &mut World, tick: &Tick, input: &Input) {
89 self.scene.tick(world, tick, input);
90 let dt = tick.dt;
91 let walk = input.action("walk").value;
92 let strafe = input.action("strafe").value;
93 let lift = input.action("lift").value;
94 let turn = input.action("turn").value;
95 let tilt = input.action("tilt").value;
96 if walk == 0.0 && strafe == 0.0 && lift == 0.0 && turn == 0.0 && tilt == 0.0 {
97 return;
98 }
99 self.yaw += (turn * TURN_SPEED * dt).to_radians();
100 self.pitch = (self.pitch + (tilt * TURN_SPEED * dt).to_radians()).clamp(-1.5, 1.5);
101 let (ahead, right, _) = {
102 let mut aimed = world.camera;
103 aimed.look_at = add(aimed.at, forward(self.yaw, self.pitch), 1.0);
104 aimed.axes()
105 };
106 let mut at = world.camera.at;
107 at = add(at, ahead, walk * MOVE_SPEED * dt);
108 at = add(at, right, strafe * MOVE_SPEED * dt);
109 at = add(at, world.camera.up, lift * MOVE_SPEED * dt);
110 world.camera.at = at;
111 self.look(world);
112 }
113
114 fn stop(&mut self) {
115 self.scene.stop();
116 }
117}