MayaFlux 0.4.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 default:
54 "ViewportPresetMode {} is not yet implemented",
55 static_cast<int>(mode));
56 }
57}
58
60 const std::shared_ptr<Core::Window>& window,
62 const std::string& name)
63{
64 for (const auto& buf : window->get_rendering_buffers()) {
65 auto rp = buf->get_render_processor();
66 if (!rp)
67 continue;
68 bind_viewport_preset(window, rp, mode, name);
69 }
70}
71
73 const std::shared_ptr<Core::Window>& window,
74 const std::shared_ptr<Buffers::RenderProcessor>& processor,
75 const ViewportPresetConfig& config,
76 const Kinesis::FlyKeyMap& key_map,
77 const std::string& name)
78{
79 auto& record = s_registry[make_key(window, name)];
80 record.saved_config = window->get_input_config();
81 record.registered_events.clear();
82
83 auto st = std::make_shared<Kinesis::NavigationState>(
85
86 on_mouse_pressed(window, IO::MouseButtons::Right, [st](double /*x*/, double /*y*/) {
87 st->rmb_held = true;
88 st->first_mouse = true; }, event_name(name, "rmb_dn"));
89
90 on_mouse_released(window, IO::MouseButtons::Right, [st](double /*x*/, double /*y*/) { st->rmb_held = false; }, event_name(name, "rmb_up"));
91
92 on_key_pressed(window, key_map.forward, [st] { st->forward_held = true; }, event_name(name, "fwd_dn"));
93 on_key_released(window, key_map.forward, [st] { st->forward_held = false; }, event_name(name, "fwd_up"));
94 on_key_pressed(window, key_map.back, [st] { st->back_held = true; }, event_name(name, "bck_dn"));
95 on_key_released(window, key_map.back, [st] { st->back_held = false; }, event_name(name, "bck_up"));
96 on_key_pressed(window, key_map.left, [st] { st->left_held = true; }, event_name(name, "lft_dn"));
97 on_key_released(window, key_map.left, [st] { st->left_held = false; }, event_name(name, "lft_up"));
98 on_key_pressed(window, key_map.right, [st] { st->right_held = true; }, event_name(name, "rgt_dn"));
99 on_key_released(window, key_map.right, [st] { st->right_held = false; }, event_name(name, "rgt_up"));
100 on_key_pressed(window, key_map.down, [st] { st->down_held = true; }, event_name(name, "dwn_dn"));
101 on_key_released(window, key_map.down, [st] { st->down_held = false; }, event_name(name, "dwn_up"));
102 on_key_pressed(window, key_map.up, [st] { st->up_held = true; }, event_name(name, "up_dn"));
103 on_key_released(window, key_map.up, [st] { st->up_held = false; }, event_name(name, "up_up"));
104
105 if (key_map.ortho_front)
106 on_key_pressed(window, *key_map.ortho_front, [st] { Kinesis::snap_ortho(*st, 0); }, event_name(name, "kp_front"));
107 if (key_map.ortho_right)
108 on_key_pressed(window, *key_map.ortho_right, [st] { Kinesis::snap_ortho(*st, 1); }, event_name(name, "kp_right"));
109 if (key_map.ortho_top)
110 on_key_pressed(window, *key_map.ortho_top, [st] { Kinesis::snap_ortho(*st, 2); }, event_name(name, "kp_top"));
111 if (key_map.ortho_flip)
112 on_key_pressed(window, *key_map.ortho_flip, [st] { Kinesis::snap_ortho(*st, 3); }, event_name(name, "kp_flip"));
113
114 on_mouse_move(window, [st](double x, double y) {
115 if (!st->rmb_held) {
116 st->first_mouse = true;
117 return;
118 }
119 if (st->first_mouse) {
120 st->last_x = x;
121 st->last_y = y;
122 st->first_mouse = false;
123 return;
124 }
126 static_cast<float>(x - st->last_x),
127 static_cast<float>(y - st->last_y));
128 st->last_x = x;
129 st->last_y = y; }, event_name(name, "mouse"));
130
131 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
132
133 processor->set_view_transform_source(
134 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
135 auto win = window_weak.lock();
136 if (!win) {
137 return {};
138 }
139 const auto& ws = win->get_state();
140 const float aspect = (ws.current_height > 0)
141 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
142 : 1.0F;
143 return Kinesis::compute_view_transform(*st, aspect);
144 });
145}
146
148 const std::shared_ptr<Core::Window>& window,
149 const ViewportPresetConfig& config,
150 const Kinesis::FlyKeyMap& key_map,
151 const std::string& name)
152{
153 for (const auto& buf : window->get_rendering_buffers()) {
154 auto rp = buf->get_render_processor();
155 if (!rp) {
156 continue;
157 }
158 bind_fly_preset(window, rp, config, key_map, name);
159 }
160}
161
163 const std::shared_ptr<Core::Window>& window,
164 const std::shared_ptr<Buffers::RenderProcessor>& processor,
165 const Kinesis::OrbitConfig& config,
166 const Kinesis::OrbitKeyMap& key_map,
167 const std::string& name)
168{
169 auto& record = s_registry[make_key(window, name)];
170 record.saved_config = window->get_input_config();
171 record.registered_events.clear();
172
173 auto st = std::make_shared<Kinesis::OrbitState>(Kinesis::make_orbit_state(config));
174
175 on_mouse_pressed(window, IO::MouseButtons::Middle, [st](double /*x*/, double /*y*/) {
176 st->mmb_held = true;
177 st->first_mouse = true; }, event_name(name, "mmb_dn"));
178
179 on_mouse_released(window, IO::MouseButtons::Middle, [st](double /*x*/, double /*y*/) { st->mmb_held = false; }, event_name(name, "mmb_up"));
180
181 on_key_pressed(window, key_map.pan_modifier, [st] { st->pan_held = true; }, event_name(name, "pan_mod_dn"));
182 on_key_released(window, key_map.pan_modifier, [st] { st->pan_held = false; }, event_name(name, "pan_mod_up"));
183
184 on_mouse_move(window, [st](double x, double y) {
185 if (!st->mmb_held) {
186 st->first_mouse = true;
187 return;
188 }
189 if (st->first_mouse) {
190 st->last_x = x;
191 st->last_y = y;
192 st->first_mouse = false;
193 return;
194 }
195 const auto dx = static_cast<float>(x - st->last_x);
196 const auto dy = static_cast<float>(y - st->last_y);
197 st->last_x = x;
198 st->last_y = y;
199
200 if (st->pan_held) {
201 Kinesis::apply_orbit_pan(*st, dx, dy);
202 } else {
203 Kinesis::apply_orbit_rotate(*st, dx, dy);
204} }, event_name(name, "mouse"));
205
206 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_orbit_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
207
208 if (key_map.ortho_front)
209 on_key_pressed(window, *key_map.ortho_front, [st] { Kinesis::snap_orbit_ortho(*st, 0); }, event_name(name, "kp_front"));
210 if (key_map.ortho_right)
211 on_key_pressed(window, *key_map.ortho_right, [st] { Kinesis::snap_orbit_ortho(*st, 1); }, event_name(name, "kp_right"));
212 if (key_map.ortho_top)
213 on_key_pressed(window, *key_map.ortho_top, [st] { Kinesis::snap_orbit_ortho(*st, 2); }, event_name(name, "kp_top"));
214 if (key_map.ortho_flip)
215 on_key_pressed(window, *key_map.ortho_flip, [st] { Kinesis::snap_orbit_ortho(*st, 3); }, event_name(name, "kp_flip"));
216
217 processor->set_view_transform_source(
218 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
219 auto win = window_weak.lock();
220 if (!win)
221 return {};
222 const auto& ws = win->get_state();
223 const float aspect = (ws.current_height > 0)
224 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
225 : 1.0F;
226 return Kinesis::compute_orbit_view_transform(*st, aspect);
227 });
228}
229
231 const std::shared_ptr<Core::Window>& window,
232 const Kinesis::OrbitConfig& config,
233 const Kinesis::OrbitKeyMap& key_map,
234 const std::string& name)
235{
236 for (const auto& buf : window->get_rendering_buffers()) {
237 auto rp = buf->get_render_processor();
238 if (!rp)
239 continue;
240 bind_orbit_preset(window, rp, config, key_map, name);
241 }
242}
243
245 const std::shared_ptr<Core::Window>& window,
246 const std::shared_ptr<Buffers::RenderProcessor>& processor,
247 const Kinesis::PanZoom2DConfig& config,
248 const Kinesis::PanZoom2DKeyMap& key_map,
249 const std::string& name)
250{
251 auto& record = s_registry[make_key(window, name)];
252 record.saved_config = window->get_input_config();
253 record.registered_events.clear();
254
255 auto st = std::make_shared<Kinesis::PanZoom2DState>(Kinesis::make_pan_zoom_state(config));
256
257 on_mouse_pressed(window, key_map.drag_button, [st](double /*x*/, double /*y*/) {
258 st->drag_held = true;
259 st->first_mouse = true; }, event_name(name, "drag_dn"));
260
261 on_mouse_released(window, key_map.drag_button, [st](double /*x*/, double /*y*/) { st->drag_held = false; }, event_name(name, "drag_up"));
262
263 on_mouse_move(window, [st, window_weak = std::weak_ptr<Core::Window>(window)](double x, double y) {
264 if (!st->drag_held) {
265 st->first_mouse = true;
266 return;
267 }
268 if (st->first_mouse) {
269 st->last_x = x;
270 st->last_y = y;
271 st->first_mouse = false;
272 return;
273 }
274 const auto dx = static_cast<float>(x - st->last_x);
275 const auto dy = static_cast<float>(y - st->last_y);
276 st->last_x = x;
277 st->last_y = y;
278
279 auto win = window_weak.lock();
280 if (!win)
281 return;
282 const auto& ws = win->get_state();
283 if (ws.current_width > 0 && ws.current_height > 0) {
284 Kinesis::apply_pan_zoom_pan(*st, dx, dy,
285 static_cast<float>(ws.current_width),
286 static_cast<float>(ws.current_height));
287 } }, event_name(name, "mouse"));
288
289 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_pan_zoom_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
290
291 processor->set_view_transform_source(
292 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
293 auto win = window_weak.lock();
294 if (!win)
295 return {};
296 const auto& ws = win->get_state();
297 const float aspect = (ws.current_height > 0)
298 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
299 : 1.0F;
301 });
302}
303
305 const std::shared_ptr<Core::Window>& window,
306 const Kinesis::PanZoom2DConfig& config,
307 const Kinesis::PanZoom2DKeyMap& key_map,
308 const std::string& name)
309{
310 for (const auto& buf : window->get_rendering_buffers()) {
311 auto rp = buf->get_render_processor();
312 if (!rp)
313 continue;
314 bind_pan_zoom_preset(window, rp, config, key_map, name);
315 }
316}
317
319 const std::shared_ptr<Core::Window>& window,
320 const std::shared_ptr<Buffers::RenderProcessor>& processor,
321 const Kinesis::NavigationConfig& config,
322 const Kinesis::ScreenspaceKeyMap& key_map,
323 const std::string& name)
324{
325 auto& record = s_registry[make_key(window, name)];
326 record.saved_config = window->get_input_config();
327 record.registered_events.clear();
328
329 auto st = std::make_shared<Kinesis::NavigationState>(
331
332 on_mouse_pressed(window, key_map.drag_button, [st](double /*x*/, double /*y*/) {
333 st->rmb_held = true;
334 st->first_mouse = true; }, event_name(name, "drag_dn"));
335
336 on_mouse_released(window, key_map.drag_button, [st](double /*x*/, double /*y*/) { st->rmb_held = false; }, event_name(name, "drag_up"));
337
338 on_mouse_move(window, [st](double x, double y) {
339 if (!st->rmb_held) {
340 st->first_mouse = true;
341 return;
342 }
343 if (st->first_mouse) {
344 st->last_x = x;
345 st->last_y = y;
346 st->first_mouse = false;
347 return;
348 }
349 const auto dx = static_cast<float>(x - st->last_x);
350 const auto dy = static_cast<float>(y - st->last_y);
351 st->last_x = x;
352 st->last_y = y;
353
354 const glm::vec3 forward {
355 std::cos(st->pitch) * std::sin(st->yaw),
356 std::sin(st->pitch),
357 std::cos(st->pitch) * std::cos(st->yaw)
358 };
359 const glm::vec3 right = glm::normalize(glm::cross(forward, glm::vec3(0.0F, 1.0F, 0.0F)));
360 const glm::vec3 up = glm::normalize(glm::cross(right, forward));
361
362 st->eye -= right * (dx * st->mouse_sensitivity);
363 st->eye += up * (dy * st->mouse_sensitivity); }, event_name(name, "mouse"));
364
365 on_scroll(window, [st](double /*dx*/, double dy) { Kinesis::apply_scroll(*st, static_cast<float>(dy)); }, event_name(name, "scroll"));
366
367 processor->set_view_transform_source(
368 [st, window_weak = std::weak_ptr<Core::Window>(window)]() -> Kinesis::ViewTransform {
369 auto win = window_weak.lock();
370 if (!win)
371 return {};
372 const auto& ws = win->get_state();
373 const float aspect = (ws.current_height > 0)
374 ? static_cast<float>(ws.current_width) / static_cast<float>(ws.current_height)
375 : 1.0F;
376 return Kinesis::build_view_transform(*st, aspect);
377 });
378}
379
381 const std::shared_ptr<Core::Window>& window,
382 const Kinesis::NavigationConfig& config,
383 const Kinesis::ScreenspaceKeyMap& key_map,
384 const std::string& name)
385{
386 for (const auto& buf : window->get_rendering_buffers()) {
387 auto rp = buf->get_render_processor();
388 if (!rp)
389 continue;
390 bind_screenspace_preset(window, rp, config, key_map, name);
391 }
392}
393
395 const std::shared_ptr<Core::Window>& window,
396 const std::string& name)
397{
398 const std::string key = make_key(window, name);
399 auto it = s_registry.find(key);
400 if (it == s_registry.end())
401 return;
402
403 window->set_input_config(it->second.saved_config);
404
405 for (const auto& ev : it->second.registered_events)
407
408 s_registry.erase(it);
409}
410
411} // namespace MayaFlux
#define MF_RT_ERROR(comp, ctx,...)
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].
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.
ViewTransform build_view_transform(const NavigationState &st, float aspect)
Build a ViewTransform from the current NavigationState without mutating it.
bool cancel_event_handler(const std::string &name)
Cancel an event handler by name.
Definition Chronie.cpp:266
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:217
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:250
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:183
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:150
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:200
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:133
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.