Loading...
Searching...
No Matches
ISFProcess.hpp
1#pragma once
2
3#include <Process/Dataflow/WidgetInlets.hpp>
4#include <Process/ProcessFactory.hpp>
5
6#include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>
7
8#include <Gfx/TexturePort.hpp>
9#include <Gfx/WindowDevice.hpp>
10
11#include <score/tools/File.hpp>
12
13#include <ossia/detail/flat_map.hpp>
14
15#include <QFile>
16
17#include <isf.hpp>
18
19namespace Gfx
20{
22{
23 template <typename T>
24 static Process::Descriptor descriptorFromISFFile(QString path)
25 {
27 if(path.isEmpty())
28 return base;
29
30 QFile f{path};
31 if(!f.open(QIODevice::ReadOnly))
32 return base;
33
34 try
35 {
36 auto [_, desc] = isf::parser::parse_isf_header(score::readFileAsString(f));
37 if(desc.credits.starts_with("Automatically converted from "))
38 desc.credits = desc.credits.substr(strlen("Automatically converted from "));
39 else if(desc.credits.starts_with("by "))
40 desc.credits = desc.credits.substr(strlen("by "));
41 if(!desc.credits.empty())
42 base.author = QString::fromStdString(desc.credits);
43 if(!desc.description.empty())
44 base.description = QString::fromStdString(desc.description);
45 for(auto& cat : desc.categories)
46 base.tags.push_back(QString::fromStdString(cat));
47 }
48 catch(...)
49 {
50 }
51
52 return base;
53 }
54
55 template <typename T>
56 static void setupISFModelPorts(
57 T& self, const isf::descriptor& desc,
58 const ossia::flat_map<QString, ossia::value>& previous_values)
59 {
60 /*
61 {
62 auto& [shader, error] = score::gfx::ShaderCache::get(
63 m_processedProgram.vertex.toLatin1(), QShader::Stage::VertexStage);
64 SCORE_ASSERT(error.isEmpty());
65 }
66 {
67 auto& [shader, error] = score::gfx::ShaderCache::get(
68 m_processedProgram.fragment.toLatin1(), QShader::Stage::FragmentStage);
69 SCORE_ASSERT(error.isEmpty());
70 }
71 */
72
73 int i = 0;
74 using namespace isf;
75
76 struct input_vis
77 {
78 const ossia::flat_map<QString, ossia::value>& previous_values;
79 const isf::input& input;
80 const int i;
81 T& self;
82
83 Process::Inlet* operator()(const float_input& v)
84 {
85 auto nm = QString::fromStdString(input.name);
86 auto port = new Process::FloatSlider(
87 v.min, v.max, v.def, nm, Id<Process::Port>(i), &self);
88
89 self.m_inlets.push_back(port);
90 if(auto it = previous_values.find(nm);
91 it != previous_values.end()
92 && it->second.get_type() == ossia::val_type::FLOAT)
93 port->setValue(it->second);
94
95 self.controlAdded(port->id());
96 return port;
97 }
98
99 Process::Inlet* operator()(const long_input& v)
100 {
101 auto nm = QString::fromStdString(input.name);
102
103 // Numeric mode: MIN/MAX set and no VALUES/LABELS → IntSpinBox
104 if(v.values.empty() && v.min && v.max)
105 {
106 auto port = new Process::IntSpinBox(
107 *v.min, *v.max, (int)v.def, nm, Id<Process::Port>(i), &self);
108
109 if(auto it = previous_values.find(nm);
110 it != previous_values.end()
111 && it->second.get_type() == port->value().get_type())
112 port->setValue(it->second);
113
114 self.m_inlets.push_back(port);
115 self.controlAdded(port->id());
116 return port;
117 }
118
119 // Enum mode: VALUES/LABELS → ComboBox
120 std::vector<std::pair<QString, ossia::value>> alternatives;
121 if(v.labels.size() == v.values.size())
122 {
123 for(std::size_t value_idx = 0; value_idx < v.values.size(); value_idx++)
124 {
125 auto& val = v.values[value_idx];
126 if(auto int_ptr = ossia::get_if<int64_t>(&val))
127 {
128 alternatives.emplace_back(
129 QString::fromStdString(v.labels[value_idx]), int(*int_ptr));
130 }
131 else if(auto dbl_ptr = ossia::get_if<double>(&val))
132 {
133 alternatives.emplace_back(
134 QString::fromStdString(v.labels[value_idx]), int(*dbl_ptr));
135 }
136 else
137 {
138 alternatives.emplace_back(
139 QString::fromStdString(v.labels[value_idx]), int(value_idx));
140 }
141 }
142 }
143 else
144 {
145 for(std::size_t value_idx = 0; value_idx < v.values.size(); value_idx++)
146 {
147 auto& val = v.values[value_idx];
148 if(auto int_ptr = ossia::get_if<int64_t>(&val))
149 {
150 alternatives.emplace_back(QString::number(*int_ptr), int(*int_ptr));
151 }
152 else if(auto dbl_ptr = ossia::get_if<double>(&val))
153 {
154 alternatives.emplace_back(QString::number(*dbl_ptr), int(*dbl_ptr));
155 }
156 else if(auto str_ptr = ossia::get_if<std::string>(&val))
157 {
158 alternatives.emplace_back(
159 QString::fromStdString(*str_ptr), int(value_idx));
160 }
161 }
162 }
163
164 if(alternatives.empty())
165 {
166 alternatives.emplace_back("0", 0);
167 alternatives.emplace_back("1", 1);
168 alternatives.emplace_back("2", 2);
169 }
170
171 auto port = new Process::ComboBox(
172 std::move(alternatives), (int)v.def, nm, Id<Process::Port>(i), &self);
173
174 if(auto it = previous_values.find(nm);
175 it != previous_values.end()
176 && it->second.get_type() == port->value().get_type())
177 port->setValue(it->second);
178
179 self.m_inlets.push_back(port);
180 self.controlAdded(port->id());
181 return port;
182 }
183
184 Process::Inlet* operator()(const event_input& v)
185 {
186 auto nm = QString::fromStdString(input.name);
187 auto port = new Process::Button(nm, Id<Process::Port>(i), &self);
188
189 self.m_inlets.push_back(port);
190 self.controlAdded(port->id());
191 return port;
192 }
193
194 Process::Inlet* operator()(const bool_input& v)
195 {
196 auto nm = QString::fromStdString(input.name);
197 auto port = new Process::Toggle(v.def, nm, Id<Process::Port>(i), &self);
198
199 if(auto it = previous_values.find(nm);
200 it != previous_values.end()
201 && it->second.get_type() == port->value().get_type())
202 port->setValue(it->second);
203
204 self.m_inlets.push_back(port);
205 self.controlAdded(port->id());
206 return port;
207 }
208
209 Process::Inlet* operator()(const point2d_input& v)
210 {
211 auto nm = QString::fromStdString(input.name);
212 ossia::vec2f min{-100., -100.};
213 ossia::vec2f max{100., 100.};
214 ossia::vec2f init{0.0, 0.0};
215 if(v.def)
216 std::copy_n(v.def->begin(), 2, init.begin());
217 if(v.min)
218 std::copy_n(v.min->begin(), 2, min.begin());
219 if(v.max)
220 std::copy_n(v.max->begin(), 2, max.begin());
221 auto port = new Process::XYSpinboxes{
222 min, max, init, false, nm, Id<Process::Port>(i), &self};
223
224 auto& ctx = score::IDocument::documentContext(self);
225 auto& device_plug = ctx.template plugin<Explorer::DeviceDocumentPlugin>();
226 const Device::DeviceList& list = device_plug.list();
227 QString firstWindowDeviceName;
228 for(auto dev : list.devices())
229 {
230 if(auto win = qobject_cast<WindowDevice*>(dev))
231 {
232 firstWindowDeviceName = win->name();
233 break;
234 }
235 }
236
237 if(!firstWindowDeviceName.isEmpty())
238 {
239 if(nm.contains("iMouse"))
240 port->setAddress(
242 State::Address{firstWindowDeviceName, {"cursor", "absolute"}}});
243 else if(nm.contains("mouse", Qt::CaseInsensitive))
244 port->setAddress(
246 State::Address{firstWindowDeviceName, {"cursor", "gl"}}});
247 }
248
249 if(auto it = previous_values.find(nm);
250 it != previous_values.end()
251 && it->second.get_type() == port->value().get_type())
252 port->setValue(it->second);
253
254 self.m_inlets.push_back(port);
255 self.controlAdded(port->id());
256 return port;
257 }
258
259 Process::Inlet* operator()(const point3d_input& v)
260 {
261 auto nm = QString::fromStdString(input.name);
262 ossia::vec3f min{-100., -100., -100.};
263 ossia::vec3f max{100., 100., 100.};
264 ossia::vec3f init{0., 0., 0.};
265 if(v.def)
266 std::copy_n(v.def->begin(), 3, init.begin());
267 if(v.min)
268 std::copy_n(v.min->begin(), 3, min.begin());
269 if(v.max)
270 std::copy_n(v.max->begin(), 3, max.begin());
271 auto port = new Process::XYZSpinboxes{
272 min, max, init, false, nm, Id<Process::Port>(i), &self};
273
274 if(auto it = previous_values.find(nm);
275 it != previous_values.end()
276 && it->second.get_type() == port->value().get_type())
277 port->setValue(it->second);
278
279 self.m_inlets.push_back(port);
280 self.controlAdded(port->id());
281 return port;
282 }
283
284 Process::Inlet* operator()(const color_input& v)
285 {
286 auto nm = QString::fromStdString(input.name);
287 ossia::vec4f init{0.5, 0.5, 0.5, 1.};
288 if(v.def)
289 {
290 std::copy_n(v.def->begin(), 4, init.begin());
291 }
292 auto port = new Process::HSVSlider(
293 init, QString::fromStdString(input.name), Id<Process::Port>(i), &self);
294
295 if(auto it = previous_values.find(nm);
296 it != previous_values.end()
297 && it->second.get_type() == port->value().get_type())
298 port->setValue(it->second);
299
300 self.m_inlets.push_back(port);
301 self.controlAdded(port->id());
302 return port;
303 }
304 Process::Inlet* operator()(const image_input& v)
305 {
306 auto port = new Gfx::TextureInlet(
307 QString::fromStdString(input.name), Id<Process::Port>(i), &self);
308
309 self.m_inlets.push_back(port);
310 return port;
311 }
312 Process::Inlet* operator()(const cubemap_input& v)
313 {
314 auto port = new Gfx::TextureInlet(
315 QString::fromStdString(input.name), Id<Process::Port>(i), &self);
316
317 self.m_inlets.push_back(port);
318 return port;
319 }
320 Process::Inlet* operator()(const audio_input& v)
321 {
322 auto port = new Process::AudioInlet(
323 QString::fromStdString(input.name), Id<Process::Port>(i), &self);
324 self.m_inlets.push_back(port);
325 return port;
326 }
327 Process::Inlet* operator()(const audioFFT_input& v)
328 {
329 auto port = new Process::AudioInlet(
330 QString::fromStdString(input.name), Id<Process::Port>(i), &self);
331 self.m_inlets.push_back(port);
332 return port;
333 }
334 Process::Inlet* operator()(const audioHist_input& v)
335 {
336 auto port = new Process::AudioInlet(
337 QString::fromStdString(input.name), Id<Process::Port>(i), &self);
338 self.m_inlets.push_back(port);
339 return port;
340 }
341
342 // CSF-specific input handlers
343 Process::Inlet* operator()(const storage_input& v) { return nullptr; }
344 Process::Inlet* operator()(const texture_input& v) { return nullptr; }
345 Process::Inlet* operator()(const csf_image_input& v) { return nullptr; }
346 Process::Inlet* operator()(const geometry_input& v) { return nullptr; }
347 };
348
349 for(const isf::input& input : desc.inputs)
350 {
351 ossia::visit(input_vis{previous_values, input, i, self}, input.data);
352 i++;
353 }
354
355 // MRT: recreate outlets from OUTPUTS declarations
356 if(!desc.outputs.empty())
357 {
358 qDeleteAll(self.m_outlets);
359 self.m_outlets.clear();
360
361 int outId = 10000; // High base to avoid ID collisions with inlets
362 for(const auto& out : desc.outputs)
363 {
364 self.m_outlets.push_back(new Gfx::TextureOutlet{
365 QString::fromStdString(out.name),
366 Id<Process::Port>(outId++), &self});
367 }
368 }
369 }
370};
371}
The DeviceList class.
Definition DeviceList.hpp:26
Definition Port.hpp:302
Definition Port.hpp:180
The id_base_t class.
Definition Identifier.hpp:59
Binds the rendering pipeline to ossia processes.
Definition CameraDevice.cpp:30
Definition ISFProcess.hpp:22
Static metadata implementation.
Definition lib/score/tools/Metadata.hpp:36
Definition WidgetInlets.hpp:488
Definition WidgetInlets.hpp:444
Definition score-lib-process/Process/ProcessMetadata.hpp:36
Definition WidgetInlets.hpp:158
Definition WidgetInlets.hpp:512
Definition WidgetInlets.hpp:281
Definition WidgetInlets.hpp:324
Definition WidgetInlets.hpp:559
Definition WidgetInlets.hpp:583
Definition Address.hpp:108
The Address struct.
Definition Address.hpp:58