Loading...
Searching...
No Matches
Window/WindowDevice.hpp
1#pragma once
2
3#include <Gfx/GfxParameter.hpp>
4#include <Gfx/Graph/ScreenNode.hpp>
5#include <Gfx/Graph/Window.hpp>
6#include <Gfx/Settings/Model.hpp>
7
8#include <core/application/ApplicationSettings.hpp>
9#include <score/application/ApplicationContext.hpp>
10
11#include <ossia/network/base/device.hpp>
12#include <ossia/network/base/protocol.hpp>
13#include <ossia/network/generic/generic_node.hpp>
14
15#include <ossia-qt/invoke.hpp>
16
17#include <QGuiApplication>
18
19namespace Gfx
20{
21
22static score::gfx::ScreenNode* createScreenNode(
23 SwapchainFlag swapFlag = SwapchainFlag::NoFlag,
24 SwapchainFormat swapFormat = SwapchainFormat::SDR)
25{
26 const auto& settings = score::AppContext().applicationSettings;
27 const auto& gfx_settings = score::AppContext().settings<Gfx::Settings::Model>();
28
29 auto make_configuration = [&] {
31 double rate = gfx_settings.getRate();
32 if(rate > 0)
33 conf = {.manualRenderingRate = 1000. / rate, .supportsVSync = true};
34 else
35 conf = {.manualRenderingRate = {}, .supportsVSync = true};
36 return conf;
37 };
38
39 auto node = new score::gfx::ScreenNode{
40 make_configuration(), false, (settings.autoplay && !settings.gui)};
41 node->setSwapchainFlag(swapFlag);
42 node->setSwapchainFormat(swapFormat);
43
44 QObject::connect(
45 &gfx_settings, &Gfx::Settings::Model::RateChanged, node,
46 [node, make_configuration] { node->setConfiguration(make_configuration()); });
47
48 return node;
49}
50class window_device : public ossia::net::device_base
51{
52 score::gfx::ScreenNode* m_screen{};
53 gfx_node_base m_root;
54 QObject m_qtContext;
55
56 ossia::net::parameter_base* scaled_win{};
57 ossia::net::parameter_base* gl_win{};
58 ossia::net::parameter_base* abs_win{};
59 ossia::net::parameter_base* abs_tablet_win{};
60 ossia::net::parameter_base* size_param{};
61 ossia::net::parameter_base* rendersize_param{};
62
63 void update_viewport()
64 {
65 auto v = rendersize_param->value();
66 if(auto val = v.target<ossia::vec2f>())
67 {
68 auto dom = abs_win->get_domain();
69 if((*val)[0] >= 1.f && (*val)[1] >= 1.f)
70 {
71 ossia::set_max(dom, *val);
72 abs_win->set_domain(std::move(dom));
73 abs_tablet_win->set_domain(std::move(dom));
74 }
75 else
76 {
77 // Use the normal size
78 v = size_param->value();
79 if(auto val = v.target<ossia::vec2f>())
80 {
81 auto dom = abs_win->get_domain();
82 if((*val)[0] >= 1.f && (*val)[1] >= 1.f)
83 {
84 ossia::set_max(dom, *val);
85 abs_win->set_domain(std::move(dom));
86 abs_tablet_win->set_domain(std::move(dom));
87 }
88 }
89 }
90 }
91 else
92 {
93 v = size_param->value();
94 if(auto val = v.target<ossia::vec2f>())
95 {
96 auto dom = abs_win->get_domain();
97 if((*val)[0] >= 1.f && (*val)[1] >= 1.f)
98 {
99 ossia::set_max(dom, *val);
100 abs_win->set_domain(std::move(dom));
101 abs_tablet_win->set_domain(std::move(dom));
102 }
103 }
104 }
105 }
106
107public:
108 score::gfx::ScreenNode* screen() const noexcept { return m_screen; }
110 {
111 if(auto w = m_screen->window())
112 w->close();
113
114 m_screen->onWindowMove = [](QPointF) { };
115 m_screen->onMouseMove = [](QPointF, QPointF) { };
116 m_screen->onTabletMove = [](QTabletEvent*) { };
117 m_screen->onKey = [](int, const QString&) { };
118 m_screen->onKeyRelease = [](int, const QString&) { };
119 m_screen->onFps = [](float) { };
120 m_protocol->stop();
121
122 m_root.clear_children();
123
124 m_protocol.reset();
125 }
126
128 std::unique_ptr<gfx_protocol_base> proto, std::string name,
129 SwapchainFlag swapFlag = SwapchainFlag::NoFlag,
130 SwapchainFormat swapFormat = SwapchainFormat::SDR)
131 : ossia::net::device_base{std::move(proto)}
132 , m_screen{createScreenNode(swapFlag, swapFormat)}
133 , m_root{*this, *static_cast<gfx_protocol_base*>(m_protocol.get()), m_screen, name}
134 {
135 this->m_capabilities.change_tree = true;
136 m_screen->setTitle(QString::fromStdString(name));
137
138 {
139 auto screen_node
140 = std::make_unique<ossia::net::generic_node>("screen", *this, m_root);
141 auto screen_param = screen_node->create_parameter(ossia::val_type::STRING);
142 screen_param->set_domain(ossia::make_domain(int(0), int(100)));
143 screen_param->add_callback([this](const ossia::value& v) {
144 if(auto val = v.target<int>())
145 {
146 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, scr = *val] {
147 const auto& cur_screens = qGuiApp->screens();
148 if(ossia::valid_index(scr, cur_screens))
149 {
150 screen->setScreen(cur_screens[scr]);
151 }
152 });
153 }
154 else if(auto val = v.target<std::string>())
155 {
156 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, scr = *val] {
157 const auto& cur_screens = qGuiApp->screens();
158 for(auto s : cur_screens)
159 {
160 if(s->name() == scr.c_str())
161 {
162 screen->setScreen(s);
163 break;
164 }
165 }
166 });
167 }
168 });
169 m_root.add_child(std::move(screen_node));
170 }
171
172 {
173 struct move_window_lock
174 {
175 bool locked{};
176 };
177 auto lock = std::make_shared<move_window_lock>();
178
179 auto pos_node
180 = std::make_unique<ossia::net::generic_node>("position", *this, m_root);
181 auto pos_param = pos_node->create_parameter(ossia::val_type::VEC2F);
182 pos_param->push_value(
183 ossia::vec2f{100.f, 100.f}); // FIXME Try to detect center of screen ?
184 pos_param->add_callback([this, lock](const ossia::value& v) {
185 if(lock->locked)
186 return;
187 if(auto val = v.target<ossia::vec2f>())
188 {
189 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, v = *val, lock] {
190 screen->setPosition({(int)v[0], (int)v[1]});
191 });
192 }
193 });
194
195 m_screen->onWindowMove = [this, pos_param, lock](QPointF pos) {
196 if(lock->locked)
197 return;
198 if(const auto& w = m_screen->window())
199 {
200 lock->locked = true;
201 pos_param->set_value(ossia::vec2f{float(pos.x()), float(pos.y())});
202 lock->locked = false;
203 }
204 };
205 m_root.add_child(std::move(pos_node));
206 }
207
208 // Mouse input
209 {
210 auto node = std::make_unique<ossia::net::generic_node>("cursor", *this, m_root);
211 {
212 auto scale_node
213 = std::make_unique<ossia::net::generic_node>("scaled", *this, *node);
214 scaled_win = scale_node->create_parameter(ossia::val_type::VEC2F);
215 scaled_win->set_domain(ossia::make_domain(0.f, 1.f));
216 scaled_win->push_value(ossia::vec2f{0.f, 0.f});
217 node->add_child(std::move(scale_node));
218 }
219 {
220 // Same as scaled but with y down like opengl
221 auto scale_node = std::make_unique<ossia::net::generic_node>("gl", *this, *node);
222 gl_win = scale_node->create_parameter(ossia::val_type::VEC2F);
223 gl_win->set_domain(ossia::make_domain(0.f, 1.f));
224 gl_win->push_value(ossia::vec2f{0.f, 0.f});
225 node->add_child(std::move(scale_node));
226 }
227 {
228 auto abs_node
229 = std::make_unique<ossia::net::generic_node>("absolute", *this, *node);
230 abs_win = abs_node->create_parameter(ossia::val_type::VEC2F);
231 abs_win->set_domain(
232 ossia::make_domain(ossia::vec2f{0.f, 0.f}, ossia::vec2f{1280, 270.f}));
233 abs_win->push_value(ossia::vec2f{0.f, 0.f});
234 node->add_child(std::move(abs_node));
235 }
236 {
237 auto visible
238 = std::make_unique<ossia::net::generic_node>("visible", *this, *node);
239 auto param = visible->create_parameter(ossia::val_type::BOOL);
240 param->add_callback([this](const ossia::value& v) {
241 if(auto val = v.target<bool>())
242 {
243 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, v = *val] {
244 screen->setCursor(v);
245 });
246 }
247 });
248 node->add_child(std::move(visible));
249 }
250
251 m_screen->onMouseMove = [this](const QPointF screen, const QPointF win) {
252 if(const auto& w = m_screen->window())
253 {
254 const auto sz = w->size();
255 scaled_win->push_value(
256 ossia::vec2f{float(win.x() / sz.width()), float(win.y() / sz.height())});
257 gl_win->push_value(
258 ossia::vec2f{
259 float(win.x() / sz.width()), 1.f - float(win.y() / sz.height())});
260 abs_win->push_value(ossia::vec2f{float(win.x()), float(win.y())});
261 }
262 };
263
264 m_root.add_child(std::move(node));
265 }
266
267 // Tablet input
268 ossia::net::parameter_base* scaled_tablet_win{};
269 {
270 auto node = std::make_unique<ossia::net::generic_node>("tablet", *this, m_root);
271 ossia::net::parameter_base* tablet_pressure{};
272 ossia::net::parameter_base* tablet_z{};
273 ossia::net::parameter_base* tablet_tan{};
274 ossia::net::parameter_base* tablet_rot{};
275 ossia::net::parameter_base* tablet_tilt_x{};
276 ossia::net::parameter_base* tablet_tilt_y{};
277 {
278 auto scale_node
279 = std::make_unique<ossia::net::generic_node>("scaled", *this, *node);
280 scaled_tablet_win = scale_node->create_parameter(ossia::val_type::VEC2F);
281 scaled_tablet_win->set_domain(ossia::make_domain(0.f, 1.f));
282 scaled_tablet_win->push_value(ossia::vec2f{0.f, 0.f});
283 node->add_child(std::move(scale_node));
284 }
285 {
286 auto abs_node
287 = std::make_unique<ossia::net::generic_node>("absolute", *this, *node);
288 abs_tablet_win = abs_node->create_parameter(ossia::val_type::VEC2F);
289 abs_tablet_win->set_domain(
290 ossia::make_domain(ossia::vec2f{0.f, 0.f}, ossia::vec2f{1280, 270.f}));
291 abs_tablet_win->push_value(ossia::vec2f{0.f, 0.f});
292 node->add_child(std::move(abs_node));
293 }
294 {
295 auto scale_node = std::make_unique<ossia::net::generic_node>("z", *this, *node);
296 tablet_z = scale_node->create_parameter(ossia::val_type::INT);
297 node->add_child(std::move(scale_node));
298 }
299 {
300 auto scale_node
301 = std::make_unique<ossia::net::generic_node>("pressure", *this, *node);
302 tablet_pressure = scale_node->create_parameter(ossia::val_type::FLOAT);
303 //tablet_pressure->set_domain(ossia::make_domain(0.f, 1.f));
304 //tablet_pressure->push_value(0.f);
305 node->add_child(std::move(scale_node));
306 }
307 {
308 auto scale_node
309 = std::make_unique<ossia::net::generic_node>("tangential", *this, *node);
310 tablet_tan = scale_node->create_parameter(ossia::val_type::FLOAT);
311 tablet_tan->set_domain(ossia::make_domain(-1.f, 1.f));
312 //tablet_tan->push_value(0.f);
313 node->add_child(std::move(scale_node));
314 }
315 {
316 auto scale_node
317 = std::make_unique<ossia::net::generic_node>("rotation", *this, *node);
318 tablet_rot = scale_node->create_parameter(ossia::val_type::FLOAT);
319 tablet_rot->set_unit(ossia::degree_u{});
320 tablet_rot->set_domain(ossia::make_domain(-180.f, 180.f));
321 node->add_child(std::move(scale_node));
322 }
323 {
324 auto scale_node
325 = std::make_unique<ossia::net::generic_node>("tilt_x", *this, *node);
326 tablet_tilt_x = scale_node->create_parameter(ossia::val_type::FLOAT);
327 tablet_tilt_x->set_domain(ossia::make_domain(-60.f, 60.f));
328 tablet_tilt_x->set_unit(ossia::degree_u{});
329 node->add_child(std::move(scale_node));
330 }
331 {
332 auto scale_node
333 = std::make_unique<ossia::net::generic_node>("tilt_y", *this, *node);
334 tablet_tilt_y = scale_node->create_parameter(ossia::val_type::FLOAT);
335 tablet_tilt_y->set_domain(ossia::make_domain(-60.f, 60.f));
336 tablet_tilt_y->set_unit(ossia::degree_u{});
337 node->add_child(std::move(scale_node));
338 }
339
340 m_screen->onTabletMove = [=, this](QTabletEvent* ev) {
341 if(const auto& w = m_screen->window())
342 {
343 const auto sz = w->size();
344 const auto win = ev->position();
345 scaled_tablet_win->push_value(
346 ossia::vec2f{float(win.x() / sz.width()), float(win.y() / sz.height())});
347 abs_tablet_win->push_value(ossia::vec2f{float(win.x()), float(win.y())});
348 tablet_pressure->push_value(ev->pressure());
349 tablet_tan->push_value(ev->tangentialPressure());
350 tablet_rot->push_value(ev->rotation());
351 tablet_z->push_value(ev->z());
352 tablet_tilt_x->push_value(ev->xTilt());
353 tablet_tilt_y->push_value(ev->yTilt());
354 }
355 };
356
357 m_root.add_child(std::move(node));
358 }
359
360 {
361 auto size_node = std::make_unique<ossia::net::generic_node>("size", *this, m_root);
362 size_param = size_node->create_parameter(ossia::val_type::VEC2F);
363 size_param->push_value(ossia::vec2f{1280.f, 720.f});
364 size_param->add_callback([this](const ossia::value& v) {
365 if(auto val = v.target<ossia::vec2f>())
366 {
367 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, v = *val] {
368 screen->setSize({(int)v[0], (int)v[1]});
369 });
370
371 update_viewport();
372 }
373 });
374
375 m_root.add_child(std::move(size_node));
376 }
377
378 {
379 auto size_node
380 = std::make_unique<ossia::net::generic_node>("rendersize", *this, m_root);
381 ossia::net::set_description(
382 *size_node, "Set to [0, 0] to use the viewport's size");
383
384 rendersize_param = size_node->create_parameter(ossia::val_type::VEC2F);
385 rendersize_param->push_value(ossia::vec2f{0.f, 0.f});
386 rendersize_param->add_callback([this](const ossia::value& v) {
387 if(auto val = v.target<ossia::vec2f>())
388 {
389 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, v = *val] {
390 screen->setRenderSize({(int)v[0], (int)v[1]});
391 });
392
393 update_viewport();
394 }
395 });
396
397 m_root.add_child(std::move(size_node));
398 }
399
400 // Keyboard input
401 {
402 auto node = std::make_unique<ossia::net::generic_node>("key", *this, m_root);
403 {
404 auto press_node
405 = std::make_unique<ossia::net::generic_node>("press", *this, *node);
406 ossia::net::parameter_base* press_param{};
407 ossia::net::parameter_base* text_param{};
408 {
409 auto code_node
410 = std::make_unique<ossia::net::generic_node>("code", *this, *press_node);
411 press_param = code_node->create_parameter(ossia::val_type::INT);
412 press_param->push_value(ossia::vec2f{0.f, 0.f});
413 press_node->add_child(std::move(code_node));
414 }
415 {
416 auto text_node
417 = std::make_unique<ossia::net::generic_node>("text", *this, *press_node);
418 text_param = text_node->create_parameter(ossia::val_type::STRING);
419 press_node->add_child(std::move(text_node));
420 }
421
422 m_screen->onKey = [press_param, text_param](int key, const QString& text) {
423 press_param->push_value(key);
424 text_param->push_value(text.toStdString());
425 };
426 node->add_child(std::move(press_node));
427 }
428 {
429 auto release_node
430 = std::make_unique<ossia::net::generic_node>("release", *this, *node);
431 ossia::net::parameter_base* press_param{};
432 ossia::net::parameter_base* text_param{};
433 {
434 auto code_node
435 = std::make_unique<ossia::net::generic_node>("code", *this, *release_node);
436 press_param = code_node->create_parameter(ossia::val_type::INT);
437 press_param->push_value(ossia::vec2f{0.f, 0.f});
438 release_node->add_child(std::move(code_node));
439 }
440 {
441 auto text_node
442 = std::make_unique<ossia::net::generic_node>("text", *this, *release_node);
443 text_param = text_node->create_parameter(ossia::val_type::STRING);
444 release_node->add_child(std::move(text_node));
445 }
446
447 m_screen->onKeyRelease
448 = [press_param, text_param](int key, const QString& text) {
449 press_param->push_value(key);
450 text_param->push_value(text.toStdString());
451 };
452 node->add_child(std::move(release_node));
453 }
454
455 m_root.add_child(std::move(node));
456 }
457
458 {
459 auto fs_node
460 = std::make_unique<ossia::net::generic_node>("fullscreen", *this, m_root);
461 auto fs_param = fs_node->create_parameter(ossia::val_type::BOOL);
462 fs_param->add_callback([this](const ossia::value& v) {
463 if(auto val = v.target<bool>())
464 {
465 ossia::qt::run_async(&m_qtContext, [screen = this->m_screen, v = *val] {
466 screen->setFullScreen(v);
467 });
468 }
469 });
470 m_root.add_child(std::move(fs_node));
471 }
472
473 {
474 auto fps_node = std::make_unique<ossia::net::generic_node>("fps", *this, m_root);
475 auto fps_param = fps_node->create_parameter(ossia::val_type::FLOAT);
476 m_screen->onFps = [fps_param](float fps) { fps_param->push_value(fps); };
477 m_root.add_child(std::move(fps_node));
478 }
479 }
480
481 const gfx_node_base& get_root_node() const override { return m_root; }
482 gfx_node_base& get_root_node() override { return m_root; }
483};
484
485}
Definition score-plugin-gfx/Gfx/Settings/Model.hpp:41
Definition GfxParameter.hpp:71
Definition GfxParameter.hpp:52
Definition Window/WindowDevice.hpp:51
Binds the rendering pipeline to ossia processes.
Definition AssetTable.cpp:7
T & settings() const
Access a specific Settings model instance.
Definition ApplicationContext.hpp:41
const score::ApplicationSettings & applicationSettings
Access to start-up command-line settings.
Definition ApplicationContext.hpp:111
Definition OutputNode.hpp:84
This node is used for rendering to a score::gfx::Window.
Definition ScreenNode.hpp:14