| 1 | // Copyright (C) 2020 The Qt Company Ltd. | 
|---|---|
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only | 
| 3 | |
| 4 | #ifndef QQUICKKEYFRAMEDATAUTILS_H | 
| 5 | #define QQUICKKEYFRAMEDATAUTILS_H | 
| 6 | |
| 7 | // | 
| 8 | // W A R N I N G | 
| 9 | // ------------- | 
| 10 | // | 
| 11 | // This file is not part of the Qt API. It exists purely as an | 
| 12 | // implementation detail. This header file may change from version to | 
| 13 | // version without notice, or even be removed. | 
| 14 | // | 
| 15 | // We mean it. | 
| 16 | // | 
| 17 | |
| 18 | #include <QtCore/QCborStreamReader> | 
| 19 | #include <QtCore/QCborStreamWriter> | 
| 20 | #include <QtCore/QVariant> | 
| 21 | #include <QtCore/QMetaType> | 
| 22 | |
| 23 | #include <QtCore/QRect> | 
| 24 | #include <QtGui/QVector2D> | 
| 25 | #include <QtGui/QVector3D> | 
| 26 | #include <QtGui/QVector4D> | 
| 27 | #include <QtGui/QQuaternion> | 
| 28 | #include <QtGui/QColor> | 
| 29 | #include <QtCore/private/qglobal_p.h> | 
| 30 | |
| 31 | // This file contains useful methods to read & write keyframes | 
| 32 | // CBOR binary files and understand the format. | 
| 33 | |
| 34 | // Read property 'type' value from CBOR and return it as QVariant. | 
| 35 | QVariant readValue(QCborStreamReader &reader, QMetaType::Type type) | 
| 36 | { | 
| 37 | switch (type) { | 
| 38 | case QMetaType::Bool: { | 
| 39 | bool b = reader.toBool(); | 
| 40 | reader.next(); | 
| 41 | return QVariant(b); | 
| 42 | break; | 
| 43 | } | 
| 44 | case QMetaType::Int: { | 
| 45 | int i = reader.toInteger(); | 
| 46 | reader.next(); | 
| 47 | return QVariant(i); | 
| 48 | break; | 
| 49 | } | 
| 50 | case QMetaType::Float: { | 
| 51 | float f = reader.toFloat(); | 
| 52 | reader.next(); | 
| 53 | return QVariant(f); | 
| 54 | break; | 
| 55 | } | 
| 56 | case QMetaType::Double: { | 
| 57 | double d = reader.toDouble(); | 
| 58 | reader.next(); | 
| 59 | return QVariant(d); | 
| 60 | break; | 
| 61 | } | 
| 62 | case QMetaType::QString: { | 
| 63 | QString s = reader.readString().data; | 
| 64 | return QVariant(s); | 
| 65 | break; | 
| 66 | } | 
| 67 | case QMetaType::QVector2D: { | 
| 68 | QVector2D v; | 
| 69 | v.setX(reader.toFloat()); | 
| 70 | reader.next(); | 
| 71 | v.setY(reader.toFloat()); | 
| 72 | reader.next(); | 
| 73 | return QVariant(v); | 
| 74 | break; | 
| 75 | } | 
| 76 | case QMetaType::QVector3D: { | 
| 77 | QVector3D v; | 
| 78 | v.setX(reader.toFloat()); | 
| 79 | reader.next(); | 
| 80 | v.setY(reader.toFloat()); | 
| 81 | reader.next(); | 
| 82 | v.setZ(reader.toFloat()); | 
| 83 | reader.next(); | 
| 84 | return QVariant(v); | 
| 85 | break; | 
| 86 | } | 
| 87 | case QMetaType::QVector4D: { | 
| 88 | QVector4D v; | 
| 89 | v.setX(reader.toFloat()); | 
| 90 | reader.next(); | 
| 91 | v.setY(reader.toFloat()); | 
| 92 | reader.next(); | 
| 93 | v.setZ(reader.toFloat()); | 
| 94 | reader.next(); | 
| 95 | v.setW(reader.toFloat()); | 
| 96 | reader.next(); | 
| 97 | return QVariant(v); | 
| 98 | break; | 
| 99 | } | 
| 100 | case QMetaType::QQuaternion: { | 
| 101 | QQuaternion q; | 
| 102 | q.setScalar(reader.toFloat()); | 
| 103 | reader.next(); | 
| 104 | q.setX(reader.toFloat()); | 
| 105 | reader.next(); | 
| 106 | q.setY(reader.toFloat()); | 
| 107 | reader.next(); | 
| 108 | q.setZ(reader.toFloat()); | 
| 109 | reader.next(); | 
| 110 | return QVariant(q); | 
| 111 | break; | 
| 112 | } | 
| 113 | case QMetaType::QColor: { | 
| 114 | QColor c; | 
| 115 | c.setRed(reader.toInteger()); | 
| 116 | reader.next(); | 
| 117 | c.setGreen(reader.toInteger()); | 
| 118 | reader.next(); | 
| 119 | c.setBlue(reader.toInteger()); | 
| 120 | reader.next(); | 
| 121 | c.setAlpha(reader.toInteger()); | 
| 122 | reader.next(); | 
| 123 | return QVariant(c); | 
| 124 | break; | 
| 125 | } | 
| 126 | case QMetaType::QRect: { | 
| 127 | QRect r; | 
| 128 | r.setX(reader.toInteger()); | 
| 129 | reader.next(); | 
| 130 | r.setY(reader.toInteger()); | 
| 131 | reader.next(); | 
| 132 | r.setWidth(reader.toInteger()); | 
| 133 | reader.next(); | 
| 134 | r.setHeight(reader.toInteger()); | 
| 135 | reader.next(); | 
| 136 | return QVariant(r); | 
| 137 | break; | 
| 138 | } | 
| 139 | default: { | 
| 140 |         qWarning() << "Keyframe property type not handled:"<< type;  | 
| 141 | } | 
| 142 | } | 
| 143 | |
| 144 | return QVariant(); | 
| 145 | } | 
| 146 | |
| 147 | // Read a string from COB. | 
| 148 | QString readString(QCborStreamReader &reader) | 
| 149 | { | 
| 150 | QString result; | 
| 151 | auto r = reader.readString(); | 
| 152 | while (r.status == QCborStreamReader::Ok) { | 
| 153 | result += r.data; | 
| 154 | r = reader.readString(); | 
| 155 | } | 
| 156 | |
| 157 | if (r.status == QCborStreamReader::Error) { | 
| 158 | // handle error condition | 
| 159 | result.clear(); | 
| 160 | } | 
| 161 | return result; | 
| 162 | } | 
| 163 | |
| 164 | // Read a real (double or float) from CBOR. | 
| 165 | double readReal(QCborStreamReader &reader) | 
| 166 | { | 
| 167 | double result = 0.0; | 
| 168 | if (reader.isDouble()) { | 
| 169 | result = reader.toDouble(); | 
| 170 | reader.next(); | 
| 171 | } else if (reader.isFloat()) { | 
| 172 | result = reader.toFloat(); | 
| 173 | reader.next(); | 
| 174 | } | 
| 175 | return result; | 
| 176 | } | 
| 177 | |
| 178 | // Read keyframes file header and return version. | 
| 179 | // If header is not valid, -1 is returned. | 
| 180 | int readKeyframesHeader(QCborStreamReader &reader) | 
| 181 | { | 
| 182 | int version = -1; | 
| 183 | if (reader.lastError() == QCborError::NoError && reader.isArray()) { | 
| 184 | // Start root array | 
| 185 | reader.enterContainer(); | 
| 186 | if (reader.isString()) { | 
| 187 | QString header = readString(reader); | 
| 188 |             if (header == QStringLiteral("QTimelineKeyframes")) {  | 
| 189 | if (reader.isInteger()) { | 
| 190 | version = reader.toInteger(); | 
| 191 | reader.next(); | 
| 192 | } else { | 
| 193 |                     qWarning() << "Invalid keyframeSource version";  | 
| 194 | } | 
| 195 | } else { | 
| 196 |                 qWarning() << "Invalid keyframeSource header";  | 
| 197 | } | 
| 198 | } else { | 
| 199 |             qWarning() << "Invalid keyframeSource container";  | 
| 200 | } | 
| 201 | } | 
| 202 | return version; | 
| 203 | } | 
| 204 | |
| 205 | void writeKeyframesHeader(QCborStreamWriter &writer, QMetaType::Type type, int version = 1) | 
| 206 | { | 
| 207 | // Root array | 
| 208 | writer.startArray(); | 
| 209 | // header name | 
| 210 |     writer.append(str: "QTimelineKeyframes");  | 
| 211 | // file version | 
| 212 | writer.append(i: version); | 
| 213 | // property type | 
| 214 | writer.append(i: type); | 
| 215 | } | 
| 216 | |
| 217 | // Write QVariant value into CBOR in correct type. | 
| 218 | void writeValue(QCborStreamWriter &writer, const QVariant &value) | 
| 219 | { | 
| 220 | const QMetaType type = value.metaType(); | 
| 221 | switch (type.id()) { | 
| 222 | case QMetaType::Bool: { | 
| 223 | bool b = value.toBool(); | 
| 224 | writer.append(b); | 
| 225 | break; | 
| 226 | } | 
| 227 | case QMetaType::Int: { | 
| 228 | int i = value.toInt(); | 
| 229 | writer.append(i); | 
| 230 | break; | 
| 231 | } | 
| 232 | case QMetaType::Float: { | 
| 233 | float f = value.toFloat(); | 
| 234 | writer.append(f); | 
| 235 | break; | 
| 236 | } | 
| 237 | case QMetaType::Double: { | 
| 238 | double d = value.toDouble(); | 
| 239 | writer.append(d); | 
| 240 | break; | 
| 241 | } | 
| 242 | case QMetaType::QVector2D: { | 
| 243 | QVector2D v = value.value<QVector2D>(); | 
| 244 | writer.append(f: v.x()); | 
| 245 | writer.append(f: v.y()); | 
| 246 | break; | 
| 247 | } | 
| 248 | case QMetaType::QVector3D: { | 
| 249 | QVector3D v = value.value<QVector3D>(); | 
| 250 | writer.append(f: v.x()); | 
| 251 | writer.append(f: v.y()); | 
| 252 | writer.append(f: v.z()); | 
| 253 | break; | 
| 254 | } | 
| 255 | case QMetaType::QVector4D: { | 
| 256 | QVector4D v = value.value<QVector4D>(); | 
| 257 | writer.append(f: v.x()); | 
| 258 | writer.append(f: v.y()); | 
| 259 | writer.append(f: v.z()); | 
| 260 | writer.append(f: v.w()); | 
| 261 | break; | 
| 262 | } | 
| 263 | case QMetaType::QQuaternion: { | 
| 264 | QQuaternion q = value.value<QQuaternion>(); | 
| 265 | writer.append(f: q.scalar()); | 
| 266 | writer.append(f: q.x()); | 
| 267 | writer.append(f: q.y()); | 
| 268 | writer.append(f: q.z()); | 
| 269 | break; | 
| 270 | } | 
| 271 | case QMetaType::QColor: { | 
| 272 | QColor c = value.value<QColor>(); | 
| 273 | writer.append(i: c.red()); | 
| 274 | writer.append(i: c.green()); | 
| 275 | writer.append(i: c.blue()); | 
| 276 | writer.append(i: c.alpha()); | 
| 277 | break; | 
| 278 | } | 
| 279 | case QMetaType::QRect: { | 
| 280 | QRect r = value.value<QRect>(); | 
| 281 | writer.append(i: r.x()); | 
| 282 | writer.append(i: r.y()); | 
| 283 | writer.append(i: r.width()); | 
| 284 | writer.append(i: r.height()); | 
| 285 | break; | 
| 286 | } | 
| 287 | default: { | 
| 288 |         qDebug() << "Not able to add:"<< value << "of type:"<< type.name();  | 
| 289 |         qDebug() << "Please add support for this type into generator.";  | 
| 290 | break; | 
| 291 | } | 
| 292 | } | 
| 293 | } | 
| 294 | |
| 295 | #endif // QQUICKKEYFRAMEDATAUTILS_H | 
| 296 | 
