| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2017 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt Data Visualization module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 or (at your option) any later version | 
| 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by | 
| 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | #include "qcustom3ditem_p.h" | 
| 31 |  | 
| 32 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION | 
| 33 |  | 
| 34 | /*! | 
| 35 |  * \class QCustom3DItem | 
| 36 |  * \inmodule QtDataVisualization | 
| 37 |  * \brief The QCustom3DItem class adds a custom item to a graph. | 
| 38 |  * \since QtDataVisualization 1.1 | 
| 39 |  * | 
| 40 |  * A custom item has a custom mesh, position, scaling, rotation, and an optional | 
| 41 |  * texture. | 
| 42 |  * | 
| 43 |  * \sa QAbstract3DGraph::addCustomItem() | 
| 44 |  */ | 
| 45 |  | 
| 46 | /*! | 
| 47 |  * \qmltype Custom3DItem | 
| 48 |  * \inqmlmodule QtDataVisualization | 
| 49 |  * \since QtDataVisualization 1.1 | 
| 50 |  * \ingroup datavisualization_qml | 
| 51 |  * \instantiates QCustom3DItem | 
| 52 |  * \brief Adds a custom item to a graph. | 
| 53 |  * | 
| 54 |  * A custom item has a custom mesh, position, scaling, rotation, and an optional | 
| 55 |  * texture. | 
| 56 |  */ | 
| 57 |  | 
| 58 | /*! \qmlproperty string Custom3DItem::meshFile | 
| 59 |  * | 
| 60 |  * The item mesh file name. The item in the file must be in Wavefront OBJ format and include | 
| 61 |  * vertices, normals, and UVs. It also needs to be in triangles. | 
| 62 |  */ | 
| 63 |  | 
| 64 | /*! \qmlproperty string Custom3DItem::textureFile | 
| 65 |  * | 
| 66 |  * The texture file name for the item. If left unset, a solid gray texture will be | 
| 67 |  * used. | 
| 68 |  * | 
| 69 |  * \note To conserve memory, the QImage loaded from the file is cleared after a | 
| 70 |  * texture is created. | 
| 71 |  */ | 
| 72 |  | 
| 73 | /*! \qmlproperty vector3d Custom3DItem::position | 
| 74 |  * | 
| 75 |  * The item position as a \l vector3d type. Defaults to | 
| 76 |  * \c {vector3d(0.0, 0.0, 0.0)}. | 
| 77 |  * | 
| 78 |  * Item position is specified either in data coordinates or in absolute | 
| 79 |  * coordinates, depending on the value of the positionAbsolute property. When | 
| 80 |  * using absolute coordinates, values between \c{-1.0...1.0} are | 
| 81 |  * within axis ranges. | 
| 82 |  * | 
| 83 |  * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}, | 
| 84 |  * unless the item is a Custom3DVolume that would be partially visible and scalingAbsolute is also | 
| 85 |  * \c{false}. In that case, the visible portion of the volume will be rendered. | 
| 86 |  * | 
| 87 |  * \sa positionAbsolute, scalingAbsolute | 
| 88 |  */ | 
| 89 |  | 
| 90 | /*! \qmlproperty bool Custom3DItem::positionAbsolute | 
| 91 |  * | 
| 92 |  * Defines whether item position is to be handled in data coordinates or in absolute | 
| 93 |  * coordinates. Defaults to \c{false}. Items with absolute coordinates will always be rendered, | 
| 94 |  * whereas items with data coordinates are only rendered if they are within axis ranges. | 
| 95 |  * | 
| 96 |  * \sa position | 
| 97 |  */ | 
| 98 |  | 
| 99 | /*! \qmlproperty vector3d Custom3DItem::scaling | 
| 100 |  * | 
| 101 |  * The item scaling as a \l vector3d type. Defaults to | 
| 102 |  * \c {vector3d(0.1, 0.1, 0.1)}. | 
| 103 |  * | 
| 104 |  * Item scaling is specified either in data values or in absolute values, | 
| 105 |  * depending on the value of the scalingAbsolute property. The default vector | 
| 106 |  * interpreted as absolute values sets the item to | 
| 107 |  * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios | 
| 108 |  * have not been changed from the defaults. | 
| 109 |  * | 
| 110 |  * \sa scalingAbsolute | 
| 111 |  */ | 
| 112 |  | 
| 113 | /*! \qmlproperty bool Custom3DItem::scalingAbsolute | 
| 114 |  * \since QtDataVisualization 1.2 | 
| 115 |  * | 
| 116 |  * Defines whether item scaling is to be handled in data values or in absolute | 
| 117 |  * values. Defaults to \c{true}. Items with absolute scaling will be rendered at the same | 
| 118 |  * size, regardless of axis ranges. Items with data scaling will change their apparent size | 
| 119 |  * according to the axis ranges. If positionAbsolute is \c{true}, this property is ignored | 
| 120 |  * and scaling is interpreted as an absolute value. If the item has rotation, the data scaling | 
| 121 |  * is calculated on the unrotated item. Similarly, for Custom3DVolume items, the range clipping | 
| 122 |  * is calculated on the unrotated item. | 
| 123 |  * | 
| 124 |  * \note Only absolute scaling is supported for Custom3DLabel items or for custom items used in | 
| 125 |  * \l{AbstractGraph3D::polar}{polar} graphs. | 
| 126 |  * | 
| 127 |  * \note The custom item's mesh must be normalized to the range \c{[-1 ,1]}, or the data | 
| 128 |  * scaling will not be accurate. | 
| 129 |  * | 
| 130 |  * \sa scaling, positionAbsolute | 
| 131 |  */ | 
| 132 |  | 
| 133 | /*! \qmlproperty quaternion Custom3DItem::rotation | 
| 134 |  * | 
| 135 |  * The item rotation as a \l quaternion. Defaults to | 
| 136 |  * \c {quaternion(0.0, 0.0, 0.0, 0.0)}. | 
| 137 |  */ | 
| 138 |  | 
| 139 | /*! \qmlproperty bool Custom3DItem::visible | 
| 140 |  * | 
| 141 |  * The visibility of the item. Defaults to \c{true}. | 
| 142 |  */ | 
| 143 |  | 
| 144 | /*! \qmlproperty bool Custom3DItem::shadowCasting | 
| 145 |  * | 
| 146 |  * Defines whether shadow casting for the item is enabled. Defaults to \c{true}. | 
| 147 |  * If \c{false}, the item does not cast shadows regardless of | 
| 148 |  * \l{QAbstract3DGraph::ShadowQuality}{ShadowQuality}. | 
| 149 |  */ | 
| 150 |  | 
| 151 | /*! | 
| 152 |  * \qmlmethod void Custom3DItem::setRotationAxisAndAngle(vector3d axis, real angle) | 
| 153 |  * | 
| 154 |  * A convenience function to construct the rotation quaternion from \a axis and | 
| 155 |  * \a angle. | 
| 156 |  * | 
| 157 |  * \sa rotation | 
| 158 |  */ | 
| 159 |  | 
| 160 | /*! | 
| 161 |  * Constructs a custom 3D item with the specified \a parent. | 
| 162 |  */ | 
| 163 | QCustom3DItem::QCustom3DItem(QObject *parent) : | 
| 164 |     QObject(parent), | 
| 165 |     d_ptr(new QCustom3DItemPrivate(this)) | 
| 166 | { | 
| 167 |     setTextureImage(QImage()); | 
| 168 | } | 
| 169 |  | 
| 170 | /*! | 
| 171 |  * \internal | 
| 172 |  */ | 
| 173 | QCustom3DItem::QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent) : | 
| 174 |     QObject(parent), | 
| 175 |     d_ptr(d) | 
| 176 | { | 
| 177 |     setTextureImage(QImage()); | 
| 178 | } | 
| 179 |  | 
| 180 | /*! | 
| 181 |  * Constructs a custom 3D item with the specified \a meshFile, \a position, \a scaling, | 
| 182 |  * \a rotation, \a texture image, and optional \a parent. | 
| 183 |  */ | 
| 184 | QCustom3DItem::QCustom3DItem(const QString &meshFile, const QVector3D &position, | 
| 185 |                              const QVector3D &scaling, const QQuaternion &rotation, | 
| 186 |                              const QImage &texture, QObject *parent) : | 
| 187 |     QObject(parent), | 
| 188 |     d_ptr(new QCustom3DItemPrivate(this, meshFile, position, scaling, rotation)) | 
| 189 | { | 
| 190 |     setTextureImage(texture); | 
| 191 | } | 
| 192 |  | 
| 193 | /*! | 
| 194 |  * Deletes the custom 3D item. | 
| 195 |  */ | 
| 196 | QCustom3DItem::~QCustom3DItem() | 
| 197 | { | 
| 198 | } | 
| 199 |  | 
| 200 | /*! \property QCustom3DItem::meshFile | 
| 201 |  * | 
| 202 |  * \brief The item mesh file name. | 
| 203 |  * | 
| 204 |  * The item in the file must be in Wavefront OBJ format and include | 
| 205 |  * vertices, normals, and UVs. It also needs to be in triangles. | 
| 206 |  */ | 
| 207 | void QCustom3DItem::setMeshFile(const QString &meshFile) | 
| 208 | { | 
| 209 |     if (d_ptr->m_meshFile != meshFile) { | 
| 210 |         d_ptr->m_meshFile = meshFile; | 
| 211 |         d_ptr->m_dirtyBits.meshDirty = true; | 
| 212 |         emit meshFileChanged(meshFile); | 
| 213 |         emit d_ptr->needUpdate(); | 
| 214 |     } | 
| 215 | } | 
| 216 |  | 
| 217 | QString QCustom3DItem::meshFile() const | 
| 218 | { | 
| 219 |     return d_ptr->m_meshFile; | 
| 220 | } | 
| 221 |  | 
| 222 | /*! \property QCustom3DItem::position | 
| 223 |  * | 
| 224 |  * \brief The item position as a QVector3D. | 
| 225 |  * | 
| 226 |  * Defaults to \c {QVector3D(0.0, 0.0, 0.0)}. | 
| 227 |  * | 
| 228 |  * Item position is specified either in data coordinates or in absolute | 
| 229 |  * coordinates, depending on the | 
| 230 |  * positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are | 
| 231 |  * within axis ranges. | 
| 232 |  * | 
| 233 |  * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}, | 
| 234 |  * unless the item is a QCustom3DVolume that would be partially visible and scalingAbsolute is also | 
| 235 |  * \c{false}. In that case, the visible portion of the volume will be rendered. | 
| 236 |  * | 
| 237 |  * \sa positionAbsolute | 
| 238 |  */ | 
| 239 | void QCustom3DItem::setPosition(const QVector3D &position) | 
| 240 | { | 
| 241 |     if (d_ptr->m_position != position) { | 
| 242 |         d_ptr->m_position = position; | 
| 243 |         d_ptr->m_dirtyBits.positionDirty = true; | 
| 244 |         emit positionChanged(position); | 
| 245 |         emit d_ptr->needUpdate(); | 
| 246 |     } | 
| 247 | } | 
| 248 |  | 
| 249 | QVector3D QCustom3DItem::position() const | 
| 250 | { | 
| 251 |     return d_ptr->m_position; | 
| 252 | } | 
| 253 |  | 
| 254 | /*! \property QCustom3DItem::positionAbsolute | 
| 255 |  * | 
| 256 |  * \brief Whether item position is to be handled in data coordinates or in absolute | 
| 257 |  * coordinates. | 
| 258 |  * | 
| 259 |  * Defaults to \c{false}. Items with absolute coordinates will always be rendered, | 
| 260 |  * whereas items with data coordinates are only rendered if they are within axis ranges. | 
| 261 |  * | 
| 262 |  * \sa position | 
| 263 |  */ | 
| 264 | void QCustom3DItem::setPositionAbsolute(bool positionAbsolute) | 
| 265 | { | 
| 266 |     if (d_ptr->m_positionAbsolute != positionAbsolute) { | 
| 267 |         d_ptr->m_positionAbsolute = positionAbsolute; | 
| 268 |         d_ptr->m_dirtyBits.positionDirty = true; | 
| 269 |         emit positionAbsoluteChanged(positionAbsolute); | 
| 270 |         emit d_ptr->needUpdate(); | 
| 271 |     } | 
| 272 | } | 
| 273 |  | 
| 274 | bool QCustom3DItem::isPositionAbsolute() const | 
| 275 | { | 
| 276 |     return d_ptr->m_positionAbsolute; | 
| 277 | } | 
| 278 |  | 
| 279 | /*! \property QCustom3DItem::scaling | 
| 280 |  * | 
| 281 |  * \brief The item scaling as a QVector3D. | 
| 282 |  * | 
| 283 |  * Defaults to \c {QVector3D(0.1, 0.1, 0.1)}. | 
| 284 |  * | 
| 285 |  * Item scaling is either in data values or in absolute values, depending on the | 
| 286 |  * scalingAbsolute property. The default vector interpreted as absolute values sets the item to | 
| 287 |  * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios | 
| 288 |  * have not been changed from the defaults. | 
| 289 |  * | 
| 290 |  * \sa scalingAbsolute | 
| 291 |  */ | 
| 292 | void QCustom3DItem::setScaling(const QVector3D &scaling) | 
| 293 | { | 
| 294 |     if (d_ptr->m_scaling != scaling) { | 
| 295 |         d_ptr->m_scaling = scaling; | 
| 296 |         d_ptr->m_dirtyBits.scalingDirty = true; | 
| 297 |         emit scalingChanged(scaling); | 
| 298 |         emit d_ptr->needUpdate(); | 
| 299 |     } | 
| 300 | } | 
| 301 |  | 
| 302 | QVector3D QCustom3DItem::scaling() const | 
| 303 | { | 
| 304 |     return d_ptr->m_scaling; | 
| 305 | } | 
| 306 |  | 
| 307 | /*! \property QCustom3DItem::scalingAbsolute | 
| 308 |  * \since QtDataVisualization 1.2 | 
| 309 |  * | 
| 310 |  * \brief Whether item scaling is to be handled in data values or in absolute | 
| 311 |  * values. | 
| 312 |  * | 
| 313 |  * Defaults to \c{true}. | 
| 314 |  * | 
| 315 |  * Items with absolute scaling will be rendered at the same | 
| 316 |  * size, regardless of axis ranges. Items with data scaling will change their apparent size | 
| 317 |  * according to the axis ranges. If positionAbsolute is \c{true}, this property is ignored | 
| 318 |  * and scaling is interpreted as an absolute value. If the item has rotation, the data scaling | 
| 319 |  * is calculated on the unrotated item. Similarly, for QCustom3DVolume items, the range clipping | 
| 320 |  * is calculated on the unrotated item. | 
| 321 |  * | 
| 322 |  * \note Only absolute scaling is supported for QCustom3DLabel items or for custom items used in | 
| 323 |  * \l{QAbstract3DGraph::polar}{polar} graphs. | 
| 324 |  * | 
| 325 |  * \note The custom item's mesh must be normalized to the range \c{[-1 ,1]}, or the data | 
| 326 |  * scaling will not be accurate. | 
| 327 |  * | 
| 328 |  * \sa scaling, positionAbsolute | 
| 329 |  */ | 
| 330 | void QCustom3DItem::setScalingAbsolute(bool scalingAbsolute) | 
| 331 | { | 
| 332 |     if (d_ptr->m_isLabelItem && !scalingAbsolute) { | 
| 333 |         qWarning() << __FUNCTION__ << "Data bounds are not supported for label items." ; | 
| 334 |     } else if (d_ptr->m_scalingAbsolute != scalingAbsolute) { | 
| 335 |         d_ptr->m_scalingAbsolute = scalingAbsolute; | 
| 336 |         d_ptr->m_dirtyBits.scalingDirty = true; | 
| 337 |         emit scalingAbsoluteChanged(scalingAbsolute); | 
| 338 |         emit d_ptr->needUpdate(); | 
| 339 |     } | 
| 340 | } | 
| 341 |  | 
| 342 | bool QCustom3DItem::isScalingAbsolute() const | 
| 343 | { | 
| 344 |     return d_ptr->m_scalingAbsolute; | 
| 345 | } | 
| 346 |  | 
| 347 | /*! \property QCustom3DItem::rotation | 
| 348 |  * | 
| 349 |  * \brief The item rotation as a QQuaternion. | 
| 350 |  * | 
| 351 |  * Defaults to \c {QQuaternion(0.0, 0.0, 0.0, 0.0)}. | 
| 352 |  */ | 
| 353 | void QCustom3DItem::setRotation(const QQuaternion &rotation) | 
| 354 | { | 
| 355 |     if (d_ptr->m_rotation != rotation) { | 
| 356 |         d_ptr->m_rotation = rotation; | 
| 357 |         d_ptr->m_dirtyBits.rotationDirty = true; | 
| 358 |         emit rotationChanged(rotation); | 
| 359 |         emit d_ptr->needUpdate(); | 
| 360 |     } | 
| 361 | } | 
| 362 |  | 
| 363 | QQuaternion QCustom3DItem::rotation() | 
| 364 | { | 
| 365 |     return d_ptr->m_rotation; | 
| 366 | } | 
| 367 |  | 
| 368 | /*! \property QCustom3DItem::visible | 
| 369 |  * | 
| 370 |  * \brief The visibility of the item. | 
| 371 |  * | 
| 372 |  * Defaults to \c{true}. | 
| 373 |  */ | 
| 374 | void QCustom3DItem::setVisible(bool visible) | 
| 375 | { | 
| 376 |     if (d_ptr->m_visible != visible) { | 
| 377 |         d_ptr->m_visible = visible; | 
| 378 |         d_ptr->m_dirtyBits.visibleDirty = true; | 
| 379 |         emit visibleChanged(visible); | 
| 380 |         emit d_ptr->needUpdate(); | 
| 381 |     } | 
| 382 | } | 
| 383 |  | 
| 384 | bool QCustom3DItem::isVisible() const | 
| 385 | { | 
| 386 |     return d_ptr->m_visible; | 
| 387 | } | 
| 388 |  | 
| 389 |  | 
| 390 | /*! \property QCustom3DItem::shadowCasting | 
| 391 |  * | 
| 392 |  * \brief Whether shadow casting for the item is enabled. | 
| 393 |  * | 
| 394 |  * Defaults to \c{true}. | 
| 395 |  * If \c{false}, the item does not cast shadows regardless of QAbstract3DGraph::ShadowQuality. | 
| 396 |  */ | 
| 397 | void QCustom3DItem::setShadowCasting(bool enabled) | 
| 398 | { | 
| 399 |     if (d_ptr->m_shadowCasting != enabled) { | 
| 400 |         d_ptr->m_shadowCasting = enabled; | 
| 401 |         d_ptr->m_dirtyBits.shadowCastingDirty = true; | 
| 402 |         emit shadowCastingChanged(shadowCasting: enabled); | 
| 403 |         emit d_ptr->needUpdate(); | 
| 404 |     } | 
| 405 | } | 
| 406 |  | 
| 407 | bool QCustom3DItem::isShadowCasting() const | 
| 408 | { | 
| 409 |     return d_ptr->m_shadowCasting; | 
| 410 | } | 
| 411 |  | 
| 412 | /*! | 
| 413 |  * A convenience function to construct the rotation quaternion from \a axis and | 
| 414 |  * \a angle. | 
| 415 |  * | 
| 416 |  * \sa rotation | 
| 417 |  */ | 
| 418 | void QCustom3DItem::setRotationAxisAndAngle(const QVector3D &axis, float angle) | 
| 419 | { | 
| 420 |     setRotation(QQuaternion::fromAxisAndAngle(axis, angle)); | 
| 421 | } | 
| 422 |  | 
| 423 | /*! | 
| 424 |  * Sets the value of \a textureImage as a QImage for the item. The texture | 
| 425 |  * defaults to solid gray. | 
| 426 |  * | 
| 427 |  * \note To conserve memory, the given QImage is cleared after a texture is | 
| 428 |  * created. | 
| 429 |  */ | 
| 430 | void QCustom3DItem::setTextureImage(const QImage &textureImage) | 
| 431 | { | 
| 432 |     if (textureImage != d_ptr->m_textureImage) { | 
| 433 |         if (textureImage.isNull()) { | 
| 434 |             // Make a solid gray texture | 
| 435 |             d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32); | 
| 436 |             d_ptr->m_textureImage.fill(color: Qt::gray); | 
| 437 |         } else { | 
| 438 |             d_ptr->m_textureImage = textureImage; | 
| 439 |         } | 
| 440 |  | 
| 441 |         if (!d_ptr->m_textureFile.isEmpty()) { | 
| 442 |             d_ptr->m_textureFile.clear(); | 
| 443 |             emit textureFileChanged(textureFile: d_ptr->m_textureFile); | 
| 444 |         } | 
| 445 |         d_ptr->m_dirtyBits.textureDirty = true; | 
| 446 |         emit d_ptr->needUpdate(); | 
| 447 |     } | 
| 448 | } | 
| 449 |  | 
| 450 | /*! \property QCustom3DItem::textureFile | 
| 451 |  * | 
| 452 |  * \brief The texture file name for the item. | 
| 453 |  * | 
| 454 |  * If both this property and the texture image are unset, a solid | 
| 455 |  * gray texture will be used. | 
| 456 |  * | 
| 457 |  * \note To conserve memory, the QImage loaded from the file is cleared after a | 
| 458 |  * texture is created. | 
| 459 |  */ | 
| 460 | void QCustom3DItem::setTextureFile(const QString &textureFile) | 
| 461 | { | 
| 462 |     if (d_ptr->m_textureFile != textureFile) { | 
| 463 |         d_ptr->m_textureFile = textureFile; | 
| 464 |         if (!textureFile.isEmpty()) { | 
| 465 |             d_ptr->m_textureImage = QImage(textureFile); | 
| 466 |         } else { | 
| 467 |             d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32); | 
| 468 |             d_ptr->m_textureImage.fill(color: Qt::gray); | 
| 469 |         } | 
| 470 |         emit textureFileChanged(textureFile); | 
| 471 |         d_ptr->m_dirtyBits.textureDirty = true; | 
| 472 |         emit d_ptr->needUpdate(); | 
| 473 |     } | 
| 474 | } | 
| 475 |  | 
| 476 | QString QCustom3DItem::textureFile() const | 
| 477 | { | 
| 478 |     return d_ptr->m_textureFile; | 
| 479 | } | 
| 480 |  | 
| 481 | QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) : | 
| 482 |     q_ptr(q), | 
| 483 |     m_textureImage(QImage(1, 1, QImage::Format_ARGB32)), | 
| 484 |     m_position(QVector3D(0.0f, 0.0f, 0.0f)), | 
| 485 |     m_positionAbsolute(false), | 
| 486 |     m_scaling(QVector3D(0.1f, 0.1f, 0.1f)), | 
| 487 |     m_scalingAbsolute(true), | 
| 488 |     m_rotation(identityQuaternion), | 
| 489 |     m_visible(true), | 
| 490 |     m_shadowCasting(true), | 
| 491 |     m_isLabelItem(false), | 
| 492 |     m_isVolumeItem(false) | 
| 493 | { | 
| 494 | } | 
| 495 |  | 
| 496 | QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &meshFile, | 
| 497 |                                            const QVector3D &position, const QVector3D &scaling, | 
| 498 |                                            const QQuaternion &rotation) : | 
| 499 |     q_ptr(q), | 
| 500 |     m_textureImage(QImage(1, 1, QImage::Format_ARGB32)), | 
| 501 |     m_meshFile(meshFile), | 
| 502 |     m_position(position), | 
| 503 |     m_positionAbsolute(false), | 
| 504 |     m_scaling(scaling), | 
| 505 |     m_scalingAbsolute(true), | 
| 506 |     m_rotation(rotation), | 
| 507 |     m_visible(true), | 
| 508 |     m_shadowCasting(true), | 
| 509 |     m_isLabelItem(false), | 
| 510 |     m_isVolumeItem(false) | 
| 511 | { | 
| 512 | } | 
| 513 |  | 
| 514 | QCustom3DItemPrivate::~QCustom3DItemPrivate() | 
| 515 | { | 
| 516 | } | 
| 517 |  | 
| 518 | QImage QCustom3DItemPrivate::textureImage() | 
| 519 | { | 
| 520 |     return m_textureImage; | 
| 521 | } | 
| 522 |  | 
| 523 | void QCustom3DItemPrivate::clearTextureImage() | 
| 524 | { | 
| 525 |     m_textureImage = QImage(); | 
| 526 |     m_textureFile.clear(); | 
| 527 | } | 
| 528 |  | 
| 529 | void QCustom3DItemPrivate::resetDirtyBits() | 
| 530 | { | 
| 531 |     m_dirtyBits.textureDirty = false; | 
| 532 |     m_dirtyBits.meshDirty = false; | 
| 533 |     m_dirtyBits.positionDirty = false; | 
| 534 |     m_dirtyBits.scalingDirty = false; | 
| 535 |     m_dirtyBits.rotationDirty = false; | 
| 536 |     m_dirtyBits.visibleDirty = false; | 
| 537 |     m_dirtyBits.shadowCastingDirty = false; | 
| 538 | } | 
| 539 |  | 
| 540 | QT_END_NAMESPACE_DATAVISUALIZATION | 
| 541 |  |