1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "uniformmodel.h"
6#include "propertyhandler.h"
7#include "effectmanager.h"
8
9UniformModel::UniformModel(QObject *parent)
10 : QAbstractListModel(parent)
11{
12
13}
14
15void UniformModel::setModelData(UniformTable *data)
16{
17 beginResetModel();
18 m_uniformTable = data;
19 endResetModel();
20 updateCanMoveStatus();
21 Q_EMIT uniformsChanged();
22}
23
24int UniformModel::rowCount(const QModelIndex &) const
25{
26 return int((m_uniformTable != nullptr) ? m_uniformTable->size() : 0);
27}
28
29QVariant UniformModel::data(const QModelIndex &index, int role) const
30{
31 if (!m_uniformTable || !index.isValid())
32 return QVariant();
33
34 if (index.row() >= m_uniformTable->size())
35 return false;
36
37 const auto &uniform = (*m_uniformTable)[index.row()];
38
39 if (role == Type) {
40 return QVariant::fromValue(value: uniform.type);
41 } else if (role == NodeId) {
42 return QVariant::fromValue(value: uniform.nodeId);
43 } else if (role == Name) {
44 return QVariant::fromValue(value: QString::fromLatin1(ba: uniform.name));
45 } else if (role == Value) {
46 switch (uniform.type) {
47 case Uniform::Type::Sampler:
48 return uniform.value.value<QString>();
49 case Uniform::Type::Bool:
50 return uniform.value.value<bool>();
51 case Uniform::Type::Int:
52 return uniform.value.value<int>();
53 case Uniform::Type::Float:
54 return uniform.value.value<double>();
55 case Uniform::Type::Vec2:
56 return uniform.value.value<QVector2D>();
57 case Uniform::Type::Vec3:
58 return uniform.value.value<QVector3D>();
59 case Uniform::Type::Vec4:
60 return uniform.value.value<QVector4D>();
61 case Uniform::Type::Color:
62 return uniform.value.value<QColor>();
63 case Uniform::Type::Define:
64 return uniform.value.value<QString>();
65 }
66 } else if (role == DefaultValue) {
67 switch (uniform.type) {
68 case Uniform::Type::Sampler:
69 return uniform.defaultValue.value<QString>();
70 case Uniform::Type::Bool:
71 return uniform.defaultValue.value<bool>();
72 case Uniform::Type::Int:
73 return uniform.defaultValue.value<int>();
74 case Uniform::Type::Float:
75 return uniform.defaultValue.value<double>();
76 case Uniform::Type::Vec2:
77 return uniform.defaultValue.value<QVector2D>();
78 case Uniform::Type::Vec3:
79 return uniform.defaultValue.value<QVector3D>();
80 case Uniform::Type::Vec4:
81 return uniform.defaultValue.value<QVector4D>();
82 case Uniform::Type::Color:
83 return uniform.defaultValue.value<QColor>();
84 case Uniform::Type::Define:
85 return uniform.defaultValue.value<QString>();
86 }
87 } else if (role == MinValue) {
88 switch (uniform.type) {
89 case Uniform::Type::Sampler:
90 return uniform.minValue.value<QString>();
91 case Uniform::Type::Bool:
92 return uniform.minValue.value<bool>();
93 case Uniform::Type::Int:
94 return uniform.minValue.value<int>();
95 case Uniform::Type::Float:
96 return uniform.minValue.value<double>();
97 case Uniform::Type::Vec2:
98 return uniform.minValue.value<QVector2D>();
99 case Uniform::Type::Vec3:
100 return uniform.minValue.value<QVector3D>();
101 case Uniform::Type::Vec4:
102 return uniform.minValue.value<QVector4D>();
103 case Uniform::Type::Color:
104 return uniform.minValue.value<QColor>();
105 case Uniform::Type::Define:
106 return uniform.minValue.value<QString>();
107 }
108 } else if (role == MaxValue) {
109 switch (uniform.type) {
110 case Uniform::Type::Sampler:
111 return uniform.maxValue.value<QString>();
112 case Uniform::Type::Bool:
113 return uniform.maxValue.value<bool>();
114 case Uniform::Type::Int:
115 return uniform.maxValue.value<int>();
116 case Uniform::Type::Float:
117 return uniform.maxValue.value<double>();
118 case Uniform::Type::Vec2:
119 return uniform.maxValue.value<QVector2D>();
120 case Uniform::Type::Vec3:
121 return uniform.maxValue.value<QVector3D>();
122 case Uniform::Type::Vec4:
123 return uniform.maxValue.value<QVector4D>();
124 case Uniform::Type::Color:
125 return uniform.maxValue.value<QColor>();
126 case Uniform::Type::Define:
127 return uniform.maxValue.value<QString>();
128 }
129 } else if (role == Description) {
130 return QVariant::fromValue(value: uniform.description);
131 } else if (role == CustomValue) {
132 return QVariant::fromValue(value: uniform.customValue);
133 } else if (role == UseCustomValue) {
134 return QVariant::fromValue(value: uniform.useCustomValue);
135 } else if (role == Visible) {
136 return QVariant::fromValue(value: uniform.visible);
137 } else if (role == ExportProperty) {
138 return QVariant::fromValue(value: uniform.exportProperty);
139 } else if (role == CanMoveUp) {
140 return QVariant::fromValue(value: uniform.canMoveUp);
141 } else if (role == CanMoveDown) {
142 return QVariant::fromValue(value: uniform.canMoveDown);
143 } else if (role == EnableMipmap) {
144 return QVariant::fromValue(value: uniform.enableMipmap);
145 } else if (role == ExportImage) {
146 return QVariant::fromValue(value: uniform.exportImage);
147 }
148
149 return QVariant();
150}
151
152QHash<int, QByteArray> UniformModel::roleNames() const
153{
154 QHash<int, QByteArray> roles;
155 roles[Type] = "type";
156 roles[Name] = "name";
157 roles[Value] = "value";
158 roles[DefaultValue] = "defaultValue";
159 roles[MinValue] = "minValue";
160 roles[MaxValue] = "maxValue";
161 roles[NodeId] = "nodeId";
162 roles[Description] = "description";
163 roles[CustomValue] = "customValue";
164 roles[UseCustomValue] = "useCustomValue";
165 roles[Visible] = "visible";
166 roles[ExportProperty] = "exportProperty";
167 roles[CanMoveUp] = "canMoveUp";
168 roles[CanMoveDown] = "canMoveDown";
169 roles[EnableMipmap] = "enableMipmap";
170 roles[ExportImage] = "exportImage";
171 return roles;
172}
173
174bool UniformModel::setData(const QModelIndex &index, const QVariant &value, int role)
175{
176 if (!index.isValid() || !m_uniformTable)
177 return false;
178
179 if (index.row() >= m_uniformTable->size())
180 return false;
181
182 auto &uniform = (*m_uniformTable)[index.row()];
183
184 bool ok = true;
185
186 if (role == Type) {
187 const auto v = value.toInt(ok: &ok);
188 if (ok)
189 uniform.type = static_cast<Uniform::Type>(v);
190 } else if (role == Name) {
191 uniform.name = value.toString().toUtf8();
192 } else if (role == Value) {
193 switch (uniform.type) {
194 case Uniform::Type::Bool:
195 case Uniform::Type::Int:
196 case Uniform::Type::Float:
197 case Uniform::Type::Vec2:
198 case Uniform::Type::Vec3:
199 case Uniform::Type::Vec4:
200 case Uniform::Type::Color:
201 case Uniform::Type::Sampler:
202 case Uniform::Type::Define:
203 uniform.value = value;
204 break;
205 }
206 } else if (role == DefaultValue) {
207 switch (uniform.type) {
208 case Uniform::Type::Bool:
209 case Uniform::Type::Int:
210 case Uniform::Type::Float:
211 case Uniform::Type::Vec2:
212 case Uniform::Type::Vec3:
213 case Uniform::Type::Vec4:
214 case Uniform::Type::Color:
215 case Uniform::Type::Sampler:
216 case Uniform::Type::Define:
217 uniform.defaultValue = value;
218 break;
219 }
220 } else if (role == MinValue) {
221 switch (uniform.type) {
222 case Uniform::Type::Bool:
223 case Uniform::Type::Int:
224 case Uniform::Type::Float:
225 case Uniform::Type::Vec2:
226 case Uniform::Type::Vec3:
227 case Uniform::Type::Vec4:
228 case Uniform::Type::Color:
229 case Uniform::Type::Sampler:
230 case Uniform::Type::Define:
231 uniform.minValue = value;
232 break;
233 }
234 } else if (role == MaxValue) {
235 switch (uniform.type) {
236 case Uniform::Type::Bool:
237 case Uniform::Type::Int:
238 case Uniform::Type::Float:
239 case Uniform::Type::Vec2:
240 case Uniform::Type::Vec3:
241 case Uniform::Type::Vec4:
242 case Uniform::Type::Color:
243 case Uniform::Type::Sampler:
244 case Uniform::Type::Define:
245 uniform.maxValue = value;
246 break;
247 }
248 } else if (role == Description) {
249 uniform.description = value.toString();
250 } else if (role == CustomValue) {
251 uniform.customValue = value.toString();
252 } else if (role == UseCustomValue) {
253 uniform.useCustomValue = value.toBool();
254 } else if (role == ExportProperty) {
255 uniform.exportProperty = value.toBool();
256 } else if (role == CanMoveUp) {
257 uniform.canMoveUp = value.toBool();
258 } else if (role == CanMoveDown) {
259 uniform.canMoveDown = value.toBool();
260 } else if (role == EnableMipmap) {
261 uniform.enableMipmap = value.toBool();
262 } else if (role == ExportImage) {
263 uniform.exportImage = value.toBool();
264 }
265
266 if (role == Value) {
267 // Don't update uniforms when value is changed, as those
268 // go through g_propertyData
269 g_propertyData.insert(key: uniform.name, value);
270 if (m_effectManager)
271 m_effectManager->setUnsavedChanges(true);
272 }
273 if (role != Value || !uniform.exportProperty) {
274 // But non-exported (const value) properties need update
275 Q_EMIT uniformsChanged();
276 }
277
278 if (ok)
279 emit dataChanged(topLeft: index, bottomRight: index, roles: {role});
280
281 return ok;
282}
283
284// Initialize the value variant with correct type
285QVariant UniformModel::getInitializedVariant(Uniform::Type type, bool maxValue)
286{
287 switch (type) {
288 case Uniform::Type::Sampler:
289 return QString();
290 case Uniform::Type::Bool:
291 return maxValue ? true : false;
292 case Uniform::Type::Int:
293 return maxValue ? 100 : 0;
294 case Uniform::Type::Float:
295 return maxValue ? 1.0 : 0.0;
296 case Uniform::Type::Vec2:
297 return maxValue ? QVector2D(1.0, 1.0) : QVector2D(0.0, 0.0);
298 case Uniform::Type::Vec3:
299 return maxValue ? QVector3D(1.0, 1.0, 1.0) : QVector3D(0.0, 0.0, 0.0);
300 case Uniform::Type::Vec4:
301 return maxValue ? QVector4D(1.0, 1.0, 1.0, 1.0) : QVector4D(0.0, 0.0, 0.0, 0.0);
302 case Uniform::Type::Color:
303 return maxValue ? QColor::fromRgbF(r: 1.0f, g: 1.0f, b: 1.0f, a: 1.0f) : QColor::fromRgbF(r: 0.0f, g: 0.0f, b: 0.0f, a: 0.0f);
304 case Uniform::Type::Define:
305 return QString();
306 }
307 return QVariant();
308}
309
310// Return name for the image property Image element
311QString UniformModel::getImageElementName(const Uniform &uniform)
312{
313 if (uniform.value.toString().isEmpty())
314 return QStringLiteral("null");
315 QString simplifiedName = uniform.name.simplified();
316 simplifiedName = simplifiedName.remove(c: ' ');
317 return QStringLiteral("imageItem") + simplifiedName;
318}
319
320// This will update the row content at rowIndex
321// When rowIndex = -1, new row will be appended
322bool UniformModel::updateRow(int nodeId, int rowIndex, int type, const QString &id,
323 const QVariant &defaultValue, const QString &description, const QString &customValue,
324 bool useCustomValue, const QVariant &minValue, const QVariant &maxValue,
325 bool enableMipmap, bool exportImage)
326{
327 if (m_uniformTable == nullptr)
328 return false;
329
330 bool addNewRow = false;
331 if (rowIndex == -1) {
332 addNewRow = true;
333 // Add new row after the last of its node so uniforms are
334 // in continuous groups per node.
335 rowIndex = m_uniformTable->size();
336 for (int i = m_uniformTable->size() - 1; i >= 0; i--) {
337 auto &uniform = (*m_uniformTable)[i];
338 if (uniform.nodeId == nodeId) {
339 rowIndex = i + 1;
340 break;
341 }
342 }
343 }
344
345 if (addNewRow && !validateUniformName(uniformName: id))
346 return false;
347
348 if (addNewRow)
349 beginInsertRows(parent: QModelIndex(), first: rowIndex, last: rowIndex);
350
351 Uniform newUniform = { };
352 auto &uniform = addNewRow ? newUniform : (*m_uniformTable)[rowIndex];
353
354 uniform.type = Uniform::Type(type);
355 uniform.name = id.toLocal8Bit();
356 uniform.description = description;
357 uniform.customValue = customValue;
358 uniform.useCustomValue = useCustomValue;
359 uniform.enableMipmap = enableMipmap;
360 uniform.exportImage = exportImage;
361 switch (uniform.type) {
362 case Uniform::Type::Bool:
363 uniform.defaultValue = defaultValue;
364 break;
365 case Uniform::Type::Int:
366 case Uniform::Type::Float:
367 case Uniform::Type::Vec2:
368 case Uniform::Type::Vec3:
369 case Uniform::Type::Vec4:
370 case Uniform::Type::Color:
371 case Uniform::Type::Define:
372 uniform.defaultValue = defaultValue;
373 uniform.minValue = minValue;
374 uniform.maxValue = maxValue;
375 break;
376 case Uniform::Type::Sampler:
377 if (defaultValue.metaType().id() == QMetaType::QUrl)
378 uniform.defaultValue = defaultValue.toString();
379 else
380 uniform.defaultValue = "";
381 // Update the mipmap property
382 QString mipmapProperty = m_effectManager->mipmapPropertyName(name: uniform.name);
383 g_propertyData[mipmapProperty] = enableMipmap;
384 break;
385 }
386
387 if (addNewRow) {
388 // When adding a property, value is default value
389 uniform.value = uniform.defaultValue;
390 g_propertyData.insert(key: uniform.name, value: uniform.value);
391 // Note: NodeId is only updated when adding new property
392 // Properties can't be moved to other nodes
393 uniform.nodeId = nodeId;
394 m_uniformTable->insert(i: rowIndex, t: uniform);
395 endInsertRows();
396 updateCanMoveStatus();
397 if (uniform.type == Uniform::Type::Sampler) {
398 QString fs = "\n";
399 fs += "// *** Autogenerated - Remove if not needed ***\n";
400 fs += "// vec4 " + uniform.name + "Tex = texture(" + uniform.name + ", texCoord);\n";
401 Q_EMIT addFSCode(code: fs);
402 }
403 } else {
404 if (!uniform.useCustomValue)
405 g_propertyData.insert(key: uniform.name, value: uniform.value);
406 Q_EMIT dataChanged(topLeft: QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0),
407 bottomRight: QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0));
408 }
409 // Update QML component as useCustomValue, customValue etc. might have changed
410 Q_EMIT qmlComponentChanged();
411 Q_EMIT uniformsChanged();
412 return true;
413}
414
415bool UniformModel::resetValue(int rowIndex)
416{
417 auto &uniform = (*m_uniformTable)[rowIndex];
418 auto index = QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0);
419 setData(index, value: uniform.defaultValue, role: Value);
420
421 g_propertyData.insert(key: uniform.name, value: uniform.defaultValue);
422
423 emit dataChanged(topLeft: index, bottomRight: index, roles: {Value});
424
425 // Image element may change, so update component
426 if (uniform.type == Uniform::Type::Sampler)
427 Q_EMIT qmlComponentChanged();
428 Q_EMIT uniformsChanged();
429
430 return true;
431}
432
433// Updates the image data at rowIndex
434bool UniformModel::setImage(int rowIndex, const QVariant &value)
435{
436 auto &uniform = (*m_uniformTable)[rowIndex];
437 uniform.value = value.toString();
438
439 g_propertyData.insert(key: uniform.name, value);
440
441 emit dataChanged(topLeft: QAbstractItemModel::createIndex(arow: 0, acolumn: 0),
442 bottomRight: QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0));
443
444 // Image element may change, so update component
445 if (uniform.type == Uniform::Type::Sampler)
446 Q_EMIT qmlComponentChanged();
447 Q_EMIT uniformsChanged();
448 return true;
449}
450
451// Move uniform up/down in the list
452void UniformModel::moveIndex(int rowIndex, int direction)
453{
454 if (m_uniformTable == nullptr)
455 return;
456
457 // Note: beginMoveRows index behaves differently than QList move index.
458 int destinationRowIndex = rowIndex + 2;
459 int destinationListIndex = rowIndex + 1;
460 if (direction == -1) {
461 destinationRowIndex = rowIndex - 1;
462 destinationListIndex = rowIndex - 1;
463 }
464
465 if (destinationListIndex >= 0 && m_uniformTable->size() > destinationListIndex) {
466 beginMoveRows(sourceParent: QModelIndex(), sourceFirst: rowIndex, sourceLast: rowIndex, destinationParent: QModelIndex(), destinationRow: destinationRowIndex);
467 m_uniformTable->move(from: rowIndex, to: destinationListIndex);
468 endMoveRows();
469 updateCanMoveStatus();
470 }
471}
472
473void UniformModel::removeRow(int rowIndex, int rows)
474{
475 if (m_uniformTable == nullptr)
476 return;
477
478 if (m_uniformTable->size() > rowIndex) {
479 rows = qBound(min: 1, val: rows, max: m_uniformTable->size());
480 beginRemoveRows(parent: QModelIndex(), first: rowIndex, last: rowIndex + rows - 1);
481 m_uniformTable->remove(i: rowIndex, n: rows);
482 endRemoveRows();
483 updateCanMoveStatus();
484
485 emit dataChanged(topLeft: QAbstractItemModel::createIndex(arow: 0, acolumn: 0),
486 bottomRight: QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0));
487 Q_EMIT uniformsChanged();
488 }
489}
490
491bool UniformModel::validateUniformName(const QString &uniformName)
492{
493 if (!m_uniformTable)
494 return false;
495
496 // must be unique
497 for (const auto &uniform : *m_uniformTable) {
498 if (uniform.name == uniformName)
499 return false;
500 }
501
502 return true;
503}
504
505QString UniformModel::typeToProperty(Uniform::Type type)
506{
507 QString property;
508 switch (type) {
509 case Uniform::Type::Bool:
510 property = "bool";
511 break;
512 case Uniform::Type::Int:
513 property = "int";
514 break;
515 case Uniform::Type::Float:
516 property = "real";
517 break;
518 case Uniform::Type::Vec2:
519 property = "point";
520 break;
521 case Uniform::Type::Vec3:
522 property = "vector3d";
523 break;
524 case Uniform::Type::Vec4:
525 property = "vector4d";
526 break;
527 case Uniform::Type::Color:
528 property = "color";
529 break;
530 case Uniform::Type::Sampler:
531 property = "var";
532 break;
533 case Uniform::Type::Define:
534 property = "var";
535 break;
536 }
537 return property;
538}
539
540QString UniformModel::typeToUniform(Uniform::Type type)
541{
542 QString property;
543 switch (type) {
544 case Uniform::Type::Bool:
545 property = "bool";
546 break;
547 case Uniform::Type::Int:
548 property = "int";
549 break;
550 case Uniform::Type::Float:
551 property = "float";
552 break;
553 case Uniform::Type::Vec2:
554 property = "vec2";
555 break;
556 case Uniform::Type::Vec3:
557 property = "vec3";
558 break;
559 case Uniform::Type::Vec4:
560 case Uniform::Type::Color:
561 property = "vec4";
562 break;
563 case Uniform::Type::Sampler:
564 property = "sampler2D";
565 break;
566 case Uniform::Type::Define:
567 property = "define";
568 break;
569 }
570 return property;
571}
572
573// Get value in QML format that used for exports
574QString UniformModel::valueAsString(const Uniform &uniform)
575{
576 QString s;
577 switch (uniform.type) {
578 case Uniform::Type::Bool:
579 s = uniform.value.toBool() ? "true" : "false";
580 break;
581 case Uniform::Type::Int:
582 s = QString::number(uniform.value.toInt());
583 break;
584 case Uniform::Type::Float:
585 s = QString::number(uniform.value.toDouble());
586 break;
587 case Uniform::Type::Vec2:
588 {
589 QVector2D v2 = uniform.value.value<QVector2D>();
590 s = QString("Qt.point(%1, %2)").arg(a: v2.x()).arg(a: v2.y());
591 break;
592 }
593 case Uniform::Type::Vec3:
594 {
595 QVector3D v3 = uniform.value.value<QVector3D>();
596 s = QString("Qt.vector3d(%1, %2, %3)").arg(a: v3.x()).arg(a: v3.y()).arg(a: v3.z());
597 break;
598 }
599 case Uniform::Type::Vec4:
600 {
601 QVector4D v4 = uniform.value.value<QVector4D>();
602 s = QString("Qt.vector4d(%1, %2, %3, %4)").arg(a: v4.x()).arg(a: v4.y()).arg(a: v4.z()).arg(a: v4.w());
603 break;
604 }
605 case Uniform::Type::Color:
606 {
607 QColor c = uniform.value.value<QColor>();
608 s = QString("Qt.rgba(%1, %2, %3, %4)").arg(a: c.redF()).arg(a: c.greenF()).arg(a: c.blueF()).arg(a: c.alphaF());
609 break;
610 }
611 case Uniform::Type::Sampler:
612 {
613 s = getImageElementName(uniform);
614 break;
615 }
616 case Uniform::Type::Define:
617 {
618 s = uniform.value.toString();
619 break;
620 }
621 }
622 return s;
623}
624
625// Get value in GLSL format that is used for non-exported const properties
626QString UniformModel::valueAsVariable(const Uniform &uniform)
627{
628 QString s;
629 switch (uniform.type) {
630 case Uniform::Type::Bool:
631 s = uniform.value.toBool() ? "true" : "false";
632 break;
633 case Uniform::Type::Int:
634 s = QString::number(uniform.value.toInt());
635 break;
636 case Uniform::Type::Float:
637 s = QString::number(uniform.value.toDouble());
638 break;
639 case Uniform::Type::Vec2:
640 {
641 QVector2D v2 = uniform.value.value<QVector2D>();
642 s = QString("vec2(%1, %2)").arg(a: v2.x()).arg(a: v2.y());
643 break;
644 }
645 case Uniform::Type::Vec3:
646 {
647 QVector3D v3 = uniform.value.value<QVector3D>();
648 s = QString("vec3(%1, %2, %3)").arg(a: v3.x()).arg(a: v3.y()).arg(a: v3.z());
649 break;
650 }
651 case Uniform::Type::Vec4:
652 {
653 QVector4D v4 = uniform.value.value<QVector4D>();
654 s = QString("vec4(%1, %2, %3, %4)").arg(a: v4.x()).arg(a: v4.y()).arg(a: v4.z()).arg(a: v4.w());
655 break;
656 }
657 case Uniform::Type::Color:
658 {
659 QColor c = uniform.value.value<QColor>();
660 s = QString("vec4(%1, %2, %3, %4)").arg(a: c.redF()).arg(a: c.greenF()).arg(a: c.blueF()).arg(a: c.alphaF());
661 break;
662 }
663 default:
664 qWarning() << QString("Unhandled const variable type: %1").arg(a: int(uniform.type)).toLatin1();
665 break;
666 }
667 return s;
668}
669
670// Get value in QML binding that used for previews
671QString UniformModel::valueAsBinding(const Uniform &uniform)
672{
673 QString s;
674 switch (uniform.type) {
675 case Uniform::Type::Bool:
676 case Uniform::Type::Int:
677 case Uniform::Type::Float:
678 case Uniform::Type::Define:
679 s = "g_propertyData." + uniform.name;
680 break;
681 case Uniform::Type::Vec2:
682 {
683 QString sx = QString("g_propertyData.%1.x").arg(a: uniform.name);
684 QString sy = QString("g_propertyData.%1.y").arg(a: uniform.name);
685 s = QString("Qt.point(%1, %2)").arg(args&: sx, args&: sy);
686 break;
687 }
688 case Uniform::Type::Vec3:
689 {
690 QString sx = QString("g_propertyData.%1.x").arg(a: uniform.name);
691 QString sy = QString("g_propertyData.%1.y").arg(a: uniform.name);
692 QString sz = QString("g_propertyData.%1.z").arg(a: uniform.name);
693 s = QString("Qt.vector3d(%1, %2, %3)").arg(args&: sx, args&: sy, args&: sz);
694 break;
695 }
696 case Uniform::Type::Vec4:
697 {
698 QString sx = QString("g_propertyData.%1.x").arg(a: uniform.name);
699 QString sy = QString("g_propertyData.%1.y").arg(a: uniform.name);
700 QString sz = QString("g_propertyData.%1.z").arg(a: uniform.name);
701 QString sw = QString("g_propertyData.%1.w").arg(a: uniform.name);
702 s = QString("Qt.vector4d(%1, %2, %3, %4)").arg(args&: sx, args&: sy, args&: sz, args&: sw);
703 break;
704 }
705 case Uniform::Type::Color:
706 {
707 QString sr = QString("g_propertyData.%1.r").arg(a: uniform.name);
708 QString sg = QString("g_propertyData.%1.g").arg(a: uniform.name);
709 QString sb = QString("g_propertyData.%1.b").arg(a: uniform.name);
710 QString sa = QString("g_propertyData.%1.a").arg(a: uniform.name);
711 s = QString("Qt.rgba(%1, %2, %3, %4)").arg(args&: sr, args&: sg, args&: sb, args&: sa);
712 break;
713 }
714 case Uniform::Type::Sampler:
715 {
716 s = getImageElementName(uniform);
717 break;
718 }
719 }
720 return s;
721}
722
723QString UniformModel::variantAsDataString(const Uniform::Type type, const QVariant &variant)
724{
725 QString s;
726 switch (type) {
727 case Uniform::Type::Bool:
728 s = variant.toBool() ? "true" : "false";
729 break;
730 case Uniform::Type::Int:
731 s = QString::number(variant.toInt());
732 break;
733 case Uniform::Type::Float:
734 s = QString::number(variant.toDouble());
735 break;
736 case Uniform::Type::Vec2:
737 {
738 QStringList list;
739 QVector2D v2 = variant.value<QVector2D>();
740 list << QString::number(v2.x());
741 list << QString::number(v2.y());
742 s = list.join(sep: ", ");
743 break;
744 }
745 case Uniform::Type::Vec3:
746 {
747 QStringList list;
748 QVector3D v3 = variant.value<QVector3D>();
749 list << QString::number(v3.x());
750 list << QString::number(v3.y());
751 list << QString::number(v3.z());
752 s = list.join(sep: ", ");
753 break;
754 }
755 case Uniform::Type::Vec4:
756 {
757 QStringList list;
758 QVector4D v4 = variant.value<QVector4D>();
759 list << QString::number(v4.x());
760 list << QString::number(v4.y());
761 list << QString::number(v4.z());
762 list << QString::number(v4.w());
763 s = list.join(sep: ", ");
764 break;
765 }
766 case Uniform::Type::Color:
767 {
768 QStringList list;
769 QColor c = variant.value<QColor>();
770 list << QString::number(c.redF(), format: 'g', precision: 3);
771 list << QString::number(c.greenF(), format: 'g', precision: 3);
772 list << QString::number(c.blueF(), format: 'g', precision: 3);
773 list << QString::number(c.alphaF(), format: 'g', precision: 3);
774 s = list.join(sep: ", ");
775 break;
776 }
777 case Uniform::Type::Sampler:
778 case Uniform::Type::Define:
779 {
780 s = variant.toString();
781 break;
782 }
783 }
784 return s;
785}
786
787void UniformModel::appendUniform(Uniform uniform)
788{
789 if (!validateUniformName(uniformName: uniform.name)) {
790 qWarning() << "Invalid uniform name, can't add it";
791 return;
792 }
793
794 int rowIndex = m_uniformTable->size();
795 beginInsertRows(parent: QModelIndex(), first: rowIndex, last: rowIndex);
796 m_uniformTable->insert(i: rowIndex, t: uniform);
797 endInsertRows();
798 updateCanMoveStatus();
799
800 emit dataChanged(topLeft: QAbstractItemModel::createIndex(arow: 0, acolumn: 0),
801 bottomRight: QAbstractItemModel::createIndex(arow: rowIndex, acolumn: 0));
802
803 Q_EMIT uniformsChanged();
804
805}
806
807void UniformModel::setUniformValueData(Uniform *uniform, const QString &value, const QString &defaultValue, const QString &minValue, const QString &maxValue)
808{
809 if (!uniform)
810 return;
811
812 uniform->value = value.isEmpty() ? getInitializedVariant(type: uniform->type, maxValue: false) : valueStringToVariant(type: uniform->type, value);
813 uniform->defaultValue = defaultValue.isEmpty() ? getInitializedVariant(type: uniform->type, maxValue: false) : valueStringToVariant(type: uniform->type, value: defaultValue);
814 uniform->minValue = minValue.isEmpty() ? getInitializedVariant(type: uniform->type, maxValue: false) : valueStringToVariant(type: uniform->type, value: minValue);
815 uniform->maxValue = maxValue.isEmpty() ? getInitializedVariant(type: uniform->type, maxValue: true) : valueStringToVariant(type: uniform->type, value: maxValue);
816
817 // Update the value data in bindings
818 g_propertyData.insert(key: uniform->name, value: uniform->value);
819}
820
821UniformModel::Uniform::Type UniformModel::typeFromString(const QString &typeString) const
822{
823 if (typeString == "bool")
824 return UniformModel::Uniform::Type::Bool;
825 else if (typeString == "int")
826 return UniformModel::Uniform::Type::Int;
827 else if (typeString == "float")
828 return UniformModel::Uniform::Type::Float;
829 else if (typeString == "vec2")
830 return UniformModel::Uniform::Type::Vec2;
831 else if (typeString == "vec3")
832 return UniformModel::Uniform::Type::Vec3;
833 else if (typeString == "vec4")
834 return UniformModel::Uniform::Type::Vec4;
835 else if (typeString == "color")
836 return UniformModel::Uniform::Type::Color;
837 else if (typeString == "image")
838 return UniformModel::Uniform::Type::Sampler;
839 else if (typeString == "define")
840 return UniformModel::Uniform::Type::Define;
841
842 qWarning() << QString("Unknown type: %1").arg(a: typeString).toLatin1();
843 return UniformModel::Uniform::Type::Float;
844}
845
846QString UniformModel::stringFromType(Uniform::Type type)
847{
848 QString property;
849 switch (type) {
850 case Uniform::Type::Bool:
851 property = "bool";
852 break;
853 case Uniform::Type::Int:
854 property = "int";
855 break;
856 case Uniform::Type::Float:
857 property = "float";
858 break;
859 case Uniform::Type::Vec2:
860 property = "vec2";
861 break;
862 case Uniform::Type::Vec3:
863 property = "vec3";
864 break;
865 case Uniform::Type::Vec4:
866 property = "vec4";
867 break;
868 case Uniform::Type::Color:
869 property = "color";
870 break;
871 case Uniform::Type::Sampler:
872 property = "image";
873 break;
874 case Uniform::Type::Define:
875 property = "define";
876 break;
877 }
878 return property;
879}
880
881QVariant UniformModel::valueStringToVariant(const Uniform::Type type, const QString &value)
882{
883 QVariant variant;
884 switch (type) {
885 case UniformModel::Uniform::Type::Bool:
886 variant = (value == "true") ? true : false;
887 break;
888 case UniformModel::Uniform::Type::Int:
889 case UniformModel::Uniform::Type::Float:
890 variant = value;
891 break;
892 case UniformModel::Uniform::Type::Vec2:
893 {
894 QStringList list = value.split(sep: QLatin1Char(','));
895 if (list.size() >= 2)
896 variant = QVector2D(list.at(i: 0).toDouble(), list.at(i: 1).toDouble());
897 }
898 break;
899 case UniformModel::Uniform::Type::Vec3:
900 {
901 QStringList list = value.split(sep: QLatin1Char(','));
902 if (list.size() >= 3)
903 variant = QVector3D(list.at(i: 0).toDouble(), list.at(i: 1).toDouble(), list.at(i: 2).toDouble());
904 }
905 break;
906 case UniformModel::Uniform::Type::Vec4:
907 {
908 QStringList list = value.split(sep: QLatin1Char(','));
909 if (list.size() >= 4)
910 variant = QVector4D(list.at(i: 0).toDouble(), list.at(i: 1).toDouble(), list.at(i: 2).toDouble(), list.at(i: 3).toDouble());
911 }
912 break;
913 case UniformModel::Uniform::Type::Color:
914 {
915 QStringList list = value.split(sep: QLatin1Char(','));
916 if (list.size() >= 4)
917 variant = QColor::fromRgbF(r: list.at(i: 0).toDouble(), g: list.at(i: 1).toDouble(), b: list.at(i: 2).toDouble(), a: list.at(i: 3).toDouble());
918 }
919 break;
920 case UniformModel::Uniform::Type::Sampler:
921 variant = value;
922 break;
923 case UniformModel::Uniform::Type::Define:
924 variant = value;
925 break;
926 }
927
928 return variant;
929}
930
931// Update canMoveUp and canMoveDown.
932// When uniform is first/last of its node it can't move up/down.
933void UniformModel::updateCanMoveStatus() {
934 if (m_uniformTable->isEmpty())
935 return;
936 QList<int> usedIds;
937 for (int i = 0; i < m_uniformTable->size() ; i++) {
938 auto &uniform = (*m_uniformTable)[i];
939 if (usedIds.contains(t: uniform.nodeId)) {
940 uniform.canMoveUp = true;
941 } else {
942 uniform.canMoveUp = false;
943 usedIds << uniform.nodeId;
944 }
945 }
946 usedIds.clear();
947 for (int i = m_uniformTable->size() - 1; i >= 0; i--) {
948 auto &uniform = (*m_uniformTable)[i];
949 if (usedIds.contains(t: uniform.nodeId)) {
950 uniform.canMoveDown = true;
951 } else {
952 uniform.canMoveDown = false;
953 usedIds << uniform.nodeId;
954 }
955 }
956 int lastRowIndex = m_uniformTable->size();
957 emit dataChanged(topLeft: QAbstractItemModel::createIndex(arow: 0, acolumn: 0),
958 bottomRight: QAbstractItemModel::createIndex(arow: lastRowIndex, acolumn: 0));
959}
960
961

source code of qtquickeffectmaker/tools/qqem/uniformmodel.cpp