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