MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ViewportPreset.cpp
Go to the documentation of this file.
1#include "ViewportPreset.hpp"
2
3#include "Chronie.hpp"
4
8
10
11namespace MayaFlux {
12
13namespace {
14
15 struct PresetRecord {
16 Core::InputConfig saved_config;
17 std::vector<std::string> registered_events;
18 };
19
20 std::unordered_map<std::string, PresetRecord> s_registry;
21
22 std::string make_key(const std::shared_ptr<Core::Window>& window, const std::string& name)
23 {
24 return std::to_string(reinterpret_cast<uintptr_t>(window.get())) + "_" + name;
25 }
26
27 std::string event_name(const std::string& prefix, const char* suffix)
28 {
29 return "vp_" + prefix + "_" + suffix;
30 }
31
32} // namespace
33
35 const std::shared_ptr<Core::Window>& window,
36 const std::shared_ptr<Buffers::RenderProcessor>& processor,
38 const std::string& name)
39{
40 switch (mode) {
42 bind_fly_preset(window, processor, {}, {}, name);
43 return;
45 bind_orbit_preset(window, processor, {}, {}, name);
46 return;
48 bind_pan_zoom_preset(window, processor, {}, {}, name);
49 return;
51 bind_screenspace_preset(window, processor, {}, {}, name);
52 return;
53 default:
55 "ViewportPresetMode {} is not yet implemented",
56 static_cast<int>(mode));
57 }
58}
59
61 const std::shared_ptr<Core::Window>& window,
63 const std::string& name)
64{
65 for (const auto& buf : window->get_rendering_buffers()) {
66 auto rp = buf->get_render_processor();
67 if (!rp)
68 continue;
70 }
71}
72
74 const std::shared_ptr<Core::Window>& window,
75 const std::shared_ptr<Buffers::RenderProcessor>& processor,
76 const ViewportPresetConfig& config,
77 const Kinesis::FlyKeyMap& key_map,
78 const std::string& name)
79{
80 auto& record = s_registry[make_key(window, name)];
81 record.saved_config = window->get_input_config();
82 record.registered_events.clear();
83
84 auto st = std::make_shared<Kinesis::NavigationState>(
86
87 on_mouse_pressed(window, IO::MouseButtons::Right, [st](double /*x*/, double /*y*/) {
88 st->rmb_held = true;
89 st->first_mouse = true; }, event_name(name, "rmb_dn"));
90
91 on_mouse_released(window, IO::MouseButtons::Right, [st](double /*x*/, double /*y*/) { st->rmb_held = false; }, event_name(name, "rmb_up"));
92
93 on_key_pressed(window, key_map.forward, [st] { st->forward_held = true; }, event_name(name, "fwd_dn"));
94 on_key_released(window, key_map.forward, [st] { st->forward_held = false; }, event_name(name, "fwd_up"));
95 on_key_pressed(window, key_map.back, [st] { st->back_held = true; }, event_name(name, "bck_dn"));
96 on_key_released(window, key_map.back, [st] { st->back_held = false; }, event_name(name, "bck_up"));
97 on_key_pressed(window, key_map.left, [st] { st->left_held = true; }, event_name(name, "lft_dn"));
98 on_key_released(window, key_map.left, [st] { st->left_held = false; }, event_name(name, "lft_up"));
99 on_key_pressed(window, key_map.right, [st] { st->right_held = true; }, event_name(name, "rgt_dn"));
100 on_key_released(window, key_map.right, [st] { st->right_held = false; }, event_name(name, "rgt_up"));
101 on_key_pressed(window, key_map.down, [st] { st->down_held = true; }, event_name(name, "dwn_dn"));
102 on_key_released(window, key_map.down, [st] { st->down_held = false; }, event_name(name, "dwn_up"));
103 on_key_pressed(window, key_map.up, [st] { st->up_held = true; }, event_name(name, "up_dn"));
104 on_key_released(window, key_map.up, [st] { st->up_held = false; }, event_name(name, "up_up"));
105
106 if (key_map.ortho_front)
107 on_key_pressed(window, *key_map.ortho_front, [st] { Kinesis::snap_ortho(*st, 0); }, event_name(name, "kp_front"));
108 if (key_map.ortho_right)
109 on_key_pressed(window, *key_map.ortho_right, [st] { Kinesis::snap_ortho(*st, 1); }, event_name(name, "kp_right"));
110 if (key_map.ortho_top)
111 on_key_pressed(window, *key_map.ortho_top, [st] { Kinesis::snap_ortho(*st, 2); }, event_name(name, "kp_top"));
112 if (key_map.ortho_flip)
113 on_key_pressed(window, *key_map.ortho_flip, [st] { Kinesis::snap_ortho(*st, 3); }, event_name(name, "kp_flip"));
114
115 on_mouse_move(window, [st](double x, double y) {
116 if (!st->rmb_held) {
117 st->first_mouse = true;
118 return;
119 }
120 if (st->first_mouse) {
121 st->last_x = x;
122 st->last_y = y;
123 st->first_mouse = false;
124 return;
125 }
127 static_cast<float>(x - st->last_x),
128 static_cast<float>(y - st->last_y));
129 st->last_x = x;
130 st->last_y = y; }, event_name(name, "mouse"));
131
132 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
133
134 processor->set_view_transform_source(
135 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
136 auto win = window_weak.lock();
137 if (!win) {
138 return {};
139 }
140 const auto& ws = win->get_state();
141 const float aspect = (ws.current_height > 0)
142 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
143 : 1.0F;
144 return Kinesis::compute_view_transform(*st, aspect);
145 });
146}
147
149 const std::shared_ptr<Core::Window>& window,
150 const ViewportPresetConfig& config,
151 const Kinesis::FlyKeyMap& key_map,
152 const std::string& name)
153{
154 for (const auto& buf : window->get_rendering_buffers()) {
155 auto rp = buf->get_render_processor();
156 if (!rp) {
157 continue;
158 }
159 bind_fly_preset(window, rp, config, key_map, name);
160 }
161}
162
164 const std::shared_ptr<Core::Window>& window,
165 const std::shared_ptr<Buffers::RenderProcessor>& processor,
166 const Kinesis::OrbitConfig& config,
167 const Kinesis::OrbitKeyMap& key_map,
168 const std::string& name)
169{
170 auto& record = s_registry[make_key(window, name)];
171 record.saved_config = window->get_input_config();
172 record.registered_events.clear();
173
174 auto st = std::make_shared<Kinesis::OrbitState>(Kinesis::make_orbit_state(config));
175
176 on_mouse_pressed(window, IO::MouseButtons::Middle, [st](double /*x*/, double /*y*/) {
177 st->mmb_held = true;
178 st->first_mouse = true; }, event_name(name, "mmb_dn"));
179
180 on_mouse_released(window, IO::MouseButtons::Middle, [st](double /*x*/, double /*y*/) { st->mmb_held = false; }, event_name(name, "mmb_up"));
181
182 on_key_pressed(window, key_map.pan_modifier, [st] { st->pan_held = true; }, event_name(name, "pan_mod_dn"));
183 on_key_released(window, key_map.pan_modifier, [st] { st->pan_held = false; }, event_name(name, "pan_mod_up"));
184
185 on_mouse_move(window, [st](double x, double y) {
186 if (!st->mmb_held) {
187 st->first_mouse = true;
188 return;
189 }
190 if (st->first_mouse) {
191 st->last_x = x;
192 st->last_y = y;
193 st->first_mouse = false;
194 return;
195 }
196 const auto dx = static_cast<float>(x - st->last_x);
197 const auto dy = static_cast<float>(y - st->last_y);
198 st->last_x = x;
199 st->last_y = y;
200
201 if (st->pan_held) {
202 Kinesis::apply_orbit_pan(*st, dx, dy);
203 } else {
204 Kinesis::apply_orbit_rotate(*st, dx, dy);
205} }, event_name(name, "mouse"));
206
207 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_orbit_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
208
209 if (key_map.ortho_front)
210 on_key_pressed(window, *key_map.ortho_front, [st] { Kinesis::snap_orbit_ortho(*st, 0); }, event_name(name, "kp_front"));
211 if (key_map.ortho_right)
212 on_key_pressed(window, *key_map.ortho_right, [st] { Kinesis::snap_orbit_ortho(*st, 1); }, event_name(name, "kp_right"));
213 if (key_map.ortho_top)
214 on_key_pressed(window, *key_map.ortho_top, [st] { Kinesis::snap_orbit_ortho(*st, 2); }, event_name(name, "kp_top"));
215 if (key_map.ortho_flip)
216 on_key_pressed(window, *key_map.ortho_flip, [st] { Kinesis::snap_orbit_ortho(*st, 3); }, event_name(name, "kp_flip"));
217
218 processor->set_view_transform_source(
219 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
220 auto win = window_weak.lock();
221 if (!win)
222 return {};
223 const auto& ws = win->get_state();
224 const float aspect = (ws.current_height > 0)
225 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
226 : 1.0F;
227 return Kinesis::compute_orbit_view_transform(*st, aspect);
228 });
229}
230
232 const std::shared_ptr<Core::Window>& window,
233 const Kinesis::OrbitConfig& config,
234 const Kinesis::OrbitKeyMap& key_map,
235 const std::string& name)
236{
237 for (const auto& buf : window->get_rendering_buffers()) {
238 auto rp = buf->get_render_processor();
239 if (!rp)
240 continue;
241 bind_orbit_preset(window, rp, config, key_map, name);
242 }
243}
244
246 const std::shared_ptr<Core::Window>& window,
247 const std::shared_ptr<Buffers::RenderProcessor>& processor,
248 const Kinesis::PanZoom2DConfig& config,
249 const Kinesis::PanZoom2DKeyMap& key_map,
250 const std::string& name)
251{
252 auto& record = s_registry[make_key(window, name)];
253 record.saved_config = window->get_input_config();
254 record.registered_events.clear();
255
256 auto st = std::make_shared<Kinesis::PanZoom2DState>(Kinesis::make_pan_zoom_state(config));
257
258 on_mouse_pressed(window, key_map.drag_button, [st](double /*x*/, double /*y*/) {
259 st->drag_held = true;
260 st->first_mouse = true; }, event_name(name, "drag_dn"));
261
262 on_mouse_released(window, key_map.drag_button, [st](double /*x*/, double /*y*/) { st->drag_held = false; }, event_name(name, "drag_up"));
263
264 on_mouse_move(window, [st, window_weak = std::weak_ptr<Core::Window>(window)](double x, double y) {
265 if (!st->drag_held) {
266 st->first_mouse = true;
267 return;
268 }
269 if (st->first_mouse) {
270 st->last_x = x;
271 st->last_y = y;
272 st->first_mouse = false;
273 return;
274 }
275 const auto dx = static_cast<float>(x - st->last_x);
276 const auto dy = static_cast<float>(y - st->last_y);
277 st->last_x = x;
278 st->last_y = y;
279
280 auto win = window_weak.lock();
281 if (!win)
282 return;
283 const auto& ws = win->get_state();
284 if (ws.current_width > 0 && ws.current_height > 0) {
285 Kinesis::apply_pan_zoom_pan(*st, dx, dy,
286 static_cast<float>(ws.current_width),
287 static_cast<float>(ws.current_height));
288 } }, event_name(name, "mouse"));
289
290 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_pan_zoom_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
291
292 processor->set_view_transform_source(
293 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
294 auto win = window_weak.lock();
295 if (!win)
296 return {};
297 const auto& ws = win->get_state();
298 const float aspect = (ws.current_height > 0)
299 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
300 : 1.0F;
302 });
303}
304
306 const std::shared_ptr<Core::Window>& window,
307 const Kinesis::PanZoom2DConfig& config,
308 const Kinesis::PanZoom2DKeyMap& key_map,
309 const std::string& name)
310{
311 for (const auto& buf : window->get_rendering_buffers()) {
312 auto rp = buf->get_render_processor();
313 if (!rp)
314 continue;
315 bind_pan_zoom_preset(window, rp, config, key_map, name);
316 }
317}
318
320 const std::shared_ptr<Core::Window>& window,
321 const std::shared_ptr<Buffers::RenderProcessor>& processor,
322 const Kinesis::NavigationConfig& config,
323 const Kinesis::ScreenspaceKeyMap& key_map,
324 const std::string& name)
325{
326 auto& record = s_registry[make_key(window, name)];
327 record.saved_config = window->get_input_config();
328 record.registered_events.clear();
329
330 auto st = std::make_shared<Kinesis::NavigationState>(
332
333 on_mouse_pressed(window, key_map.drag_button, [st](double /*x*/, double /*y*/) {
334 st->rmb_held = true;
335 st->first_mouse = true; }, event_name(name, "drag_dn"));
336
337 on_mouse_released(window, key_map.drag_button, [st](double /*x*/, double /*y*/) { st->rmb_held = false; }, event_name(name, "drag_up"));
338
339 on_mouse_move(window, [st](double x, double y) {
340 if (!st->rmb_held) {
341 st->first_mouse = true;
342 return;
343 }
344 if (st->first_mouse) {
345 st->last_x = x;
346 st->last_y = y;
347 st->first_mouse = false;
348 return;
349 }
350 const auto dx = static_cast<float>(x - st->last_x);
351 const auto dy = static_cast<float>(y - st->last_y);
352 st->last_x = x;
353 st->last_y = y;
354
355 const glm::vec3 forward {
356 std::cos(st->pitch) * std::sin(st->yaw),
357 std::sin(st->pitch),
358 std::cos(st->pitch) * std::cos(st->yaw)
359 };
360 const glm::vec3 right = glm::normalize(glm::cross(forward, glm::vec3(0.0F, 1.0F, 0.0F)));
361 const glm::vec3 up = glm::normalize(glm::cross(right, forward));
362
363 st->eye -= right * (dx * st->mouse_sensitivity);
364 st->eye += up * (dy * st->mouse_sensitivity); }, event_name(name, "mouse"));
365
366 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
367
368 processor->set_view_transform_source(
369 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
370 auto win = window_weak.lock();
371 if (!win)
372 return {};
373 const auto& ws = win->get_state();
374 const float aspect = (ws.current_height > 0)
375 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
376 : 1.0F;
377 return Kinesis::build_view_transform(*st, aspect);
378 });
379}
380
382 const std::shared_ptr<Core::Window>& window,
383 const Kinesis::NavigationConfig& config,
384 const Kinesis::ScreenspaceKeyMap& key_map,
385 const std::string& name)
386{
387 for (const auto& buf : window->get_rendering_buffers()) {
388 auto rp = buf->get_render_processor();
389 if (!rp)
390 continue;
391 bind_screenspace_preset(window, rp, config, key_map, name);
392 }
393}
394
396 const std::shared_ptr<Core::Window>& window,
397 const std::string& name)
398{
399 const std::string key = make_key(window, name);
400 auto it = s_registry.find(key);
401 if (it == s_registry.end())
402 return;
403
404 window->set_input_config(it->second.saved_config);
405
406 for (const auto& ev : it->second.registered_events)
408
409 s_registry.erase(it);
410}
411
412} // namespace MayaFlux
#define MF_RT_ERROR(comp, ctx,...)
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
uint32_t mode
std::string name
Definition VKDevice.cpp:123
std::vector< std::string > registered_events
Core::InputConfig saved_config
@ EventDispatch
Event dispatching and coordination.
@ API
MayaFlux/API Wrapper and convenience functions.
void apply_orbit_rotate(OrbitState &st, float dx, float dy)
Apply a mouse delta to azimuth and elevation.
ViewTransform compute_pan_zoom_view_transform(const PanZoom2DState &st, float aspect)
Build a ViewTransform from the current PanZoom2DState.
PanZoom2DState make_pan_zoom_state(const PanZoom2DConfig &config)
Construct a PanZoom2DState from a PanZoom2DConfig.
void apply_pan_zoom_scroll(PanZoom2DState &st, float ticks)
Zoom by multiplying the half-height, clamped to [min_zoom, max_zoom].
ViewTransform build_view_transform(const NavigationState &st, float aspect)
Build a ViewTransform from the current NavigationState without mutating it.
void apply_pan_zoom_pan(PanZoom2DState &st, float dx, float dy, float viewport_width, float viewport_height)
Pan by a pixel delta, scaled to world units by the current zoom level.
void apply_scroll(NavigationState &st, float ticks)
Dolly eye along the current forward vector.
void apply_orbit_scroll(OrbitState &st, float ticks)
Dolly the camera toward or away from the focal point.
ViewTransform compute_orbit_view_transform(const OrbitState &st, float aspect)
Build a ViewTransform from the current OrbitState.
NavigationState make_navigation_state(const NavigationConfig &config)
Construct a NavigationState from a NavigationConfig.
void apply_orbit_pan(OrbitState &st, float dx, float dy)
Pan the focal point in the camera's local right/up plane.
ViewTransform compute_view_transform(NavigationState &st, float aspect)
Compute a ViewTransform from the current NavigationState.
OrbitState make_orbit_state(const OrbitConfig &config)
Construct an OrbitState from an OrbitConfig.
Definition OrbitState.cpp:5
void apply_mouse_delta(NavigationState &st, float dx, float dy)
Apply a mouse delta to yaw and pitch.
bool cancel_event_handler(const std::string &name)
Cancel an event handler by name.
Definition Chronie.cpp:280
void on_mouse_move(const std::shared_ptr< Core::Window > &window, std::function< void(double, double)> callback, std::string name)
Schedule a mouse movement handler.
Definition Chronie.cpp:231
void on_scroll(const std::shared_ptr< Core::Window > &window, std::function< void(double, double)> callback, std::string name)
Schedule a mouse scroll handler.
Definition Chronie.cpp:264
void bind_screenspace_preset(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< Buffers::RenderProcessor > &processor, const Kinesis::NavigationConfig &config, const Kinesis::ScreenspaceKeyMap &key_map, const std::string &name)
Bind the screenspace navigation controller to a window and render processor.
ViewportPresetMode
Selects which navigation controller bind_viewport_preset installs.
@ PanZoom2D
Orthographic 2D pan and zoom (not yet implemented)
@ Orbit
Tumble around a focal point (not yet implemented)
@ Fly
First-person fly: WASD/QE translate, RMB drag yaw/pitch, scroll dolly, KP ortho snaps.
@ Screenspace
Perspective pan in camera's local right/up plane, scroll dolly, no rotation.
void on_mouse_pressed(const std::shared_ptr< Core::Window > &window, IO::MouseButtons button, std::function< void(double, double)> callback, std::string name)
Schedule a mouse button press handler.
Definition Chronie.cpp:197
void bind_viewport_preset(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< Buffers::RenderProcessor > &processor, ViewportPresetMode mode, const std::string &name)
Bind a navigation preset to a window and render processor using default settings.
void on_key_released(const std::shared_ptr< Core::Window > &window, IO::Keys key, std::function< void()> callback, std::string name)
Schedule a key release handler.
Definition Chronie.cpp:164
void bind_pan_zoom_preset(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< Buffers::RenderProcessor > &processor, const Kinesis::PanZoom2DConfig &config, const Kinesis::PanZoom2DKeyMap &key_map, const std::string &name)
Bind the 2D pan/zoom controller to a window and render processor.
void on_mouse_released(const std::shared_ptr< Core::Window > &window, IO::MouseButtons button, std::function< void(double, double)> callback, std::string name)
Schedule a mouse button release handler.
Definition Chronie.cpp:214
void bind_orbit_preset(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< Buffers::RenderProcessor > &processor, const Kinesis::OrbitConfig &config, const Kinesis::OrbitKeyMap &key_map, const std::string &name)
Bind the orbit navigation controller to a window and render processor.
void unbind_viewport_preset(const std::shared_ptr< Core::Window > &window, const std::string &name)
Cancel all event handlers registered by bind_viewport_preset() and restore the window input config to...
void on_key_pressed(const std::shared_ptr< Core::Window > &window, IO::Keys key, std::function< void()> callback, std::string name)
Schedule a key press handler.
Definition Chronie.cpp:147
void bind_fly_preset(const std::shared_ptr< Core::Window > &window, const std::shared_ptr< Buffers::RenderProcessor > &processor, const ViewportPresetConfig &config, const Kinesis::FlyKeyMap &key_map, const std::string &name)
Bind the fly navigation controller to a window and render processor.
Main namespace for the Maya Flux audio engine.
Definition Runtime.cpp:12
std::optional< IO::Keys > ortho_top
Snap to top (+Y) view.
std::optional< IO::Keys > ortho_right
Snap to right (+X) view.
std::optional< IO::Keys > ortho_flip
Flip to opposite view.
std::optional< IO::Keys > ortho_front
Snap to front (+Z) view.
Key assignments for the Fly navigation preset.
Tuning parameters for a first-person fly-navigation controller.
Construction parameters for an orbit navigation controller.
std::optional< IO::Keys > ortho_right
IO::Keys pan_modifier
Held during MMB drag to pan instead of rotate.
std::optional< IO::Keys > ortho_flip
std::optional< IO::Keys > ortho_front
std::optional< IO::Keys > ortho_top
Key assignments for the Orbit navigation preset.
Construction parameters for a 2D pan/zoom orthographic controller.
IO::MouseButtons drag_button
Button held to pan.
Input assignments for the PanZoom2D navigation preset.
IO::MouseButtons drag_button
Button held to pan.
Input assignments for the Screenspace navigation preset.
View and projection matrices as a named push constant slot.