| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt3D module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "gltfgeometryloader.h" |
| |
| #include <QtCore/QDir> |
| #include <QtCore/QJsonArray> |
| #include <QtCore/QJsonObject> |
| #include <QtCore/QVersionNumber> |
| |
| #include <QOpenGLTexture> |
| |
| #include <Qt3DRender/QGeometry> |
| #include <Qt3DRender/private/renderlogging_p.h> |
| #include <Qt3DCore/private/qloadgltf_p.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| #ifndef qUtf16PrintableImpl // -Impl is a Qt 5.8 feature |
| # define qUtf16PrintableImpl(string) \ |
| static_cast<const wchar_t*>(static_cast<const void*>(string.utf16())) |
| #endif |
| |
| namespace Qt3DRender { |
| |
| Q_LOGGING_CATEGORY(GLTFGeometryLoaderLog, "Qt3D.GLTFGeometryLoader", QtWarningMsg) |
| |
| #define KEY_ASSET QLatin1String("asset") |
| #define KEY_ACCESSORS QLatin1String("accessors") |
| #define KEY_ATTRIBUTES QLatin1String("attributes") |
| #define KEY_BUFFER QLatin1String("buffer") |
| #define KEY_BUFFERS QLatin1String("buffers") |
| #define KEY_BYTE_LENGTH QLatin1String("byteLength") |
| #define KEY_BYTE_OFFSET QLatin1String("byteOffset") |
| #define KEY_BYTE_STRIDE QLatin1String("byteStride") |
| #define KEY_COUNT QLatin1String("count") |
| #define KEY_INDICES QLatin1String("indices") |
| #define KEY_MATERIAL QLatin1String("material") |
| #define KEY_MESHES QLatin1String("meshes") |
| #define KEY_NAME QLatin1String("name") |
| #define KEY_PRIMITIVES QLatin1String("primitives") |
| #define KEY_TARGET QLatin1String("target") |
| #define KEY_TYPE QLatin1String("type") |
| #define KEY_URI QLatin1String("uri") |
| #define KEY_VERSION QLatin1String("version") |
| |
| #define KEY_BUFFER_VIEW QLatin1String("bufferView") |
| #define KEY_BUFFER_VIEWS QLatin1String("bufferViews") |
| #define KEY_COMPONENT_TYPE QLatin1String("componentType") |
| |
| GLTFGeometryLoader::GLTFGeometryLoader() |
| : m_geometry(nullptr) |
| { |
| } |
| |
| GLTFGeometryLoader::~GLTFGeometryLoader() |
| { |
| cleanup(); |
| } |
| |
| QGeometry *GLTFGeometryLoader::geometry() const |
| { |
| return m_geometry; |
| } |
| |
| bool GLTFGeometryLoader::load(QIODevice *ioDev, const QString &subMesh) |
| { |
| Q_UNUSED(subMesh); |
| |
| if (Q_UNLIKELY(!setJSON(qLoadGLTF(ioDev->readAll())))) { |
| qCWarning(GLTFGeometryLoaderLog, "not a JSON document"); |
| return false; |
| } |
| |
| auto file = qobject_cast<QFile*>(ioDev); |
| if (file) { |
| QFileInfo finfo(file->fileName()); |
| setBasePath(finfo.dir().absolutePath()); |
| } |
| |
| m_mesh = subMesh; |
| |
| parse(); |
| |
| return true; |
| } |
| |
| GLTFGeometryLoader::BufferData::BufferData() |
| : length(0) |
| , data(nullptr) |
| { |
| } |
| |
| GLTFGeometryLoader::BufferData::BufferData(const QJsonObject &json) |
| : length(json.value(KEY_BYTE_LENGTH).toInt()) |
| , path(json.value(KEY_URI).toString()) |
| , data(nullptr) |
| { |
| } |
| |
| GLTFGeometryLoader::AccessorData::AccessorData() |
| : bufferViewIndex(0) |
| , type(QAttribute::Float) |
| , dataSize(0) |
| , count(0) |
| , offset(0) |
| , stride(0) |
| { |
| |
| } |
| |
| GLTFGeometryLoader::AccessorData::AccessorData(const QJsonObject &json) |
| : bufferViewName(json.value(KEY_BUFFER_VIEW).toString()) |
| , bufferViewIndex(json.value(KEY_BUFFER_VIEW).toInt(-1)) |
| , type(accessorTypeFromJSON(json.value(KEY_COMPONENT_TYPE).toInt())) |
| , dataSize(accessorDataSizeFromJson(json.value(KEY_TYPE).toString())) |
| , count(json.value(KEY_COUNT).toInt()) |
| , offset(0) |
| , stride(0) |
| { |
| const auto byteOffset = json.value(KEY_BYTE_OFFSET); |
| if (!byteOffset.isUndefined()) |
| offset = byteOffset.toInt(); |
| const auto byteStride = json.value(KEY_BYTE_STRIDE); |
| if (!byteStride.isUndefined()) |
| stride = byteStride.toInt(); |
| } |
| |
| void GLTFGeometryLoader::setBasePath(const QString &path) |
| { |
| m_basePath = path; |
| } |
| |
| bool GLTFGeometryLoader::setJSON(const QJsonDocument &json ) |
| { |
| if (!json.isObject()) |
| return false; |
| |
| m_json = json; |
| |
| cleanup(); |
| |
| return true; |
| } |
| |
| QString GLTFGeometryLoader::standardAttributeNameFromSemantic(const QString &semantic) |
| { |
| //Standard Attributes |
| if (semantic.startsWith(QLatin1String("POSITION"))) |
| return QAttribute::defaultPositionAttributeName(); |
| if (semantic.startsWith(QLatin1String("NORMAL"))) |
| return QAttribute::defaultNormalAttributeName(); |
| if (semantic.startsWith(QLatin1String("TEXCOORD"))) |
| return QAttribute::defaultTextureCoordinateAttributeName(); |
| if (semantic.startsWith(QLatin1String("COLOR"))) |
| return QAttribute::defaultColorAttributeName(); |
| if (semantic.startsWith(QLatin1String("TANGENT"))) |
| return QAttribute::defaultTangentAttributeName(); |
| if (semantic.startsWith(QLatin1String("JOINTS"))) |
| return QAttribute::defaultJointIndicesAttributeName(); |
| if (semantic.startsWith(QLatin1String("WEIGHTS"))) |
| return QAttribute::defaultJointWeightsAttributeName(); |
| |
| return QString(); |
| } |
| |
| void GLTFGeometryLoader::parse() |
| { |
| // Find the glTF version |
| const QJsonObject asset = m_json.object().value(KEY_ASSET).toObject(); |
| const QString versionString = asset.value(KEY_VERSION).toString(); |
| const auto version = QVersionNumber::fromString(versionString); |
| switch (version.majorVersion()) { |
| case 1: |
| parseGLTF1(); |
| break; |
| |
| case 2: |
| parseGLTF2(); |
| break; |
| |
| default: |
| qWarning() << "Unsupported version of glTF" << versionString; |
| } |
| } |
| |
| void GLTFGeometryLoader::parseGLTF1() |
| { |
| const QJsonObject buffers = m_json.object().value(KEY_BUFFERS).toObject(); |
| for (auto it = buffers.begin(), end = buffers.end(); it != end; ++it) |
| processJSONBuffer(it.key(), it.value().toObject()); |
| |
| const QJsonObject views = m_json.object().value(KEY_BUFFER_VIEWS).toObject(); |
| loadBufferData(); |
| for (auto it = views.begin(), end = views.end(); it != end; ++it) |
| processJSONBufferView(it.key(), it.value().toObject()); |
| unloadBufferData(); |
| |
| const QJsonObject attrs = m_json.object().value(KEY_ACCESSORS).toObject(); |
| for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) |
| processJSONAccessor(it.key(), it.value().toObject()); |
| |
| const QJsonObject meshes = m_json.object().value(KEY_MESHES).toObject(); |
| for (auto it = meshes.begin(), end = meshes.end(); it != end && !m_geometry; ++it) { |
| const QJsonObject &mesh = it.value().toObject(); |
| if (m_mesh.isEmpty() || |
| m_mesh.compare(mesh.value(KEY_NAME).toString(), Qt::CaseInsensitive) == 0) |
| processJSONMesh(it.key(), mesh); |
| } |
| } |
| |
| void GLTFGeometryLoader::parseGLTF2() |
| { |
| const QJsonArray buffers = m_json.object().value(KEY_BUFFERS).toArray(); |
| for (auto it = buffers.begin(), end = buffers.end(); it != end; ++it) |
| processJSONBufferV2(it->toObject()); |
| |
| const QJsonArray views = m_json.object().value(KEY_BUFFER_VIEWS).toArray(); |
| loadBufferDataV2(); |
| for (auto it = views.begin(), end = views.end(); it != end; ++it) |
| processJSONBufferViewV2(it->toObject()); |
| unloadBufferDataV2(); |
| |
| const QJsonArray attrs = m_json.object().value(KEY_ACCESSORS).toArray(); |
| for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) |
| processJSONAccessorV2(it->toObject()); |
| |
| const QJsonArray meshes = m_json.object().value(KEY_MESHES).toArray(); |
| for (auto it = meshes.begin(), end = meshes.end(); it != end && !m_geometry; ++it) { |
| const QJsonObject &mesh = it->toObject(); |
| if (m_mesh.isEmpty() || m_mesh.compare(mesh.value(KEY_NAME).toString(), Qt::CaseInsensitive) == 0) |
| processJSONMeshV2(mesh); |
| } |
| } |
| |
| void GLTFGeometryLoader::cleanup() |
| { |
| m_geometry = nullptr; |
| m_gltf1.m_accessorDict.clear(); |
| m_gltf1.m_buffers.clear(); |
| } |
| |
| void GLTFGeometryLoader::processJSONBuffer(const QString &id, const QJsonObject &json) |
| { |
| // simply cache buffers for lookup by buffer-views |
| m_gltf1.m_bufferDatas[id] = BufferData(json); |
| } |
| |
| void GLTFGeometryLoader::processJSONBufferV2(const QJsonObject &json) |
| { |
| // simply cache buffers for lookup by buffer-views |
| m_gltf2.m_bufferDatas.push_back(BufferData(json)); |
| } |
| |
| void GLTFGeometryLoader::processJSONBufferView(const QString &id, const QJsonObject &json) |
| { |
| QString bufName = json.value(KEY_BUFFER).toString(); |
| const auto it = qAsConst(m_gltf1.m_bufferDatas).find(bufName); |
| if (Q_UNLIKELY(it == m_gltf1.m_bufferDatas.cend())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer: %ls processing view: %ls", |
| qUtf16PrintableImpl(bufName), qUtf16PrintableImpl(id)); |
| return; |
| } |
| const auto &bufferData = *it; |
| |
| int target = json.value(KEY_TARGET).toInt(); |
| |
| switch (target) { |
| case GL_ARRAY_BUFFER: |
| case GL_ELEMENT_ARRAY_BUFFER: |
| break; |
| default: |
| qCWarning(GLTFGeometryLoaderLog, "buffer %ls unsupported target: %d", |
| qUtf16PrintableImpl(id), target); |
| return; |
| } |
| |
| quint64 offset = 0; |
| const auto byteOffset = json.value(KEY_BYTE_OFFSET); |
| if (!byteOffset.isUndefined()) { |
| offset = byteOffset.toInt(); |
| qCDebug(GLTFGeometryLoaderLog, "bv: %ls has offset: %lld", qUtf16PrintableImpl(id), offset); |
| } |
| |
| const quint64 len = json.value(KEY_BYTE_LENGTH).toInt(); |
| |
| QByteArray bytes = bufferData.data->mid(offset, len); |
| if (Q_UNLIKELY(bytes.count() != int(len))) { |
| qCWarning(GLTFGeometryLoaderLog, "failed to read sufficient bytes from: %ls for view %ls", |
| qUtf16PrintableImpl(bufferData.path), qUtf16PrintableImpl(id)); |
| } |
| |
| Qt3DRender::QBuffer *b = new Qt3DRender::QBuffer(); |
| b->setData(bytes); |
| m_gltf1.m_buffers[id] = b; |
| } |
| |
| void GLTFGeometryLoader::processJSONBufferViewV2(const QJsonObject &json) |
| { |
| const int bufferIndex = json.value(KEY_BUFFER).toInt(); |
| if (Q_UNLIKELY(bufferIndex) >= m_gltf2.m_bufferDatas.size()) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer: %d processing view", bufferIndex); |
| return; |
| } |
| const auto bufferData = m_gltf2.m_bufferDatas[bufferIndex]; |
| |
| int target = json.value(KEY_TARGET).toInt(); |
| switch (target) { |
| case GL_ARRAY_BUFFER: |
| case GL_ELEMENT_ARRAY_BUFFER: |
| break; |
| default: |
| return; |
| } |
| |
| quint64 offset = 0; |
| const auto byteOffset = json.value(KEY_BYTE_OFFSET); |
| if (!byteOffset.isUndefined()) { |
| offset = byteOffset.toInt(); |
| qCDebug(GLTFGeometryLoaderLog, "bufferview has offset: %lld", offset); |
| } |
| |
| const quint64 len = json.value(KEY_BYTE_LENGTH).toInt(); |
| QByteArray bytes = bufferData.data->mid(offset, len); |
| if (Q_UNLIKELY(bytes.count() != int(len))) { |
| qCWarning(GLTFGeometryLoaderLog, "failed to read sufficient bytes from: %ls for view", |
| qUtf16PrintableImpl(bufferData.path)); |
| } |
| |
| auto b = new Qt3DRender::QBuffer; |
| b->setData(bytes); |
| m_gltf2.m_buffers.push_back(b); |
| } |
| |
| void GLTFGeometryLoader::processJSONAccessor(const QString &id, const QJsonObject &json) |
| { |
| m_gltf1.m_accessorDict[id] = AccessorData(json); |
| } |
| |
| void GLTFGeometryLoader::processJSONAccessorV2(const QJsonObject &json) |
| { |
| m_gltf2.m_accessors.push_back(AccessorData(json)); |
| } |
| |
| void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &json) |
| { |
| const QJsonArray primitivesArray = json.value(KEY_PRIMITIVES).toArray(); |
| for (const QJsonValue &primitiveValue : primitivesArray) { |
| QJsonObject primitiveObject = primitiveValue.toObject(); |
| QString material = primitiveObject.value(KEY_MATERIAL).toString(); |
| |
| if (Q_UNLIKELY(material.isEmpty())) { |
| qCWarning(GLTFGeometryLoaderLog, "malformed primitive on %ls, missing material value %ls", |
| qUtf16PrintableImpl(id), qUtf16PrintableImpl(material)); |
| continue; |
| } |
| |
| QGeometry *meshGeometry = new QGeometry; |
| |
| const QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject(); |
| for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) { |
| QString k = it.value().toString(); |
| const auto accessorIt = qAsConst(m_gltf1.m_accessorDict).find(k); |
| if (Q_UNLIKELY(accessorIt == m_gltf1.m_accessorDict.cend())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown attribute accessor: %ls on mesh %ls", |
| qUtf16PrintableImpl(k), qUtf16PrintableImpl(id)); |
| continue; |
| } |
| |
| const QString attrName = it.key(); |
| QString attributeName = standardAttributeNameFromSemantic(attrName); |
| if (attributeName.isEmpty()) |
| attributeName = attrName; |
| |
| //Get buffer handle for accessor |
| Qt3DRender::QBuffer *buffer = m_gltf1.m_buffers.value(accessorIt->bufferViewName, nullptr); |
| if (Q_UNLIKELY(!buffer)) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %ls processing accessor: %ls", |
| qUtf16PrintableImpl(accessorIt->bufferViewName), qUtf16PrintableImpl(id)); |
| continue; |
| } |
| |
| QAttribute *attribute = new QAttribute(buffer, |
| attributeName, |
| accessorIt->type, |
| accessorIt->dataSize, |
| accessorIt->count, |
| accessorIt->offset, |
| accessorIt->stride); |
| attribute->setAttributeType(QAttribute::VertexAttribute); |
| meshGeometry->addAttribute(attribute); |
| } |
| |
| const auto indices = primitiveObject.value(KEY_INDICES); |
| if (!indices.isUndefined()) { |
| QString k = indices.toString(); |
| const auto accessorIt = qAsConst(m_gltf1.m_accessorDict).find(k); |
| if (Q_UNLIKELY(accessorIt == m_gltf1.m_accessorDict.cend())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown index accessor: %ls on mesh %ls", |
| qUtf16PrintableImpl(k), qUtf16PrintableImpl(id)); |
| } else { |
| //Get buffer handle for accessor |
| Qt3DRender::QBuffer *buffer = m_gltf1.m_buffers.value(accessorIt->bufferViewName, nullptr); |
| if (Q_UNLIKELY(!buffer)) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %ls processing accessor: %ls", |
| qUtf16PrintableImpl(accessorIt->bufferViewName), qUtf16PrintableImpl(id)); |
| continue; |
| } |
| |
| QAttribute *attribute = new QAttribute(buffer, |
| accessorIt->type, |
| accessorIt->dataSize, |
| accessorIt->count, |
| accessorIt->offset, |
| accessorIt->stride); |
| attribute->setAttributeType(QAttribute::IndexAttribute); |
| meshGeometry->addAttribute(attribute); |
| } |
| } // of has indices |
| |
| m_geometry = meshGeometry; |
| |
| break; |
| } // of primitives iteration |
| } |
| |
| void GLTFGeometryLoader::processJSONMeshV2(const QJsonObject &json) |
| { |
| const QJsonArray primitivesArray = json.value(KEY_PRIMITIVES).toArray(); |
| for (const QJsonValue &primitiveValue : primitivesArray) { |
| QJsonObject primitiveObject = primitiveValue.toObject(); |
| |
| QGeometry *meshGeometry = new QGeometry; |
| |
| const QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject(); |
| for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) { |
| const int accessorIndex = it.value().toInt(); |
| if (Q_UNLIKELY(accessorIndex >= m_gltf2.m_accessors.size())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown attribute accessor: %d on mesh %ls", |
| accessorIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString())); |
| continue; |
| } |
| const auto &accessor = m_gltf2.m_accessors[accessorIndex]; |
| |
| const QString attrName = it.key(); |
| QString attributeName = standardAttributeNameFromSemantic(attrName); |
| if (attributeName.isEmpty()) |
| attributeName = attrName; |
| |
| // Get buffer handle for accessor |
| if (Q_UNLIKELY(accessor.bufferViewIndex >= m_gltf2.m_buffers.size())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %d processing accessor: %ls", |
| accessor.bufferViewIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString())); |
| continue; |
| } |
| Qt3DRender::QBuffer *buffer = m_gltf2.m_buffers[accessor.bufferViewIndex]; |
| |
| QAttribute *attribute = new QAttribute(buffer, |
| attributeName, |
| accessor.type, |
| accessor.dataSize, |
| accessor.count, |
| accessor.offset, |
| accessor.stride); |
| attribute->setAttributeType(QAttribute::VertexAttribute); |
| meshGeometry->addAttribute(attribute); |
| } |
| |
| const auto indices = primitiveObject.value(KEY_INDICES); |
| if (!indices.isUndefined()) { |
| const int accessorIndex = indices.toInt(); |
| if (Q_UNLIKELY(accessorIndex >= m_gltf2.m_accessors.size())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown index accessor: %d on mesh %ls", |
| accessorIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString())); |
| } else { |
| const auto &accessor = m_gltf2.m_accessors[accessorIndex]; |
| |
| //Get buffer handle for accessor |
| if (Q_UNLIKELY(accessor.bufferViewIndex >= m_gltf2.m_buffers.size())) { |
| qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %d processing accessor: %ls", |
| accessor.bufferViewIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString())); |
| continue; |
| } |
| Qt3DRender::QBuffer *buffer = m_gltf2.m_buffers[accessor.bufferViewIndex]; |
| |
| QAttribute *attribute = new QAttribute(buffer, |
| accessor.type, |
| accessor.dataSize, |
| accessor.count, |
| accessor.offset, |
| accessor.stride); |
| attribute->setAttributeType(QAttribute::IndexAttribute); |
| meshGeometry->addAttribute(attribute); |
| } |
| } // of has indices |
| |
| m_geometry = meshGeometry; |
| |
| break; |
| } // of primitives iteration |
| } |
| |
| void GLTFGeometryLoader::loadBufferData() |
| { |
| for (auto &bufferData : m_gltf1.m_bufferDatas) { |
| if (!bufferData.data) { |
| bufferData.data = new QByteArray(resolveLocalData(bufferData.path)); |
| } |
| } |
| } |
| |
| void GLTFGeometryLoader::unloadBufferData() |
| { |
| for (const auto &bufferData : qAsConst(m_gltf1.m_bufferDatas)) { |
| QByteArray *data = bufferData.data; |
| delete data; |
| } |
| } |
| |
| void GLTFGeometryLoader::loadBufferDataV2() |
| { |
| for (auto &bufferData : m_gltf2.m_bufferDatas) { |
| if (!bufferData.data) |
| bufferData.data = new QByteArray(resolveLocalData(bufferData.path)); |
| } |
| } |
| |
| void GLTFGeometryLoader::unloadBufferDataV2() |
| { |
| for (const auto &bufferData : qAsConst(m_gltf2.m_bufferDatas)) { |
| QByteArray *data = bufferData.data; |
| delete data; |
| } |
| } |
| |
| QByteArray GLTFGeometryLoader::resolveLocalData(const QString &path) const |
| { |
| QDir d(m_basePath); |
| Q_ASSERT(d.exists()); |
| |
| QString absPath = d.absoluteFilePath(path); |
| QFile f(absPath); |
| f.open(QIODevice::ReadOnly); |
| return f.readAll(); |
| } |
| |
| QAttribute::VertexBaseType GLTFGeometryLoader::accessorTypeFromJSON(int componentType) |
| { |
| if (componentType == GL_BYTE) |
| return QAttribute::Byte; |
| else if (componentType == GL_UNSIGNED_BYTE) |
| return QAttribute::UnsignedByte; |
| else if (componentType == GL_SHORT) |
| return QAttribute::Short; |
| else if (componentType == GL_UNSIGNED_SHORT) |
| return QAttribute::UnsignedShort; |
| else if (componentType == GL_UNSIGNED_INT) |
| return QAttribute::UnsignedInt; |
| else if (componentType == GL_FLOAT) |
| return QAttribute::Float; |
| |
| //There shouldn't be an invalid case here |
| qCWarning(GLTFGeometryLoaderLog, "unsupported accessor type %d", componentType); |
| return QAttribute::Float; |
| } |
| |
| uint GLTFGeometryLoader::accessorDataSizeFromJson(const QString &type) |
| { |
| QString typeName = type.toUpper(); |
| if (typeName == QLatin1String("SCALAR")) |
| return 1; |
| if (typeName == QLatin1String("VEC2")) |
| return 2; |
| if (typeName == QLatin1String("VEC3")) |
| return 3; |
| if (typeName == QLatin1String("VEC4")) |
| return 4; |
| if (typeName == QLatin1String("MAT2")) |
| return 4; |
| if (typeName == QLatin1String("MAT3")) |
| return 9; |
| if (typeName == QLatin1String("MAT4")) |
| return 16; |
| |
| return 0; |
| } |
| |
| } // namespace Qt3DRender |
| |
| QT_END_NAMESPACE |