summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/geometryloaders/CMakeLists.txt1
-rw-r--r--src/plugins/geometryloaders/geometryloaders.pro1
-rw-r--r--src/plugins/geometryloaders/gltf/CMakeLists.txt24
-rw-r--r--src/plugins/geometryloaders/gltf/gltf.json3
-rw-r--r--src/plugins/geometryloaders/gltf/gltf.pro16
-rw-r--r--src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp628
-rw-r--r--src/plugins/geometryloaders/gltf/gltfgeometryloader.h194
-rw-r--r--src/plugins/geometryloaders/gltf/main.cpp71
-rw-r--r--tests/auto/render/geometryloaders/CMakeLists.txt1
-rw-r--r--tests/auto/render/geometryloaders/cube.gltf263
-rw-r--r--tests/auto/render/geometryloaders/geometryloaders.qrc1
-rw-r--r--tests/auto/render/geometryloaders/tst_geometryloaders.cpp43
-rw-r--r--tools/CMakeLists.txt5
-rw-r--r--tools/qgltf/CMakeLists.txt22
-rw-r--r--tools/qgltf/qgltf.cpp2589
-rw-r--r--tools/qgltf/qgltf.pro7
-rw-r--r--tools/tools.pro9
17 files changed, 0 insertions, 3878 deletions
diff --git a/src/plugins/geometryloaders/CMakeLists.txt b/src/plugins/geometryloaders/CMakeLists.txt
index d2ccc5ae5..91944f948 100644
--- a/src/plugins/geometryloaders/CMakeLists.txt
+++ b/src/plugins/geometryloaders/CMakeLists.txt
@@ -8,7 +8,6 @@ qt_feature_module_begin(
include(configure.cmake)
qt_feature_module_end(NO_MODULE)
-add_subdirectory(gltf)
if(QT_FEATURE_regularexpression)
add_subdirectory(default)
endif()
diff --git a/src/plugins/geometryloaders/geometryloaders.pro b/src/plugins/geometryloaders/geometryloaders.pro
index 764c615da..c462493a4 100644
--- a/src/plugins/geometryloaders/geometryloaders.pro
+++ b/src/plugins/geometryloaders/geometryloaders.pro
@@ -1,4 +1,3 @@
TEMPLATE = subdirs
qtConfig(regularexpression) : SUBDIRS += default
-SUBDIRS += gltf
qtConfig(qt3d-fbxsdk) : SUBDIRS += fbx
diff --git a/src/plugins/geometryloaders/gltf/CMakeLists.txt b/src/plugins/geometryloaders/gltf/CMakeLists.txt
deleted file mode 100644
index aa8f80c19..000000000
--- a/src/plugins/geometryloaders/gltf/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated from gltf.pro.
-
-#####################################################################
-## GLTFGeometryLoaderPlugin Plugin:
-#####################################################################
-
-qt_internal_add_plugin(GLTFGeometryLoaderPlugin
- OUTPUT_NAME gltfgeometryloader
- TYPE geometryloaders
- SOURCES
- gltfgeometryloader.cpp gltfgeometryloader.h
- main.cpp
- PUBLIC_LIBRARIES
- Qt::3DCore
- Qt::3DCorePrivate
- Qt::3DRender
- Qt::3DRenderPrivate
- Qt::Core
- Qt::CorePrivate
- Qt::Gui
-)
-
-#### Keys ignored in scope 1:.:.:gltf.pro:<TRUE>:
-# DISTFILES = "gltf.json"
diff --git a/src/plugins/geometryloaders/gltf/gltf.json b/src/plugins/geometryloaders/gltf/gltf.json
deleted file mode 100644
index 9ad97ce1a..000000000
--- a/src/plugins/geometryloaders/gltf/gltf.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": ["gltf", "json", "qgltf"]
-}
diff --git a/src/plugins/geometryloaders/gltf/gltf.pro b/src/plugins/geometryloaders/gltf/gltf.pro
deleted file mode 100644
index 815226b4e..000000000
--- a/src/plugins/geometryloaders/gltf/gltf.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = gltfgeometryloader
-QT += core-private 3dcore 3dcore-private 3drender 3drender-private
-
-HEADERS += \
- gltfgeometryloader.h \
-
-SOURCES += \
- main.cpp \
- gltfgeometryloader.cpp \
-
-DISTFILES += \
- gltf.json
-
-PLUGIN_TYPE = geometryloaders
-PLUGIN_CLASS_NAME = GLTFGeometryLoaderPlugin
-load(qt_plugin)
diff --git a/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp b/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp
deleted file mode 100644
index 9f13ca2c6..000000000
--- a/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp
+++ /dev/null
@@ -1,628 +0,0 @@
-/****************************************************************************
-**
-** 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/private/renderlogging_p.h>
-#include <Qt3DCore/QGeometry>
-#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
-
-using namespace Qt3DCore;
-
-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));
- }
-
- Qt3DCore::QBuffer *b = new Qt3DCore::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 Qt3DCore::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
- Qt3DCore::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
- Qt3DCore::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;
- }
- Qt3DCore::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;
- }
- Qt3DCore::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
diff --git a/src/plugins/geometryloaders/gltf/gltfgeometryloader.h b/src/plugins/geometryloaders/gltf/gltfgeometryloader.h
deleted file mode 100644
index 36ac0f174..000000000
--- a/src/plugins/geometryloaders/gltf/gltfgeometryloader.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#ifndef GLTFGEOMETRYLOADER_H
-#define GLTFGEOMETRYLOADER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QJsonDocument>
-
-#include <Qt3DRender/private/qgeometryloaderinterface_p.h>
-#include <Qt3DCore/qattribute.h>
-#include <Qt3DCore/qbuffer.h>
-
-#include <private/qlocale_tools_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DCore {
-class QGeometry;
-}
-
-namespace Qt3DRender {
-
-#define GLTFGEOMETRYLOADER_EXT QLatin1String("gltf")
-#define JSONGEOMETRYLOADER_EXT QLatin1String("json")
-#define QGLTFGEOMETRYLOADER_EXT QLatin1String("qgltf")
-
-class QCamera;
-class QCameraLens;
-class QMaterial;
-class QShaderProgram;
-class QEffect;
-class QAbstractTexture;
-class QRenderState;
-class QTechnique;
-class QParameter;
-class QGeometryRenderer;
-
-class GLTFGeometryLoader : public QGeometryLoaderInterface
-{
- class BufferData
- {
- public:
- BufferData();
- explicit BufferData(const QJsonObject &json);
-
- quint64 length;
- QString path;
- QByteArray *data;
- // type if ever useful
- };
-
- class ParameterData
- {
- public:
- ParameterData();
- explicit ParameterData(const QJsonObject &json);
-
- QString semantic;
- int type;
- };
-
- class AccessorData
- {
- public:
- AccessorData();
- explicit AccessorData(const QJsonObject &json);
-
- QString bufferViewName;
- int bufferViewIndex;
- Qt3DCore::QAttribute::VertexBaseType type;
- uint dataSize;
- int count;
- int offset;
- int stride;
- };
-
- struct Gltf1
- {
- QHash<QString, AccessorData> m_accessorDict;
- QHash<QString, BufferData> m_bufferDatas;
- QHash<QString, Qt3DCore::QBuffer*> m_buffers;
- };
-
- struct Gltf2
- {
- QVector<BufferData> m_bufferDatas;
- QVector<Qt3DCore::QBuffer*> m_buffers;
- QVector<AccessorData> m_accessors;
- };
-
- Q_OBJECT
-public:
- GLTFGeometryLoader();
- ~GLTFGeometryLoader();
-
- Qt3DCore::QGeometry *geometry() const final;
-
- bool load(QIODevice *ioDev, const QString &subMesh = QString()) final;
-
-protected:
- void setBasePath(const QString &path);
- bool setJSON(const QJsonDocument &json);
-
- static QString standardAttributeNameFromSemantic(const QString &semantic);
-
- void parse();
- void parseGLTF1();
- void parseGLTF2();
- void cleanup();
-
- void processJSONBuffer(const QString &id, const QJsonObject &json);
- void processJSONBufferView(const QString &id, const QJsonObject &json);
- void processJSONAccessor(const QString &id, const QJsonObject &json);
- void processJSONMesh(const QString &id, const QJsonObject &json);
-
- void loadBufferData();
- void unloadBufferData();
-
- void processJSONBufferV2(const QJsonObject &json);
- void processJSONBufferViewV2(const QJsonObject &json);
- void processJSONAccessorV2(const QJsonObject &json);
- void processJSONMeshV2(const QJsonObject &json);
-
- void loadBufferDataV2();
- void unloadBufferDataV2();
-
- QByteArray resolveLocalData(const QString &path) const;
-
- static Qt3DCore::QAttribute::VertexBaseType accessorTypeFromJSON(int componentType);
- static uint accessorDataSizeFromJson(const QString &type);
-
-private:
- QJsonDocument m_json;
- QString m_basePath;
- QString m_mesh;
-
- Gltf1 m_gltf1;
- Gltf2 m_gltf2;
-
- Qt3DCore::QGeometry *m_geometry;
-};
-
-} // namespace Qt3DRender
-
-QT_END_NAMESPACE
-
-#endif // GLTFGEOMETRYLOADER_H
diff --git a/src/plugins/geometryloaders/gltf/main.cpp b/src/plugins/geometryloaders/gltf/main.cpp
deleted file mode 100644
index ee27e1325..000000000
--- a/src/plugins/geometryloaders/gltf/main.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** 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 <Qt3DRender/private/qgeometryloaderfactory_p.h>
-
-#include "gltfgeometryloader.h"
-
-QT_BEGIN_NAMESPACE
-
-class GLTFGeometryLoaderPlugin : public Qt3DRender::QGeometryLoaderFactory
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QGeometryLoaderFactory_iid FILE "gltf.json")
-public:
-
- QStringList keys() const override
- {
- return QStringList() << GLTFGEOMETRYLOADER_EXT
- << JSONGEOMETRYLOADER_EXT
- << QGLTFGEOMETRYLOADER_EXT;
- }
-
- Qt3DRender::QGeometryLoaderInterface *create(const QString &ext) override
- {
- if ((ext.compare(GLTFGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0) ||
- (ext.compare(JSONGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0) ||
- (ext.compare(QGLTFGEOMETRYLOADER_EXT, Qt::CaseInsensitive) == 0))
- return new Qt3DRender::GLTFGeometryLoader;
- return nullptr;
- }
-};
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/tests/auto/render/geometryloaders/CMakeLists.txt b/tests/auto/render/geometryloaders/CMakeLists.txt
index dab7699c9..ac45579bb 100644
--- a/tests/auto/render/geometryloaders/CMakeLists.txt
+++ b/tests/auto/render/geometryloaders/CMakeLists.txt
@@ -19,7 +19,6 @@ qt_add_test(tst_geometryloaders
# Resources:
set(geometryloaders_resource_files
"cube.fbx"
- "cube.gltf"
"cube.obj"
"cube.ply"
"cube.stl"
diff --git a/tests/auto/render/geometryloaders/cube.gltf b/tests/auto/render/geometryloaders/cube.gltf
deleted file mode 100644
index c60ae4ad9..000000000
--- a/tests/auto/render/geometryloaders/cube.gltf
+++ /dev/null
@@ -1,263 +0,0 @@
-{
- "accessors": {
- "accessor_index_0": {
- "bufferView": "bufferView_1",
- "byteOffset": 0,
- "byteStride": 0,
- "componentType": 5123,
- "count": 36,
- "type": "SCALAR",
- "min": [
- 0
- ],
- "max": [
- 23
- ]
- },
- "accessor_position": {
- "bufferView": "bufferView_0",
- "byteOffset": 0,
- "byteStride": 0,
- "componentType": 5126,
- "count": 24,
- "min": [
- -1,
- -1,
- -1
- ],
- "max": [
- 1,
- 1,
- 1.0000009536743164
- ],
- "type": "VEC3"
- },
- "accessor_normal": {
- "bufferView": "bufferView_0",
- "byteOffset": 288,
- "byteStride": 0,
- "componentType": 5126,
- "count": 24,
- "type": "VEC3",
- "min": [
- -1,
- -1,
- -1
- ],
- "max": [
- 1,
- 1,
- 1
- ]
- }
- },
- "asset": {
- "generator": "OBJ2GLTF",
- "premultipliedAlpha": true,
- "profile": {
- "api": "WebGL",
- "version": "1.0"
- },
- "version": "1.0"
- },
- "buffers": {
- "cube_buffer": {
- "type": "arraybuffer",
- "byteLength": 648,
- "uri": "cube_buffer.bin"
- }
- },
- "bufferViews": {
- "bufferView_0": {
- "buffer": "cube_buffer",
- "byteLength": 576,
- "byteOffset": 0,
- "target": 34962
- },
- "bufferView_1": {
- "buffer": "cube_buffer",
- "byteLength": 72,
- "byteOffset": 576,
- "target": 34963
- }
- },
- "images": {},
- "materials": {
- "material_czmDefaultMat": {
- "name": "czmDefaultMat",
- "extensions": {},
- "values": {
- "ambient": [
- 0,
- 0,
- 0,
- 1
- ],
- "diffuse": [
- 0.5,
- 0.5,
- 0.5,
- 1
- ],
- "emission": [
- 0,
- 0,
- 0,
- 1
- ],
- "specular": [
- 0,
- 0,
- 0,
- 1
- ],
- "shininess": 0,
- "transparency": 1
- },
- "technique": "technique0"
- }
- },
- "meshes": {
- "mesh_cube": {
- "name": "cube",
- "primitives": [
- {
- "attributes": {
- "POSITION": "accessor_position",
- "NORMAL": "accessor_normal"
- },
- "indices": "accessor_index_0",
- "material": "material_czmDefaultMat",
- "mode": 4
- }
- ]
- }
- },
- "nodes": {
- "rootNode": {
- "children": [],
- "meshes": [
- "mesh_cube"
- ],
- "matrix": [
- 1,
- 0,
- 0,
- 0,
- 0,
- 1,
- 0,
- 0,
- 0,
- 0,
- 1,
- 0,
- 0,
- 0,
- 0,
- 1
- ]
- }
- },
- "samplers": {},
- "scene": "scene_cube",
- "scenes": {
- "scene_cube": {
- "nodes": [
- "rootNode"
- ]
- }
- },
- "textures": {},
- "extensionsUsed": [],
- "animations": {},
- "cameras": {},
- "techniques": {
- "technique0": {
- "attributes": {
- "a_position": "position",
- "a_normal": "normal"
- },
- "parameters": {
- "modelViewMatrix": {
- "semantic": "MODELVIEW",
- "type": 35676
- },
- "projectionMatrix": {
- "semantic": "PROJECTION",
- "type": 35676
- },
- "normalMatrix": {
- "semantic": "MODELVIEWINVERSETRANSPOSE",
- "type": 35675
- },
- "ambient": {
- "type": 35666
- },
- "diffuse": {
- "type": 35666
- },
- "emission": {
- "type": 35666
- },
- "specular": {
- "type": 35666
- },
- "shininess": {
- "type": 5126
- },
- "transparency": {
- "type": 5126
- },
- "position": {
- "semantic": "POSITION",
- "type": 35665
- },
- "normal": {
- "semantic": "NORMAL",
- "type": 35665
- }
- },
- "program": "program0",
- "states": {
- "enable": [
- 2884,
- 2929
- ]
- },
- "uniforms": {
- "u_modelViewMatrix": "modelViewMatrix",
- "u_projectionMatrix": "projectionMatrix",
- "u_normalMatrix": "normalMatrix",
- "u_ambient": "ambient",
- "u_diffuse": "diffuse",
- "u_emission": "emission",
- "u_specular": "specular",
- "u_shininess": "shininess",
- "u_transparency": "transparency"
- }
- }
- },
- "programs": {
- "program0": {
- "attributes": [
- "a_position",
- "a_normal"
- ],
- "fragmentShader": "fragmentShader0",
- "vertexShader": "vertexShader0"
- }
- },
- "shaders": {
- "vertexShader0": {
- "type": 35633,
- "uri": "vertexShader0.glsl"
- },
- "fragmentShader0": {
- "type": 35632,
- "uri": "fragmentShader0.glsl"
- }
- },
- "skins": {},
- "extensions": {}
-}
diff --git a/tests/auto/render/geometryloaders/geometryloaders.qrc b/tests/auto/render/geometryloaders/geometryloaders.qrc
index 8f98f5a14..a15332941 100644
--- a/tests/auto/render/geometryloaders/geometryloaders.qrc
+++ b/tests/auto/render/geometryloaders/geometryloaders.qrc
@@ -4,7 +4,6 @@
<file>cube2.obj</file>
<file>cube.ply</file>
<file>cube.stl</file>
- <file>cube.gltf</file>
<file>cube_buffer.bin</file>
<file>cube.fbx</file>
</qresource>
diff --git a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
index 7fc914cda..e0141a51d 100644
--- a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
+++ b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
@@ -65,7 +65,6 @@ private Q_SLOTS:
void testOBJLoader();
void testPLYLoader();
void testSTLLoader();
- void testGLTFLoader();
#ifdef QT_3DGEOMETRYLOADERS_FBX
void testFBXLoader();
#endif
@@ -194,48 +193,6 @@ void tst_geometryloaders::testSTLLoader()
file.close();
}
-void tst_geometryloaders::testGLTFLoader()
-{
- QScopedPointer<QGeometryLoaderInterface> loader;
- loader.reset(qLoadPlugin<QGeometryLoaderInterface, QGeometryLoaderFactory>(geometryLoader(), QStringLiteral("gltf")));
- QVERIFY(loader);
- if (!loader)
- return;
-
- QFile file(QStringLiteral(":/cube.gltf"));
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- qDebug("Could not open test file for reading");
- return;
- }
-
- bool loaded = loader->load(&file, QStringLiteral("Cube"));
- QVERIFY(loaded);
- if (!loaded)
- return;
-
- QGeometry *geometry = loader->geometry();
- QVERIFY(geometry);
- if (!geometry)
- return;
-
- QCOMPARE(geometry->attributes().count(), 3);
- for (QAttribute *attr : geometry->attributes()) {
- switch (attr->attributeType()) {
- case QAttribute::IndexAttribute:
- QCOMPARE(attr->count(), 36u);
- break;
- case QAttribute::VertexAttribute:
- QCOMPARE(attr->count(), 24u);
- break;
- default:
- Q_UNREACHABLE();
- break;
- }
- }
-
- file.close();
-}
-
#ifdef QT_3DGEOMETRYLOADERS_FBX
void tst_geometryloaders::testFBXLoader()
{
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
deleted file mode 100644
index d9e4ecdcd..000000000
--- a/tools/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# Generated from tools.pro.
-
-#if(QT_FEATURE_assimp AND QT_FEATURE_commandlineparser AND NOT CMAKE_CROSSCOMPILING)
-# add_subdirectory(qgltf)
-#endif()
diff --git a/tools/qgltf/CMakeLists.txt b/tools/qgltf/CMakeLists.txt
deleted file mode 100644
index be90beda8..000000000
--- a/tools/qgltf/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated from qgltf.pro.
-
-#####################################################################
-## qgltf Tool:
-#####################################################################
-
-qt_add_tool(qgltf
- TOOLS_TARGET 3DRender # special case
- SOURCES
- qgltf.cpp
- EXCEPTIONS # special case
- PUBLIC_LIBRARIES
- Qt::Gui
-)
-
-#### Keys ignored in scope 1:.:.:qgltf.pro:<TRUE>:
-# _OPTION = "host_build"
-
-## Scopes:
-#####################################################################
-include(../../src/3rdparty/assimp/assimp.cmake)
-qt3d_extend_target_for_assimp(qgltf)
diff --git a/tools/qgltf/qgltf.cpp b/tools/qgltf/qgltf.cpp
deleted file mode 100644
index 559ad7691..000000000
--- a/tools/qgltf/qgltf.cpp
+++ /dev/null
@@ -1,2589 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <assimp/Importer.hpp>
-#include <assimp/IOStream.hpp>
-#include <assimp/IOSystem.hpp>
-#include <assimp/scene.h>
-#include <assimp/postprocess.h>
-
-#include <qiodevice.h>
-#include <qfile.h>
-#include <qfileinfo.h>
-#include <qdir.h>
-#include <qhash.h>
-#include <qdebug.h>
-#include <qcoreapplication.h>
-#include <qcommandlineparser.h>
-#include <qjsondocument.h>
-#include <qjsonobject.h>
-#include <qjsonarray.h>
-#include <qcborvalue.h>
-#include <qmath.h>
-
-#define GLT_UNSIGNED_SHORT 0x1403
-#define GLT_UNSIGNED_INT 0x1405
-#define GLT_FLOAT 0x1406
-
-#define GLT_FLOAT_VEC2 0x8B50
-#define GLT_FLOAT_VEC3 0x8B51
-#define GLT_FLOAT_VEC4 0x8B52
-#define GLT_FLOAT_MAT3 0x8B5B
-#define GLT_FLOAT_MAT4 0x8B5C
-#define GLT_SAMPLER_2D 0x8B5E
-
-#define GLT_ARRAY_BUFFER 0x8892
-#define GLT_ELEMENT_ARRAY_BUFFER 0x8893
-
-#define GLT_DEPTH_TEST 0x0B71
-#define GLT_CULL_FACE 0x0B44
-#define GLT_BLEND 0x0BE2
-
-class AssimpIOStream : public Assimp::IOStream
-{
-public:
- AssimpIOStream(QIODevice *device);
- ~AssimpIOStream();
-
- size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override;
- size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) override;
- aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
- size_t Tell() const override;
- size_t FileSize() const override;
- void Flush() override;
-
-private:
- QIODevice *m_device;
-};
-
-class AssimpIOSystem : public Assimp::IOSystem
-{
-public:
- bool Exists(const char *pFile) const override;
- char getOsSeparator() const override;
- Assimp::IOStream *Open(const char *pFile, const char *pMode) override;
- void Close(Assimp::IOStream *pFile) override;
-};
-
-AssimpIOStream::AssimpIOStream(QIODevice *device) :
- m_device(device)
-{
- Q_ASSERT(m_device);
-}
-
-AssimpIOStream::~AssimpIOStream()
-{
- delete m_device;
-}
-
-size_t AssimpIOStream::Read(void *pvBuffer, size_t pSize, size_t pCount)
-{
- qint64 readBytes = m_device->read((char *)pvBuffer, pSize * pCount);
- if (readBytes < 0)
- qWarning() << Q_FUNC_INFO << " read failed";
- return readBytes;
-}
-
-size_t AssimpIOStream::Write(const void *pvBuffer, size_t pSize, size_t pCount)
-{
- qint64 writtenBytes = m_device->write((char *)pvBuffer, pSize * pCount);
- if (writtenBytes < 0)
- qWarning() << Q_FUNC_INFO << " write failed";
- return writtenBytes;
-}
-
-aiReturn AssimpIOStream::Seek(size_t pOffset, aiOrigin pOrigin)
-{
- qint64 seekPos = pOffset;
-
- if (pOrigin == aiOrigin_CUR)
- seekPos += m_device->pos();
- else if (pOrigin == aiOrigin_END)
- seekPos += m_device->size();
-
- if (!m_device->seek(seekPos)) {
- qWarning() << Q_FUNC_INFO << " seek failed";
- return aiReturn_FAILURE;
- }
- return aiReturn_SUCCESS;
-}
-
-size_t AssimpIOStream::Tell() const
-{
- return m_device->pos();
-}
-
-size_t AssimpIOStream::FileSize() const
-{
- return m_device->size();
-}
-
-void AssimpIOStream::Flush()
-{
- // we don't write via assimp
-}
-
-static QIODevice::OpenMode openModeFromText(const char *name) noexcept
-{
- static const struct OpenModeMapping {
- char name[2];
- int mode;
- } openModeMapping[] = {
- { { 'r', 0 }, QIODevice::ReadOnly },
- { { 'r', '+' }, QIODevice::ReadWrite },
- { { 'w', 0 }, QIODevice::WriteOnly | QIODevice::Truncate },
- { { 'w', '+' }, QIODevice::ReadWrite | QIODevice::Truncate },
- { { 'a', 0 }, QIODevice::WriteOnly | QIODevice::Append },
- { { 'a', '+' }, QIODevice::ReadWrite | QIODevice::Append },
- { { 'w', 'b' }, QIODevice::WriteOnly },
- { { 'w', 't' }, QIODevice::WriteOnly | QIODevice::Text },
- { { 'r', 'b' }, QIODevice::ReadOnly },
- { { 'r', 't' }, QIODevice::ReadOnly | QIODevice::Text },
- };
-
- for (auto e : openModeMapping) {
- if (qstrncmp(e.name, name, sizeof(OpenModeMapping::name)) == 0)
- return static_cast<QIODevice::OpenMode>(e.mode);
- }
- return QIODevice::NotOpen;
-}
-
-bool AssimpIOSystem::Exists(const char *pFile) const
-{
- return QFileInfo::exists(QString::fromUtf8(pFile));
-}
-
-char AssimpIOSystem::getOsSeparator() const
-{
- return QDir::separator().toLatin1();
-}
-
-Assimp::IOStream *AssimpIOSystem::Open(const char *pFile, const char *pMode)
-{
- const QString fileName(QString::fromUtf8(pFile));
- const QLatin1String cleanedMode = QLatin1String{pMode}.trimmed();
-
- if (const QIODevice::OpenMode openMode = openModeFromText(cleanedMode.data())) {
- QScopedPointer<QFile> file(new QFile(fileName));
- if (file->open(openMode))
- return new AssimpIOStream(file.take());
- }
-
- return nullptr;
-}
-
-void AssimpIOSystem::Close(Assimp::IOStream *pFile)
-{
- delete pFile;
-}
-
-static inline QString ai2qt(const aiString &str)
-{
- return QString::fromUtf8(str.data, int(str.length));
-}
-
-static inline QVector<float> ai2qt(const aiMatrix4x4 &matrix)
-{
- return QVector<float>() << matrix.a1 << matrix.b1 << matrix.c1 << matrix.d1
- << matrix.a2 << matrix.b2 << matrix.c2 << matrix.d2
- << matrix.a3 << matrix.b3 << matrix.c3 << matrix.d3
- << matrix.a4 << matrix.b4 << matrix.c4 << matrix.d4;
-}
-
-struct Options {
- QString outDir;
-#if QT_CONFIG(cborstreamwriter)
- bool genBin;
-#endif
- bool compact;
- bool compress;
- bool genTangents;
- bool interleave;
- float scale;
- bool genCore;
- enum TextureCompression {
- NoTextureCompression,
- ETC1
- };
- TextureCompression texComp;
- bool commonMat;
- bool shaders;
- bool showLog;
-} opts;
-
-class Importer
-{
-public:
- Importer();
- virtual ~Importer();
-
- virtual bool load(const QString &filename) = 0;
-
- struct BufferInfo {
- QString name;
- QByteArray data;
- };
- QVector<BufferInfo> buffers() const;
-
- struct MeshInfo {
- struct BufferView {
- BufferView() : bufIndex(0), offset(0), length(0), componentType(0), target(0) { }
- QString name;
- uint bufIndex;
- uint offset;
- uint length;
- uint componentType;
- uint target;
- };
- QVector<BufferView> views;
- struct Accessor {
- Accessor() : offset(0), stride(0), count(0), componentType(0) { }
- QString name;
- QString usage;
- QString bufferView;
- uint offset;
- uint stride;
- uint count;
- uint componentType;
- QString type;
- QVector<float> minVal;
- QVector<float> maxVal;
- };
- QVector<Accessor> accessors;
- QString name; // generated
- QString originalName; // may be empty
- uint materialIndex;
- };
-
- QVector<MeshInfo::BufferView> bufferViews() const;
- QVector<MeshInfo::Accessor> accessors() const;
- uint meshCount() const;
- MeshInfo meshInfo(uint meshIndex) const;
-
- struct MaterialInfo {
- QString name;
- QString originalName;
- QHash<QByteArray, QVector<float> > m_colors;
- QHash<QByteArray, float> m_values;
- QHash<QByteArray, QString> m_textures;
- };
- uint materialCount() const;
- MaterialInfo materialInfo(uint materialIndex) const;
-
- QSet<QString> externalTextures() const;
-
- struct CameraInfo {
- QString name; // suffixed
- float aspectRatio;
- float yfov;
- float zfar;
- float znear;
- };
- QHash<QString, CameraInfo> cameraInfo() const;
-
- struct EmbeddedTextureInfo {
- EmbeddedTextureInfo() { }
- QString name;
-#ifdef HAS_QIMAGE
- EmbeddedTextureInfo(const QString &name, const QImage &image) : name(name), image(image) { }
- QImage image;
-#endif
- };
- QHash<QString, EmbeddedTextureInfo> embeddedTextures() const;
-
- struct Node {
- QString name;
- QString uniqueName; // generated
- QVector<float> transformation;
- QVector<Node *> children;
- QVector<uint> meshes;
- };
- const Node *rootNode() const;
-
- struct KeyFrame {
- KeyFrame() : t(0), transValid(false), rotValid(false), scaleValid(false) { }
- float t;
- bool transValid;
- QVector<float> trans;
- bool rotValid;
- QVector<float> rot;
- bool scaleValid;
- QVector<float> scale;
- };
- struct AnimationInfo {
- AnimationInfo() : hasTranslation(false), hasRotation(false), hasScale(false) { }
- QString name;
- QString targetNode;
- bool hasTranslation;
- bool hasRotation;
- bool hasScale;
- QVector<KeyFrame> keyFrames;
- };
- QVector<AnimationInfo> animations() const;
-
- bool allMeshesForMaterialHaveTangents(uint materialIndex) const;
-
- const Node *findNode(const Node *root, const QString &originalName) const;
-
-protected:
- void delNode(Importer::Node *n);
-
- QByteArray m_buffer;
- QHash<uint, MeshInfo> m_meshInfo;
- QHash<uint, MaterialInfo> m_materialInfo;
- QHash<QString, EmbeddedTextureInfo> m_embeddedTextures;
- QSet<QString> m_externalTextures;
- QHash<QString, CameraInfo> m_cameraInfo;
- Node *m_rootNode;
- QVector<AnimationInfo> m_animations;
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(Importer::BufferInfo, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::MeshInfo::BufferView, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::MeshInfo::Accessor, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::MaterialInfo, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::CameraInfo, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::EmbeddedTextureInfo, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::Node, Q_COMPLEX_TYPE); // uses address as identity
-Q_DECLARE_TYPEINFO(Importer::KeyFrame, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(Importer::AnimationInfo, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-Importer::Importer()
- : m_rootNode(nullptr)
-{
-}
-
-void Importer::delNode(Importer::Node *n)
-{
- if (!n)
- return;
- for (Importer::Node *c : qAsConst(n->children))
- delNode(c);
- delete n;
-}
-
-Importer::~Importer()
-{
- delNode(m_rootNode);
-}
-
-QVector<Importer::BufferInfo> Importer::buffers() const
-{
- BufferInfo b;
- b.name = QStringLiteral("buf");
- b.data = m_buffer;
- return QVector<BufferInfo>() << b;
-}
-
-const Importer::Node *Importer::rootNode() const
-{
- return m_rootNode;
-}
-
-bool Importer::allMeshesForMaterialHaveTangents(uint materialIndex) const
-{
- for (const MeshInfo &mi : m_meshInfo) {
- if (mi.materialIndex == materialIndex) {
- bool hasTangents = false;
- for (const MeshInfo::Accessor &acc : mi.accessors) {
- if (acc.usage == QStringLiteral("TANGENT")) {
- hasTangents = true;
- break;
- }
- }
- if (!hasTangents)
- return false;
- }
- }
- return true;
-}
-
-QVector<Importer::MeshInfo::BufferView> Importer::bufferViews() const
-{
- QVector<Importer::MeshInfo::BufferView> bv;
- for (const MeshInfo &mi : m_meshInfo) {
- for (const MeshInfo::BufferView &v : mi.views)
- bv << v;
- }
- return bv;
-}
-
-QVector<Importer::MeshInfo::Accessor> Importer::accessors() const
-{
- QVector<Importer::MeshInfo::Accessor> acc;
- for (const MeshInfo &mi : m_meshInfo) {
- for (const MeshInfo::Accessor &a : mi.accessors)
- acc << a;
- }
- return acc;
-}
-
-uint Importer::meshCount() const
-{
- return m_meshInfo.count();
-}
-
-Importer::MeshInfo Importer::meshInfo(uint meshIndex) const
-{
- return m_meshInfo[meshIndex];
-}
-
-uint Importer::materialCount() const
-{
- return m_materialInfo.count();
-}
-
-Importer::MaterialInfo Importer::materialInfo(uint materialIndex) const
-{
- return m_materialInfo[materialIndex];
-}
-
-QHash<QString, Importer::CameraInfo> Importer::cameraInfo() const
-{
- return m_cameraInfo;
-}
-
-QSet<QString> Importer::externalTextures() const
-{
- return m_externalTextures;
-}
-
-QHash<QString, Importer::EmbeddedTextureInfo> Importer::embeddedTextures() const
-{
- return m_embeddedTextures;
-}
-
-QVector<Importer::AnimationInfo> Importer::animations() const
-{
- return m_animations;
-}
-
-const Importer::Node *Importer::findNode(const Node *root, const QString &originalName) const
-{
- for (const Node *c : root->children) {
- if (c->name == originalName)
- return c;
- const Node *cn = findNode(c, originalName);
- if (cn)
- return cn;
- }
- return nullptr;
-}
-
-class AssimpImporter : public Importer
-{
-public:
- AssimpImporter();
-
- bool load(const QString &filename) override;
-
-private:
- const aiScene *scene() const;
- void printNodes(const aiNode *node, int level = 1);
- void buildBuffer();
- void parseEmbeddedTextures();
- void parseMaterials();
- void parseCameras();
- void parseNode(Importer::Node *dst, const aiNode *src);
- void parseScene();
- void parseAnimations();
- void addKeyFrame(QVector<KeyFrame> &keyFrames, float t, aiVector3D *vt, aiQuaternion *vr, aiVector3D *vs);
-
- QScopedPointer<Assimp::Importer> m_importer;
-};
-
-AssimpImporter::AssimpImporter() :
- m_importer(new Assimp::Importer)
-{
- m_importer->SetIOHandler(new AssimpIOSystem);
- m_importer->SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
-}
-
-bool AssimpImporter::load(const QString &filename)
-{
- uint flags = aiProcess_Triangulate | aiProcess_SortByPType
- | aiProcess_JoinIdenticalVertices
- | aiProcess_GenSmoothNormals
- | aiProcess_GenUVCoords
- | aiProcess_FlipUVs
- | aiProcess_FindDegenerates;
-
- if (opts.genTangents)
- flags |= aiProcess_CalcTangentSpace;
-
- const aiScene *scene = m_importer->ReadFile(filename.toUtf8().constData(), flags);
- if (!scene)
- return false;
-
- if (opts.showLog) {
- qDebug().noquote() << filename
- << scene->mNumMeshes << "meshes,"
- << scene->mNumMaterials << "materials,"
- << scene->mNumTextures << "embedded textures,"
- << scene->mNumCameras << "cameras,"
- << scene->mNumLights << "lights,"
- << scene->mNumAnimations << "animations";
- qDebug() << "Scene:";
- printNodes(scene->mRootNode);
- }
-
- buildBuffer();
- parseEmbeddedTextures();
- parseMaterials();
- parseCameras();
- parseScene();
- parseAnimations();
-
- return true;
-}
-
-void AssimpImporter::printNodes(const aiNode *node, int level)
-{
- qDebug().noquote() << QString().fill('-', level * 4) << ai2qt(node->mName) << node->mNumMeshes << "mesh refs";
- for (uint i = 0; i < node->mNumChildren; ++i)
- printNodes(node->mChildren[i], level + 1);
-}
-
-template<class T> void copyIndexBuf(T *dst, const aiMesh *src)
-{
- for (uint j = 0; j < src->mNumFaces; ++j) {
- const aiFace *f = &src->mFaces[j];
- if (f->mNumIndices != 3)
- qFatal("Face %d is not a triangle (index count %d instead of 3)", j, f->mNumIndices);
- *dst++ = f->mIndices[0];
- *dst++ = f->mIndices[1];
- *dst++ = f->mIndices[2];
- }
-}
-
-static QString newBufferViewName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("bufferView_%1")).arg(++cnt);
-}
-
-static QString newAccessorName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("accessor_%1")).arg(++cnt);
-}
-
-static QString newMeshName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("mesh_%1")).arg(++cnt);
-}
-
-static QString newMaterialName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("material_%1")).arg(++cnt);
-}
-
-static QString newTechniqueName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("technique_%1")).arg(++cnt);
-}
-
-static QString newTextureName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("texture_%1")).arg(++cnt);
-}
-
-static QString newImageName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("image_%1")).arg(++cnt);
-}
-
-static QString newShaderName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("shader_%1")).arg(++cnt);
-}
-
-static QString newProgramName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("program_%1")).arg(++cnt);
-}
-
-static QString newNodeName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("node_%1")).arg(++cnt);
-}
-
-static QString newAnimationName()
-{
- static int cnt = 0;
- return QString(QStringLiteral("animation_%1")).arg(++cnt);
-}
-
-template<class T> void calcBB(QVector<float> &minVal, QVector<float> &maxVal, T *data, int vertexCount, int compCount)
-{
- minVal.resize(compCount);
- maxVal.resize(compCount);
- for (int i = 0; i < vertexCount; ++i) {
- for (int j = 0; j < compCount; ++j) {
- if (i == 0) {
- minVal[j] = maxVal[j] = data[i][j];
- } else {
- if (data[i][j] < minVal[j])
- minVal[j] = data[i][j];
- if (data[i][j] > maxVal[j])
- maxVal[j] = data[i][j];
- }
- }
- }
-}
-
-// One buffer per importer (scene).
-// Two buffer views (array, index) + three or more accessors per mesh.
-
-void AssimpImporter::buildBuffer()
-{
- m_buffer.clear();
- m_meshInfo.clear();
-
- if (opts.showLog)
- qDebug() << "Meshes:";
-
- const aiScene *sc = scene();
- for (uint i = 0; i < sc->mNumMeshes; ++i) {
- aiMesh *m = sc->mMeshes[i];
- MeshInfo meshInfo;
- meshInfo.originalName = ai2qt(m->mName);
- meshInfo.name = newMeshName();
- meshInfo.materialIndex = m->mMaterialIndex;
-
- aiVector3D *vertices = m->mVertices;
- aiVector3D *normals = m->mNormals;
- aiVector3D *textureCoords = m->mTextureCoords[0];
- aiColor4D *colors = m->mColors[0];
- aiVector3D *tangents = m->mTangents;
-
- if (opts.scale != 1) {
- for (uint j = 0; j < m->mNumVertices; ++j) {
- vertices[j].x *= opts.scale;
- vertices[j].y *= opts.scale;
- vertices[j].z *= opts.scale;
- }
- }
-
- // Vertex (3), Normal (3), Coord? (2), Color? (4), Tangent? (3)
- uint stride = 3 + 3 + (textureCoords ? 2 : 0) + (colors ? 4 : 0) + (tangents ? 3 : 0);
- QByteArray vertexBuf;
- vertexBuf.resize(stride * m->mNumVertices * sizeof(float));
- float *p = reinterpret_cast<float *>(vertexBuf.data());
-
- if (opts.interleave) {
- for (uint j = 0; j < m->mNumVertices; ++j) {
- // Vertex
- *p++ = vertices[j].x;
- *p++ = vertices[j].y;
- *p++ = vertices[j].z;
-
- // Normal
- *p++ = normals[j].x;
- *p++ = normals[j].y;
- *p++ = normals[j].z;
-
- // Coord
- if (textureCoords) {
- *p++ = textureCoords[j].x;
- *p++ = textureCoords[j].y;
- }
-
- // Color
- if (colors) {
- *p++ = colors[j].r;
- *p++ = colors[j].g;
- *p++ = colors[j].b;
- *p++ = colors[j].a;
- }
-
- // Tangent
- if (tangents) {
- *p++ = tangents[j].x;
- *p++ = tangents[j].y;
- *p++ = tangents[j].z;
- }
- }
- } else {
- // Vertex
- for (uint j = 0; j < m->mNumVertices; ++j) {
- *p++ = vertices[j].x;
- *p++ = vertices[j].y;
- *p++ = vertices[j].z;
- }
-
- // Normal
- for (uint j = 0; j < m->mNumVertices; ++j) {
- *p++ = normals[j].x;
- *p++ = normals[j].y;
- *p++ = normals[j].z;
- }
-
- // Coord
- if (textureCoords) {
- for (uint j = 0; j < m->mNumVertices; ++j) {
- *p++ = textureCoords[j].x;
- *p++ = textureCoords[j].y;
- }
- }
-
- // Color
- if (colors) {
- for (uint j = 0; j < m->mNumVertices; ++j) {
- *p++ = colors[j].r;
- *p++ = colors[j].g;
- *p++ = colors[j].b;
- *p++ = colors[j].a;
- }
- }
-
- // Tangent
- if (tangents) {
- for (uint j = 0; j < m->mNumVertices; ++j) {
- *p++ = tangents[j].x;
- *p++ = tangents[j].y;
- *p++ = tangents[j].z;
- }
- }
- }
-
- MeshInfo::BufferView vertexBufView;
- vertexBufView.name = newBufferViewName();
- vertexBufView.length = vertexBuf.size();
- vertexBufView.offset = m_buffer.size();
- vertexBufView.componentType = GLT_FLOAT;
- vertexBufView.target = GLT_ARRAY_BUFFER;
- meshInfo.views.append(vertexBufView);
-
- QByteArray indexBuf;
- uint indexCount = m->mNumFaces * 3;
- if (indexCount >= USHRT_MAX) {
- indexBuf.resize(indexCount * sizeof(quint32));
- quint32 *p = reinterpret_cast<quint32 *>(indexBuf.data());
- copyIndexBuf(p, m);
- } else {
- indexBuf.resize(indexCount * sizeof(quint16));
- quint16 *p = reinterpret_cast<quint16 *>(indexBuf.data());
- copyIndexBuf(p, m);
- }
-
- MeshInfo::BufferView indexBufView;
- indexBufView.name = newBufferViewName();
- indexBufView.length = indexBuf.size();
- indexBufView.offset = vertexBufView.offset + vertexBufView.length;
- indexBufView.componentType = indexCount >= USHRT_MAX ? GLT_UNSIGNED_INT : GLT_UNSIGNED_SHORT;
- indexBufView.target = GLT_ELEMENT_ARRAY_BUFFER;
- meshInfo.views.append(indexBufView);
-
- MeshInfo::Accessor acc;
- uint startOffset = 0;
- // Vertex
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("POSITION");
- acc.bufferView = vertexBufView.name;
- acc.offset = 0;
- acc.stride = opts.interleave ? stride * sizeof(float) : 3 * sizeof(float);
- acc.count = m->mNumVertices;
- acc.componentType = vertexBufView.componentType;
- acc.type = QStringLiteral("VEC3");
- calcBB(acc.minVal, acc.maxVal, vertices, m->mNumVertices, 3);
- meshInfo.accessors.append(acc);
- startOffset += opts.interleave ? 3 : 3 * m->mNumVertices;
- // Normal
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("NORMAL");
- acc.offset = startOffset * sizeof(float);
- if (!opts.interleave)
- acc.stride = 3 * sizeof(float);
- calcBB(acc.minVal, acc.maxVal, normals, m->mNumVertices, 3);
- meshInfo.accessors.append(acc);
- startOffset += opts.interleave ? 3 : 3 * m->mNumVertices;
- // Coord
- if (textureCoords) {
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("TEXCOORD_0");
- acc.offset = startOffset * sizeof(float);
- if (!opts.interleave)
- acc.stride = 2 * sizeof(float);
- acc.type = QStringLiteral("VEC2");
- calcBB(acc.minVal, acc.maxVal, textureCoords, m->mNumVertices, 2);
- meshInfo.accessors.append(acc);
- startOffset += opts.interleave ? 2 : 2 * m->mNumVertices;
- }
- // Color
- if (colors) {
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("COLOR");
- acc.offset = startOffset * sizeof(float);
- if (!opts.interleave)
- acc.stride = 4 * sizeof(float);
- acc.type = QStringLiteral("VEC4");
- calcBB(acc.minVal, acc.maxVal, colors, m->mNumVertices, 4);
- meshInfo.accessors.append(acc);
- startOffset += opts.interleave ? 4 : 4 * m->mNumVertices;
- }
- // Tangent
- if (tangents) {
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("TANGENT");
- acc.offset = startOffset * sizeof(float);
- if (!opts.interleave)
- acc.stride = 3 * sizeof(float);
- acc.type = QStringLiteral("VEC3");
- calcBB(acc.minVal, acc.maxVal, tangents, m->mNumVertices, 3);
- meshInfo.accessors.append(acc);
- startOffset += opts.interleave ? 3 : 3 * m->mNumVertices;
- }
-
- // Index
- acc.name = newAccessorName();
- acc.usage = QStringLiteral("INDEX");
- acc.bufferView = indexBufView.name;
- acc.offset = 0;
- acc.stride = 0;
- acc.count = indexCount;
- acc.componentType = indexBufView.componentType;
- acc.type = QStringLiteral("SCALAR");
- acc.minVal = acc.maxVal = QVector<float>();
- meshInfo.accessors.append(acc);
-
- if (opts.showLog) {
- qDebug().noquote() << "#" << i << "(" << meshInfo.name << "/" << meshInfo.originalName << ")"
- << m->mNumVertices << "vertices,"
- << m->mNumFaces << "faces," << stride << "bytes per vertex,"
- << vertexBuf.size() << "vertex bytes," << indexBuf.size() << "index bytes";
- if (opts.scale != 1)
- qDebug() << " scaled by" << opts.scale;
- if (!opts.interleave)
- qDebug() << " non-interleaved layout";
- QStringList sl;
- for (const MeshInfo::BufferView &bv : qAsConst(meshInfo.views)) sl << bv.name;
- qDebug() << " buffer views:" << sl;
- sl.clear();
- for (const MeshInfo::Accessor &acc : qAsConst(meshInfo.accessors)) sl << acc.name;
- qDebug() << " accessors:" << sl;
- qDebug() << " material: #" << meshInfo.materialIndex;
- }
-
- m_buffer.append(vertexBuf);
- m_buffer.append(indexBuf);
-
- m_meshInfo.insert(i, meshInfo);
- }
-
- if (opts.showLog)
- qDebug().noquote() << "Total buffer size" << m_buffer.size();
-}
-
-void AssimpImporter::parseEmbeddedTextures()
-{
-#ifdef HAS_QIMAGE
- m_embeddedTextures.clear();
-
- const aiScene *sc = scene();
- if (opts.showLog && sc->mNumTextures)
- qDebug() << "Embedded textures:";
-
- for (uint i = 0; i < sc->mNumTextures; ++i) {
- aiTexture *t = sc->mTextures[i];
- QImage img;
- if (t->mHeight == 0) {
- img = QImage::fromData(reinterpret_cast<uchar *>(t->pcData), t->mWidth);
- } else {
- uint sz = t->mWidth * t->mHeight;
- QByteArray data;
- data.resize(sz * 4);
- uchar *p = reinterpret_cast<uchar *>(data.data());
- for (uint j = 0; j < sz; ++j) {
- *p++ = t->pcData[j].r;
- *p++ = t->pcData[j].g;
- *p++ = t->pcData[j].b;
- *p++ = t->pcData[j].a;
- }
- img = QImage(reinterpret_cast<const uchar *>(data.constData()), t->mWidth, t->mHeight, QImage::Format_RGBA8888);
- img.detach();
- }
- QString name;
- static int imgCnt = 0;
- name = QString(QStringLiteral("texture_%1.png")).arg(++imgCnt);
- QString embeddedTextureRef = QStringLiteral("*") + QString::number(i); // see AI_MAKE_EMBEDDED_TEXNAME
- m_embeddedTextures.insert(embeddedTextureRef, EmbeddedTextureInfo(name, img));
- if (opts.showLog)
- qDebug().noquote() << "#" << i << name << img;
- }
-#else
- if (scene()->mNumTextures)
- qWarning() << "WARNING: No image support, ignoring" << scene()->mNumTextures << "embedded textures";
-#endif
-}
-
-void AssimpImporter::parseMaterials()
-{
- m_materialInfo.clear();
- m_externalTextures.clear();
-
- if (opts.showLog)
- qDebug() << "Materials:";
-
- const aiScene *sc = scene();
- for (uint i = 0; i < sc->mNumMaterials; ++i) {
- const aiMaterial *mat = sc->mMaterials[i];
- MaterialInfo matInfo;
- matInfo.name = newMaterialName();
-
- aiString s;
- if (mat->Get(AI_MATKEY_NAME, s) == aiReturn_SUCCESS)
- matInfo.originalName = ai2qt(s);
-
- aiColor4D color;
- if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS)
- matInfo.m_colors.insert("diffuse", QVector<float>() << color.r << color.g << color.b << color.a);
- if (mat->Get(AI_MATKEY_COLOR_SPECULAR, color) == aiReturn_SUCCESS)
- matInfo.m_colors.insert("specular", QVector<float>() << color.r << color.g << color.b);
- if (mat->Get(AI_MATKEY_COLOR_AMBIENT, color) == aiReturn_SUCCESS)
- matInfo.m_colors.insert("ambient", QVector<float>() << color.r << color.g << color.b);
-
- float f;
- if (mat->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS)
- matInfo.m_values.insert("shininess", f);
-
- if (mat->GetTexture(aiTextureType_DIFFUSE, 0, &s) == aiReturn_SUCCESS)
- matInfo.m_textures.insert("diffuse", ai2qt(s));
- if (mat->GetTexture(aiTextureType_SPECULAR, 0, &s) == aiReturn_SUCCESS)
- matInfo.m_textures.insert("specular", ai2qt(s));
- if (mat->GetTexture(aiTextureType_NORMALS, 0, &s) == aiReturn_SUCCESS)
- matInfo.m_textures.insert("normal", ai2qt(s));
-
- QHash<QByteArray, QString>::iterator texIt = matInfo.m_textures.begin();
- while (texIt != matInfo.m_textures.end()) {
- // Map embedded texture references to real files.
- if (texIt->startsWith('*'))
- *texIt = m_embeddedTextures[*texIt].name;
- else
- m_externalTextures.insert(*texIt);
- ++texIt;
- }
-
- m_materialInfo.insert(i, matInfo);
-
- if (opts.showLog) {
- qDebug().noquote() << "#" << i << "(" << matInfo.name << "/" << matInfo.originalName << ")";
- qDebug() << " colors:" << matInfo.m_colors;
- qDebug() << " values:" << matInfo.m_values;
- qDebug() << " textures:" << matInfo.m_textures;
- }
- }
-}
-
-void AssimpImporter::parseCameras()
-{
- m_cameraInfo.clear();
-
- if (opts.showLog)
- qDebug() << "Cameras:";
-
- const aiScene *sc = scene();
- for (uint i = 0; i < sc->mNumCameras; ++i) {
- const aiCamera *cam = sc->mCameras[i];
- QString name = ai2qt(cam->mName);
- CameraInfo c;
-
- c.name = name + QStringLiteral("_cam");
- c.aspectRatio = qFuzzyIsNull(cam->mAspect) ? 1.5f : cam->mAspect;
- c.yfov = cam->mHorizontalFOV;
- if (c.yfov < (M_PI / 10.0)) // this can't be right (probably orthographic source camera)
- c.yfov = float(M_PI / 4.0);
- c.znear = cam->mClipPlaneNear;
- c.zfar = cam->mClipPlaneFar;
-
- // Collada / glTF cameras point in -Z by default, the rest is in the
- // node matrix, no separate look-at params given here.
-
- m_cameraInfo.insert(name, c);
-
- if (opts.showLog)
- qDebug().noquote() << "#" << i << "(" << name << ")" << c.aspectRatio << c.yfov << c.znear << c.zfar;
- }
-}
-
-void AssimpImporter::parseNode(Importer::Node *dst, const aiNode *src)
-{
- dst->name = ai2qt(src->mName);
- dst->uniqueName = newNodeName();
- for (uint j = 0; j < src->mNumChildren; ++j) {
- Node *c = new Node;
- parseNode(c, src->mChildren[j]);
- dst->children << c;
- }
- dst->transformation = ai2qt(src->mTransformation);
- for (uint j = 0; j < src->mNumMeshes; ++j)
- dst->meshes << src->mMeshes[j];
-}
-
-void AssimpImporter::parseScene()
-{
- delNode(m_rootNode);
- const aiScene *sc = scene();
- m_rootNode = new Node;
- parseNode(m_rootNode, sc->mRootNode);
-}
-
-void AssimpImporter::addKeyFrame(QVector<KeyFrame> &keyFrames, float t, aiVector3D *vt, aiQuaternion *vr, aiVector3D *vs)
-{
- KeyFrame kf;
- int idx = -1;
- for (int i = 0; i < keyFrames.count(); ++i) {
- if (qFuzzyCompare(keyFrames[i].t, t)) {
- kf = keyFrames[i];
- idx = i;
- break;
- }
- }
-
- kf.t = t;
- if (vt) {
- kf.transValid = true;
- kf.trans = QVector<float>() << vt->x << vt->y << vt->z;
- }
- if (vr) {
- kf.rotValid = true;
- kf.rot = QVector<float>() << vr->w << vr->x << vr->y << vr->z;
- }
- if (vs) {
- kf.scaleValid = true;
- kf.scale = QVector<float>() << vs->x << vs->y << vs->z;
- }
-
- if (idx >= 0)
- keyFrames[idx] = kf;
- else
- keyFrames.append(kf);
-}
-
-void AssimpImporter::parseAnimations()
-{
- const aiScene *sc = scene();
- if (opts.showLog && sc->mNumAnimations)
- qDebug() << "Animations:";
-
- for (uint i = 0; i < sc->mNumAnimations; ++i) {
- const aiAnimation *anim = sc->mAnimations[i];
-
- // Only care about node animations.
- for (uint j = 0; j < anim->mNumChannels; ++j) {
- const aiNodeAnim *a = anim->mChannels[j];
- AnimationInfo animInfo;
- QVector<KeyFrame> keyFrames;
-
- if (opts.showLog)
- qDebug().noquote() << ai2qt(anim->mName) << "->" << ai2qt(a->mNodeName);
-
- // Target values in the keyframes are local absolute (relative to parent, like node.matrix).
- for (uint kf = 0; kf < a->mNumPositionKeys; ++kf) {
- float t = float(a->mPositionKeys[kf].mTime);
- aiVector3D v = a->mPositionKeys[kf].mValue;
- animInfo.hasTranslation = true;
- addKeyFrame(keyFrames, t, &v, nullptr, nullptr);
- }
- for (uint kf = 0; kf < a->mNumRotationKeys; ++kf) {
- float t = float(a->mRotationKeys[kf].mTime);
- aiQuaternion v = a->mRotationKeys[kf].mValue;
- animInfo.hasRotation = true;
- addKeyFrame(keyFrames, t, nullptr, &v, nullptr);
- }
- for (uint kf = 0; kf < a->mNumScalingKeys; ++kf) {
- float t = float(a->mScalingKeys[kf].mTime);
- aiVector3D v = a->mScalingKeys[kf].mValue;
- animInfo.hasScale = true;
- addKeyFrame(keyFrames, t, nullptr, nullptr, &v);
- }
-
- // Here we should ideally get rid of non-animated properties (that
- // just set the t-r-s value from node.matrix in every frame) but
- // let's leave that as a future exercise.
-
- if (!keyFrames.isEmpty()) {
- animInfo.name = ai2qt(anim->mName);
- QString nodeName = ai2qt(a->mNodeName); // have to map to our generated, unique node names
- const Node *targetNode = findNode(m_rootNode, nodeName);
- if (targetNode)
- animInfo.targetNode = targetNode->uniqueName;
- else
- qWarning().noquote() << "ERROR: Cannot find target node" << nodeName << "for animation" << animInfo.name;
- animInfo.keyFrames = keyFrames;
- m_animations << animInfo;
-
- if (opts.showLog) {
- for (const KeyFrame &kf : qAsConst(keyFrames)) {
- QString msg;
- QTextStream s(&msg);
- s << " @ " << kf.t;
- if (kf.transValid)
- s << " T=(" << kf.trans[0] << ", " << kf.trans[1] << ", " << kf.trans[2] << ")";
- if (kf.rotValid)
- s << " R=(w=" << kf.rot[0] << ", " << kf.rot[1] << ", " << kf.rot[2] << ", " << kf.rot[3] << ")";
- if (kf.scaleValid)
- s << " S=(" << kf.scale[0] << ", " << kf.scale[1] << ", " << kf.scale[2] << ")";
- qDebug().noquote() << msg;
- }
- }
- }
- }
- }
-}
-
-const aiScene *AssimpImporter::scene() const
-{
- return m_importer->GetScene();
-}
-
-class Exporter
-{
-public:
- Exporter(Importer *importer) : m_importer(importer) { }
- virtual ~Exporter() { }
-
- virtual void save(const QString &inputFilename) = 0;
-
-protected:
- bool nodeIsUseful(const Importer::Node *n) const;
- void copyExternalTextures(const QString &inputFilename);
- void exportEmbeddedTextures();
- void compressTextures();
-
- Importer *m_importer;
- QSet<QString> m_files;
- QHash<QString, QString> m_compressedTextures;
-};
-
-bool Exporter::nodeIsUseful(const Importer::Node *n) const
-{
- if (!n->meshes.isEmpty() || m_importer->cameraInfo().contains(n->name))
- return true;
-
- for (const Importer::Node *c : n->children) {
- if (nodeIsUseful(c))
- return true;
- }
-
- return false;
-}
-
-void Exporter::copyExternalTextures(const QString &inputFilename)
-{
- const auto textureFilenames = m_importer->externalTextures();
- for (const QString &textureFilename : textureFilenames) {
- const QString dst = opts.outDir + textureFilename;
- m_files.insert(QFileInfo(dst).fileName());
- // External textures need copying only when output dir was specified.
- if (!opts.outDir.isEmpty()) {
- const QString src = QFileInfo(inputFilename).path() + QStringLiteral("/") + textureFilename;
- if (QFileInfo(src).absolutePath() != QFileInfo(dst).absolutePath()) {
- if (opts.showLog)
- qDebug().noquote() << "Copying" << src << "to" << dst;
- QFile(src).copy(dst);
- }
- }
- }
-}
-
-void Exporter::exportEmbeddedTextures()
-{
-#ifdef HAS_QIMAGE
- const auto embeddedTextures = m_importer->embeddedTextures();
- for (const Importer::EmbeddedTextureInfo &embTex : embeddedTextures) {
- QString fn = opts.outDir + embTex.name;
- m_files.insert(QFileInfo(fn).fileName());
- if (opts.showLog)
- qDebug().noquote() << "Writing" << fn;
- embTex.image.save(fn);
- }
-#endif
-}
-
-void Exporter::compressTextures()
-{
- if (opts.texComp != Options::ETC1)
- return;
-
- const auto textureFilenames = m_importer->externalTextures();
- const auto embeddedTextures = m_importer->embeddedTextures();
- QStringList imageList;
- imageList.reserve(textureFilenames.size() + embeddedTextures.size());
- for (const QString &textureFilename : textureFilenames)
- imageList << opts.outDir + textureFilename;
- for (const Importer::EmbeddedTextureInfo &embTex : embeddedTextures)
- imageList << opts.outDir + embTex.name;
-
- for (const QString &filename : qAsConst(imageList)) {
- if (QFileInfo(filename).suffix().toLower() != QStringLiteral("png"))
- continue;
- QByteArray cmd = QByteArrayLiteral("etc1tool ");
- cmd += filename.toUtf8();
- qDebug().noquote() << "Invoking" << cmd;
- // No QProcess in bootstrap
- if (system(cmd.constData()) == -1) {
- qWarning() << "ERROR: Failed to launch etc1tool";
- } else {
- QString src = QFileInfo(filename).fileName();
- QString dst = QFileInfo(src).baseName() + QStringLiteral(".pkm");
- m_compressedTextures.insert(src, dst);
- m_files.remove(src);
- m_files.insert(dst);
- }
- }
-}
-
-class GltfExporter : public Exporter
-{
-public:
- GltfExporter(Importer *importer);
- void save(const QString &inputFilename) override;
-
-private:
- struct ProgramInfo {
- struct Param {
- Param() : type(0) { }
- Param(QString name, QString nameInShader, QString semantic, uint type)
- : name(name), nameInShader(nameInShader), semantic(semantic), type(type) { }
- QString name;
- QString nameInShader;
- QString semantic;
- uint type;
- };
- QString commonTechniqueName;
- QString vertShader;
- QString fragShader;
- QVector<Param> attributes;
- QVector<Param> uniforms;
- };
- friend class QTypeInfo<ProgramInfo>;
- friend class QTypeInfo<ProgramInfo::Param>;
-
- void writeShader(const QString &src, const QString &dst, const QVector<QPair<QByteArray, QByteArray> > &substTab);
- QString exportNode(const Importer::Node *n, QJsonObject &nodes);
- void exportMaterials(QJsonObject &materials, QHash<QString, QString> *textureNameMap);
- void exportParameter(QJsonObject &dst, const QVector<ProgramInfo::Param> &params);
- void exportTechniques(QJsonObject &obj, const QString &basename);
- void exportAnimations(QJsonObject &obj, QVector<Importer::BufferInfo> &bufList,
- QVector<Importer::MeshInfo::BufferView> &bvList,
- QVector<Importer::MeshInfo::Accessor> &accList);
- void initShaderInfo();
- ProgramInfo *chooseProgram(uint materialIndex);
-
- QJsonObject m_obj;
- QVector<ProgramInfo> m_progs;
-
- struct TechniqueInfo {
- TechniqueInfo() : opaque(true), prog(nullptr) { }
- TechniqueInfo(const QString &name, bool opaque, ProgramInfo *prog)
- : name(name)
- , opaque(opaque)
- , prog(prog)
- {
- coreName = name + QStringLiteral("_core");
- gl2Name = name + QStringLiteral("_gl2");
- }
- QString name;
- QString coreName;
- QString gl2Name;
- bool opaque;
- ProgramInfo *prog;
- };
- friend class QTypeInfo<TechniqueInfo>;
- QVector<TechniqueInfo> m_techniques;
- QSet<ProgramInfo *> m_usedPrograms;
-
- QVector<QPair<QByteArray, QByteArray> > m_subst_es2;
- QVector<QPair<QByteArray, QByteArray> > m_subst_core;
-
- QHash<QString, bool> m_imageHasAlpha;
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(GltfExporter::ProgramInfo, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(GltfExporter::ProgramInfo::Param, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(GltfExporter::TechniqueInfo, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-GltfExporter::GltfExporter(Importer *importer)
- : Exporter(importer)
-{
- initShaderInfo();
-}
-
-struct Shader {
- const char *name;
- const char *text;
-} shaders[] = {
- {
- "color.vert",
-"$VERSION\n"
-"$ATTRIBUTE vec3 vertexPosition;\n"
-"$ATTRIBUTE vec3 vertexNormal;\n"
-"$VVARYING vec3 vPosition;\n"
-"$VVARYING vec3 vNormal;\n"
-"uniform mat4 projection;\n"
-"uniform mat4 modelView;\n"
-"uniform mat3 modelViewNormal;\n"
-"void main()\n"
-"{\n"
-" vNormal = normalize( modelViewNormal * vertexNormal );\n"
-" vPosition = vec3( modelView * vec4( vertexPosition, 1.0 ) );\n"
-" gl_Position = projection * modelView * vec4( vertexPosition, 1.0 );\n"
-"}\n"
- },
- {
- "color.frag",
-"$VERSION\n"
-"uniform $HIGHP vec4 lightPosition;\n"
-"uniform $HIGHP vec3 lightIntensity;\n"
-"uniform $HIGHP vec3 ka;\n"
-"uniform $HIGHP vec4 kd;\n"
-"uniform $HIGHP vec3 ks;\n"
-"uniform $HIGHP float shininess;\n"
-"$FVARYING $HIGHP vec3 vPosition;\n"
-"$FVARYING $HIGHP vec3 vNormal;\n"
-"$DECL_FRAGCOLOR\n"
-"$HIGHP vec3 adsModel( const $HIGHP vec3 pos, const $HIGHP vec3 n )\n"
-"{\n"
-" $HIGHP vec3 s = normalize( vec3( lightPosition ) - pos );\n"
-" $HIGHP vec3 v = normalize( -pos );\n"
-" $HIGHP vec3 r = reflect( -s, n );\n"
-" $HIGHP float diffuse = max( dot( s, n ), 0.0 );\n"
-" $HIGHP float specular = 0.0;\n"
-" if ( dot( s, n ) > 0.0 )\n"
-" specular = pow( max( dot( r, v ), 0.0 ), shininess );\n"
-" return lightIntensity * ( ka + kd.rgb * diffuse + ks * specular );\n"
-"}\n"
-"void main()\n"
-"{\n"
-" $FRAGCOLOR = vec4( adsModel( vPosition, normalize( vNormal ) ) * kd.a, kd.a );\n"
-"}\n"
- },
- {
- "diffusemap.vert",
-"$VERSION\n"
-"$ATTRIBUTE vec3 vertexPosition;\n"
-"$ATTRIBUTE vec3 vertexNormal;\n"
-"$ATTRIBUTE vec2 vertexTexCoord;\n"
-"$VVARYING vec3 vPosition;\n"
-"$VVARYING vec3 vNormal;\n"
-"$VVARYING vec2 vTexCoord;\n"
-"uniform mat4 projection;\n"
-"uniform mat4 modelView;\n"
-"uniform mat3 modelViewNormal;\n"
-"void main()\n"
-"{\n"
-" vTexCoord = vertexTexCoord;\n"
-" vNormal = normalize( modelViewNormal * vertexNormal );\n"
-" vPosition = vec3( modelView * vec4( vertexPosition, 1.0 ) );\n"
-" gl_Position = projection * modelView * vec4( vertexPosition, 1.0 );\n"
-"}\n"
- },
- {
- "diffusemap.frag",
-"$VERSION\n"
-"uniform $HIGHP vec4 lightPosition;\n"
-"uniform $HIGHP vec3 lightIntensity;\n"
-"uniform $HIGHP vec3 ka;\n"
-"uniform $HIGHP vec3 ks;\n"
-"uniform $HIGHP float shininess;\n"
-"uniform sampler2D diffuseTexture;\n"
-"$FVARYING $HIGHP vec3 vPosition;\n"
-"$FVARYING $HIGHP vec3 vNormal;\n"
-"$FVARYING $HIGHP vec2 vTexCoord;\n"
-"$DECL_FRAGCOLOR\n"
-"$HIGHP vec4 adsModel( const $HIGHP vec3 pos, const $HIGHP vec3 n )\n"
-"{\n"
-" $HIGHP vec3 s = normalize( vec3( lightPosition ) - pos );\n"
-" $HIGHP vec3 v = normalize( -pos );\n"
-" $HIGHP vec3 r = reflect( -s, n );\n"
-" $HIGHP float diffuse = max( dot( s, n ), 0.0 );\n"
-" $HIGHP float specular = 0.0;\n"
-" if ( dot( s, n ) > 0.0 )\n"
-" specular = pow( max( dot( r, v ), 0.0 ), shininess );\n"
-" $HIGHP vec4 kd = $TEXTURE2D( diffuseTexture, vTexCoord );\n"
-" return vec4( lightIntensity * ( ka + kd.rgb * diffuse + ks * specular ) * kd.a, kd.a );\n"
-"}\n"
-"void main()\n"
-"{\n"
-" $FRAGCOLOR = adsModel( vPosition, normalize( vNormal ) );\n"
-"}\n"
- },
- {
- "diffusespecularmap.frag",
-"$VERSION\n"
-"uniform $HIGHP vec4 lightPosition;\n"
-"uniform $HIGHP vec3 lightIntensity;\n"
-"uniform $HIGHP vec3 ka;\n"
-"uniform $HIGHP float shininess;\n"
-"uniform sampler2D diffuseTexture;\n"
-"uniform sampler2D specularTexture;\n"
-"$FVARYING $HIGHP vec3 vPosition;\n"
-"$FVARYING $HIGHP vec3 vNormal;\n"
-"$FVARYING $HIGHP vec2 vTexCoord;\n"
-"$DECL_FRAGCOLOR\n"
-"$HIGHP vec4 adsModel( const in $HIGHP vec3 pos, const in $HIGHP vec3 n )\n"
-"{\n"
-" $HIGHP vec3 s = normalize( vec3( lightPosition ) - pos );\n"
-" $HIGHP vec3 v = normalize( -pos );\n"
-" $HIGHP vec3 r = reflect( -s, n );\n"
-" $HIGHP float diffuse = max( dot( s, n ), 0.0 );\n"
-" $HIGHP float specular = 0.0;\n"
-" if ( dot( s, n ) > 0.0 )\n"
-" specular = ( shininess / ( 8.0 * 3.14 ) ) * pow( max( dot( r, v ), 0.0 ), shininess );\n"
-" $HIGHP vec4 kd = $TEXTURE2D( diffuseTexture, vTexCoord );\n"
-" $HIGHP vec3 ks = $TEXTURE2D( specularTexture, vTexCoord );\n"
-" return vec4( lightIntensity * ( ka + kd.rgb * diffuse + ks * specular ) * kd.a, kd.a );\n"
-"}\n"
-"void main()\n"
-"{\n"
-" $FRAGCOLOR = vec4( adsModel( vPosition, normalize( vNormal ) ), 1.0 );\n"
-"}\n"
- },
- {
- "normaldiffusemap.vert",
-"$VERSION\n"
-"$ATTRIBUTE vec3 vertexPosition;\n"
-"$ATTRIBUTE vec3 vertexNormal;\n"
-"$ATTRIBUTE vec2 vertexTexCoord;\n"
-"$ATTRIBUTE vec4 vertexTangent;\n"
-"$VVARYING vec3 lightDir;\n"
-"$VVARYING vec3 viewDir;\n"
-"$VVARYING vec2 texCoord;\n"
-"uniform mat4 projection;\n"
-"uniform mat4 modelView;\n"
-"uniform mat3 modelViewNormal;\n"
-"uniform vec4 lightPosition;\n"
-"void main()\n"
-"{\n"
-" texCoord = vertexTexCoord;\n"
-" vec3 normal = normalize( modelViewNormal * vertexNormal );\n"
-" vec3 tangent = normalize( modelViewNormal * vertexTangent.xyz );\n"
-" vec3 position = vec3( modelView * vec4( vertexPosition, 1.0 ) );\n"
-" vec3 binormal = normalize( cross( normal, tangent ) );\n"
-" mat3 tangentMatrix = mat3 (\n"
-" tangent.x, binormal.x, normal.x,\n"
-" tangent.y, binormal.y, normal.y,\n"
-" tangent.z, binormal.z, normal.z );\n"
-" vec3 s = vec3( lightPosition ) - position;\n"
-" lightDir = normalize( tangentMatrix * s );\n"
-" vec3 v = -position;\n"
-" viewDir = normalize( tangentMatrix * v );\n"
-" gl_Position = projection * modelView * vec4( vertexPosition, 1.0 );\n"
-"}\n"
- },
- {
- "normaldiffusemap.frag",
-"$VERSION\n"
-"uniform $HIGHP vec3 lightIntensity;\n"
-"uniform $HIGHP vec3 ka;\n"
-"uniform $HIGHP vec3 ks;\n"
-"uniform $HIGHP float shininess;\n"
-"uniform sampler2D diffuseTexture;\n"
-"uniform sampler2D normalTexture;\n"
-"$FVARYING $HIGHP vec3 lightDir;\n"
-"$FVARYING $HIGHP vec3 viewDir;\n"
-"$FVARYING $HIGHP vec2 texCoord;\n"
-"$DECL_FRAGCOLOR\n"
-"$HIGHP vec3 adsModel( const $HIGHP vec3 norm, const $HIGHP vec3 diffuseReflect)\n"
-"{\n"
-" $HIGHP vec3 r = reflect( -lightDir, norm );\n"
-" $HIGHP vec3 ambient = lightIntensity * ka;\n"
-" $HIGHP float sDotN = max( dot( lightDir, norm ), 0.0 );\n"
-" $HIGHP vec3 diffuse = lightIntensity * diffuseReflect * sDotN;\n"
-" $HIGHP vec3 ambientAndDiff = ambient + diffuse;\n"
-" $HIGHP vec3 spec = vec3( 0.0 );\n"
-" if ( sDotN > 0.0 )\n"
-" spec = lightIntensity * ks * pow( max( dot( r, viewDir ), 0.0 ), shininess );\n"
-" return ambientAndDiff + spec;\n"
-"}\n"
-"void main()\n"
-"{\n"
-" $HIGHP vec4 kd = $TEXTURE2D( diffuseTexture, texCoord );\n"
-" $HIGHP vec4 normal = 2.0 * $TEXTURE2D( normalTexture, texCoord ) - vec4( 1.0 );\n"
-" $FRAGCOLOR = vec4( adsModel( normalize( normal.xyz ), kd.rgb) * kd.a, kd.a );\n"
-"}\n"
- },
- {
- "normaldiffusespecularmap.frag",
-"$VERSION\n"
-"uniform $HIGHP vec3 lightIntensity;\n"
-"uniform $HIGHP vec3 ka;\n"
-"uniform $HIGHP float shininess;\n"
-"uniform sampler2D diffuseTexture;\n"
-"uniform sampler2D specularTexture;\n"
-"uniform sampler2D normalTexture;\n"
-"$FVARYING $HIGHP vec3 lightDir;\n"
-"$FVARYING $HIGHP vec3 viewDir;\n"
-"$FVARYING $HIGHP vec2 texCoord;\n"
-"$DECL_FRAGCOLOR\n"
-"$HIGHP vec3 adsModel( const $HIGHP vec3 norm, const $HIGHP vec3 diffuseReflect, const $HIGHP vec3 specular )\n"
-"{\n"
-" $HIGHP vec3 r = reflect( -lightDir, norm );\n"
-" $HIGHP vec3 ambient = lightIntensity * ka;\n"
-" $HIGHP float sDotN = max( dot( lightDir, norm ), 0.0 );\n"
-" $HIGHP vec3 diffuse = lightIntensity * diffuseReflect * sDotN;\n"
-" $HIGHP vec3 ambientAndDiff = ambient + diffuse;\n"
-" $HIGHP vec3 spec = vec3( 0.0 );\n"
-" if ( sDotN > 0.0 )\n"
-" spec = lightIntensity * ( shininess / ( 8.0 * 3.14 ) ) * pow( max( dot( r, viewDir ), 0.0 ), shininess );\n"
-" return (ambientAndDiff + spec * specular.rgb);\n"
-"}\n"
-"void main()\n"
-"{\n"
-" $HIGHP vec4 kd = $TEXTURE2D( diffuseTexture, texCoord );\n"
-" $HIGHP vec3 ks = $TEXTURE2D( specularTexture, texCoord );\n"
-" $HIGHP vec4 normal = 2.0 * $TEXTURE2D( normalTexture, texCoord ) - vec4( 1.0 );\n"
-" $FRAGCOLOR = vec4( adsModel( normalize( normal.xyz ), kd.rgb, ks ) * kd.a, kd.a );\n"
-"}\n"
- }
-};
-
-void GltfExporter::initShaderInfo()
-{
- ProgramInfo p;
-
- p = ProgramInfo();
- p.commonTechniqueName = "PHONG"; // diffuse RGBA, specular RGBA
- p.vertShader = "color.vert";
- p.fragShader = "color.frag";
- p.attributes << ProgramInfo::Param("position", "vertexPosition", "POSITION", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("normal", "vertexNormal", "NORMAL", GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("projection", "projection", "PROJECTION", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("modelView", "modelView", "MODELVIEW", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("normalMatrix", "modelViewNormal", "MODELVIEWINVERSETRANSPOSE", GLT_FLOAT_MAT3);
- p.uniforms << ProgramInfo::Param("lightPosition", "lightPosition", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("lightIntensity", "lightIntensity", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("ambient", "ka", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("diffuse", "kd", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("specular", "ks", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("shininess", "shininess", QString(), GLT_FLOAT);
- m_progs << p;
-
- p = ProgramInfo();
- p.commonTechniqueName = "PHONG"; // diffuse texture, specular RGBA
- p.vertShader = "diffusemap.vert";
- p.fragShader = "diffusemap.frag";
- p.attributes << ProgramInfo::Param("position", "vertexPosition", "POSITION", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("normal", "vertexNormal", "NORMAL", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("texcoord0", "vertexTexCoord", "TEXCOORD_0", GLT_FLOAT_VEC2);
- p.uniforms << ProgramInfo::Param("projection", "projection", "PROJECTION", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("modelView", "modelView", "MODELVIEW", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("normalMatrix", "modelViewNormal", "MODELVIEWINVERSETRANSPOSE", GLT_FLOAT_MAT3);
- p.uniforms << ProgramInfo::Param("lightPosition", "lightPosition", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("lightIntensity", "lightIntensity", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("ambient", "ka", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("specular", "ks", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("shininess", "shininess", QString(), GLT_FLOAT);
- p.uniforms << ProgramInfo::Param("diffuse", "diffuseTexture", QString(), GLT_SAMPLER_2D);
- m_progs << p;
-
- p = ProgramInfo();
- p.commonTechniqueName = "PHONG"; // diffuse texture, specular texture
- p.vertShader = "diffusemap.vert";
- p.fragShader = "diffusespecularmap.frag";
- p.attributes << ProgramInfo::Param("position", "vertexPosition", "POSITION", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("normal", "vertexNormal", "NORMAL", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("texcoord0", "vertexTexCoord", "TEXCOORD_0", GLT_FLOAT_VEC2);
- p.uniforms << ProgramInfo::Param("projection", "projection", "PROJECTION", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("modelView", "modelView", "MODELVIEW", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("normalMatrix", "modelViewNormal", "MODELVIEWINVERSETRANSPOSE", GLT_FLOAT_MAT3);
- p.uniforms << ProgramInfo::Param("lightPosition", "lightPosition", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("lightIntensity", "lightIntensity", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("ambient", "ka", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("shininess", "shininess", QString(), GLT_FLOAT);
- p.uniforms << ProgramInfo::Param("diffuse", "diffuseTexture", QString(), GLT_SAMPLER_2D);
- p.uniforms << ProgramInfo::Param("specular", "specularTexture", QString(), GLT_SAMPLER_2D);
- m_progs << p;
-
- p = ProgramInfo();
- p.commonTechniqueName = "PHONG"; // diffuse texture, specular RGBA, normalmap texture
- p.vertShader = "normaldiffusemap.vert";
- p.fragShader = "normaldiffusemap.frag";
- p.attributes << ProgramInfo::Param("position", "vertexPosition", "POSITION", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("normal", "vertexNormal", "NORMAL", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("texcoord0", "vertexTexCoord", "TEXCOORD_0", GLT_FLOAT_VEC2);
- p.attributes << ProgramInfo::Param("tangent", "vertexTangent", "TANGENT", GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("projection", "projection", "PROJECTION", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("modelView", "modelView", "MODELVIEW", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("normalMatrix", "modelViewNormal", "MODELVIEWINVERSETRANSPOSE", GLT_FLOAT_MAT3);
- p.uniforms << ProgramInfo::Param("lightPosition", "lightPosition", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("lightIntensity", "lightIntensity", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("ambient", "ka", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("specular", "ks", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("shininess", "shininess", QString(), GLT_FLOAT);
- p.uniforms << ProgramInfo::Param("diffuse", "diffuseTexture", QString(), GLT_SAMPLER_2D);
- p.uniforms << ProgramInfo::Param("normalmap", "normalTexture", QString(), GLT_SAMPLER_2D);
- m_progs << p;
-
- p = ProgramInfo();
- p.commonTechniqueName = "PHONG"; // diffuse texture, specular texture, normalmap texture
- p.vertShader = "normaldiffusemap.vert";
- p.fragShader = "normaldiffusespecularmap.frag";
- p.attributes << ProgramInfo::Param("position", "vertexPosition", "POSITION", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("normal", "vertexNormal", "NORMAL", GLT_FLOAT_VEC3);
- p.attributes << ProgramInfo::Param("texcoord0", "vertexTexCoord", "TEXCOORD_0", GLT_FLOAT_VEC2);
- p.attributes << ProgramInfo::Param("tangent", "vertexTangent", "TANGENT", GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("projection", "projection", "PROJECTION", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("modelView", "modelView", "MODELVIEW", GLT_FLOAT_MAT4);
- p.uniforms << ProgramInfo::Param("normalMatrix", "modelViewNormal", "MODELVIEWINVERSETRANSPOSE", GLT_FLOAT_MAT3);
- p.uniforms << ProgramInfo::Param("lightPosition", "lightPosition", QString(), GLT_FLOAT_VEC4);
- p.uniforms << ProgramInfo::Param("lightIntensity", "lightIntensity", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("ambient", "ka", QString(), GLT_FLOAT_VEC3);
- p.uniforms << ProgramInfo::Param("shininess", "shininess", QString(), GLT_FLOAT);
- p.uniforms << ProgramInfo::Param("diffuse", "diffuseTexture", QString(), GLT_SAMPLER_2D);
- p.uniforms << ProgramInfo::Param("specular", "specularTexture", QString(), GLT_SAMPLER_2D);
- p.uniforms << ProgramInfo::Param("normalmap", "normalTexture", QString(), GLT_SAMPLER_2D);
- m_progs << p;
-
- m_subst_es2 << qMakePair(QByteArrayLiteral("$VERSION"), QByteArray());
- m_subst_es2 << qMakePair(QByteArrayLiteral("$ATTRIBUTE"), QByteArrayLiteral("attribute"));
- m_subst_es2 << qMakePair(QByteArrayLiteral("$VVARYING"), QByteArrayLiteral("varying"));
- m_subst_es2 << qMakePair(QByteArrayLiteral("$FVARYING"), QByteArrayLiteral("varying"));
- m_subst_es2 << qMakePair(QByteArrayLiteral("$TEXTURE2D"), QByteArrayLiteral("texture2D"));
- m_subst_es2 << qMakePair(QByteArrayLiteral("$DECL_FRAGCOLOR"), QByteArray());
- m_subst_es2 << qMakePair(QByteArrayLiteral("$FRAGCOLOR"), QByteArrayLiteral("gl_FragColor"));
- m_subst_es2 << qMakePair(QByteArrayLiteral("$HIGHP"), QByteArrayLiteral("highp"));
-
- m_subst_core << qMakePair(QByteArrayLiteral("$VERSION"), QByteArrayLiteral("#version 150 core"));
- m_subst_core << qMakePair(QByteArrayLiteral("$ATTRIBUTE"), QByteArrayLiteral("in"));
- m_subst_core << qMakePair(QByteArrayLiteral("$VVARYING"), QByteArrayLiteral("out"));
- m_subst_core << qMakePair(QByteArrayLiteral("$FVARYING"), QByteArrayLiteral("in"));
- m_subst_core << qMakePair(QByteArrayLiteral("$TEXTURE2D"), QByteArrayLiteral("texture"));
- m_subst_core << qMakePair(QByteArrayLiteral("$DECL_FRAGCOLOR"), QByteArrayLiteral("out vec4 fragColor;"));
- m_subst_core << qMakePair(QByteArrayLiteral("$FRAGCOLOR"), QByteArrayLiteral("fragColor"));
- m_subst_core << qMakePair(QByteArrayLiteral("$HIGHP "), QByteArray());
-}
-
-GltfExporter::ProgramInfo *GltfExporter::chooseProgram(uint materialIndex)
-{
- Importer::MaterialInfo matInfo = m_importer->materialInfo(materialIndex);
- const bool hasNormalTexture = matInfo.m_textures.contains("normal");
- const bool hasSpecularTexture = matInfo.m_textures.contains("specular");
- const bool hasDiffuseTexture = matInfo.m_textures.contains("diffuse");
-
- if (hasNormalTexture && !m_importer->allMeshesForMaterialHaveTangents(materialIndex))
- qWarning() << "WARNING: Tangent vectors not exported while the material requires it. (hint: try -t)";
-
- if (hasNormalTexture && hasSpecularTexture && hasDiffuseTexture) {
- if (opts.showLog)
- qDebug() << "Using program taking diffuse, specular, normal textures";
- return &m_progs[4];
- }
-
- if (hasNormalTexture && hasDiffuseTexture) {
- if (opts.showLog)
- qDebug() << "Using program taking diffuse, normal textures";
- return &m_progs[3];
- }
-
- if (hasSpecularTexture && hasDiffuseTexture) {
- if (opts.showLog)
- qDebug() << "Using program taking diffuse, specular textures";
- return &m_progs[2];
- }
-
- if (hasDiffuseTexture) {
- if (opts.showLog)
- qDebug() << "Using program taking diffuse texture";
- return &m_progs[1];
- }
-
- if (opts.showLog)
- qDebug() << "Using program without textures";
- return &m_progs[0];
-}
-
-QString GltfExporter::exportNode(const Importer::Node *n, QJsonObject &nodes)
-{
- QJsonObject node;
- node["name"] = n->name;
- QJsonArray children;
- for (const Importer::Node *c : n->children) {
- if (nodeIsUseful(c))
- children << exportNode(c, nodes);
- }
- node["children"] = children;
- QJsonArray matrix;
- const float *mtxp = n->transformation.constData();
- for (int j = 0; j < 16; ++j)
- matrix.append(*mtxp++);
- node["matrix"] = matrix;
- QJsonArray meshList;
- for (int j = 0; j < n->meshes.count(); ++j)
- meshList.append(m_importer->meshInfo(n->meshes[j]).name);
- if (!meshList.isEmpty()) {
- node["meshes"] = meshList;
- } else {
- QHash<QString, Importer::CameraInfo> cam = m_importer->cameraInfo();
- if (cam.contains(n->name))
- node["camera"] = cam[n->name].name;
- }
-
- nodes[n->uniqueName] = node;
- return n->uniqueName;
-}
-
-static inline QJsonArray col2jsvec(const QVector<float> &color, bool alpha = false)
-{
- QJsonArray arr;
- arr << color[0] << color[1] << color[2];
- if (alpha)
- arr << color[3];
- return arr;
-}
-
-static inline QJsonArray vec2jsvec(const QVector<float> &v)
-{
- QJsonArray arr;
- for (int i = 0; i < v.count(); ++i)
- arr << v[i];
- return arr;
-}
-
-static inline void promoteColorsToRGBA(QJsonObject *obj)
-{
- QJsonObject::iterator it = obj->begin(), itEnd = obj->end();
- while (it != itEnd) {
- QJsonArray arr = it.value().toArray();
- if (arr.count() == 3) {
- const QString key = it.key();
- if (key == QStringLiteral("ambient")
- || key == QStringLiteral("diffuse")
- || key == QStringLiteral("specular")) {
- arr.append(1);
- *it = arr;
- }
- }
- ++it;
- }
-}
-
-void GltfExporter::exportMaterials(QJsonObject &materials, QHash<QString, QString> *textureNameMap)
-{
- for (uint i = 0; i < m_importer->materialCount(); ++i) {
- Importer::MaterialInfo matInfo = m_importer->materialInfo(i);
- QJsonObject material;
- material["name"] = matInfo.originalName;
-
- bool opaque = true;
- QJsonObject vals;
- for (QHash<QByteArray, QString>::const_iterator it = matInfo.m_textures.constBegin(); it != matInfo.m_textures.constEnd(); ++it) {
- if (!textureNameMap->contains(it.value()))
- textureNameMap->insert(it.value(), newTextureName());
- QByteArray key = it.key();
- if (key == QByteArrayLiteral("normal")) // avoid clashing with the vertex normals
- key = QByteArrayLiteral("normalmap");
- // alpha is supported for diffuse textures, but have to check the image data to decide if blending is needed
- if (key == QByteArrayLiteral("diffuse")) {
- QString imgFn = opts.outDir + it.value();
- if (m_imageHasAlpha.contains(imgFn)) {
- if (m_imageHasAlpha[imgFn])
- opaque = false;
- } else {
-#ifdef HAS_QIMAGE
- QImage img(imgFn);
- if (!img.isNull()) {
- if (img.hasAlphaChannel()) {
- for (int y = 0; opaque && y < img.height(); ++y)
- for (int x = 0; opaque && x < img.width(); ++x)
- if (qAlpha(img.pixel(x, y)) < 255)
- opaque = false;
- }
- m_imageHasAlpha[imgFn] = !opaque;
- } else {
- qWarning() << "WARNING: Cannot determine presence of alpha for" << imgFn;
- }
-#else
- qWarning() << "WARNING: No image support, assuming all textures are opaque";
-#endif
- }
- }
- vals[key] = textureNameMap->value(it.value());
- }
- for (QHash<QByteArray, float>::const_iterator it = matInfo.m_values.constBegin();
- it != matInfo.m_values.constEnd(); ++it) {
- if (vals.contains(it.key()))
- continue;
- vals[it.key()] = it.value();
- }
- for (QHash<QByteArray, QVector<float> >::const_iterator it = matInfo.m_colors.constBegin();
- it != matInfo.m_colors.constEnd(); ++it) {
- if (vals.contains(it.key()))
- continue;
- // alpha is supported for the diffuse color. < 1 will enable blending.
- const bool alpha = it.key() == QStringLiteral("diffuse");
- if (alpha && it.value()[3] < 1.0f)
- opaque = false;
- vals[it.key()] = col2jsvec(it.value(), alpha);
- }
- if (opts.shaders)
- material["values"] = vals;
-
- ProgramInfo *prog = chooseProgram(i);
- TechniqueInfo techniqueInfo;
- bool needsNewTechnique = true;
- for (int j = 0; j < m_techniques.count(); ++j) {
- if (m_techniques[j].prog == prog) {
- techniqueInfo = m_techniques[j];
- needsNewTechnique = opaque != techniqueInfo.opaque;
- }
- if (!needsNewTechnique)
- break;
- }
- if (needsNewTechnique) {
- QString techniqueName = newTechniqueName();
- techniqueInfo = TechniqueInfo(techniqueName, opaque, prog);
- m_techniques.append(techniqueInfo);
- m_usedPrograms.insert(prog);
- }
-
- if (opts.shaders) {
- if (opts.showLog)
- qDebug().noquote() << "Material #" << i << "->" << techniqueInfo.name;
-
- material["technique"] = techniqueInfo.name;
- if (opts.genCore) {
- material["techniqueCore"] = techniqueInfo.coreName;
- material["techniqueGL2"] = techniqueInfo.gl2Name;
- }
- }
-
- if (opts.commonMat) {
- // The built-in shaders we output are of little use in practice.
- // Ideally we want Qt3D's own standard materials in order to have our
- // models participate in lighting for example. To achieve this, output
- // a KHR_materials_common block which Qt3D's loader will recognize and
- // prefer over the shader-based techniques.
- if (!prog->commonTechniqueName.isEmpty()) {
- QJsonObject commonMat;
- commonMat["technique"] = prog->commonTechniqueName;
- // Set the values as-is. "normalmap" is our own extension, not in the spec.
- // However, RGB colors have to be promoted to RGBA since the spec uses
- // vec4, and all types are pre-defined for common material values.
- promoteColorsToRGBA(&vals);
- commonMat["values"] = vals;
- if (!opaque)
- commonMat["transparent"] = true;
- QJsonObject extensions;
- extensions["KHR_materials_common"] = commonMat;
- material["extensions"] = extensions;
- }
- }
-
- materials[matInfo.name] = material;
- }
-}
-
-void GltfExporter::writeShader(const QString &src, const QString &dst, const QVector<QPair<QByteArray, QByteArray> > &substTab)
-{
- for (const Shader shader : shaders) {
- QByteArray name = src.toUtf8();
- if (!qstrcmp(shader.name, name.constData())) {
- QString outfn = opts.outDir + dst;
- QFile outf(outfn);
- if (outf.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- m_files.insert(QFileInfo(outf.fileName()).fileName());
- if (opts.showLog)
- qDebug() << "Writing" << outfn;
- const auto lines = QString::fromUtf8(shader.text).split('\n');
- for (QString line : lines) {
- for (const auto &subst : substTab)
- line.replace(subst.first, subst.second);
- line += QStringLiteral("\n");
- outf.write(line.toUtf8());
- }
- }
- return;
- }
- }
- qWarning() << "ERROR: No shader found for" << src;
-}
-
-void GltfExporter::exportParameter(QJsonObject &dst, const QVector<ProgramInfo::Param> &params)
-{
- for (const ProgramInfo::Param &param : params) {
- QJsonObject parameter;
- parameter["type"] = int(param.type);
- if (!param.semantic.isEmpty())
- parameter["semantic"] = param.semantic;
- if (param.name == QStringLiteral("lightIntensity"))
- parameter["value"] = QJsonArray() << 1 << 1 << 1;
- if (param.name == QStringLiteral("lightPosition"))
- parameter["value"] = QJsonArray() << 0 << 0 << 0 << 1;
- dst[param.name] = parameter;
- }
-}
-
-namespace {
-struct ProgramNames
-{
- QString name;
- QString coreName;
-};
-}
-
-void GltfExporter::exportTechniques(QJsonObject &obj, const QString &basename)
-{
- if (!opts.shaders)
- return;
-
- QJsonObject shaders;
- QHash<QString, QString> shaderMap;
- for (ProgramInfo *prog : qAsConst(m_usedPrograms)) {
- QString newName;
- if (!shaderMap.contains(prog->vertShader)) {
- QJsonObject vertexShader;
- vertexShader["type"] = 35633;
- if (newName.isEmpty())
- newName = newShaderName();
- QString key = basename + QStringLiteral("_") + newName + QStringLiteral("_v");
- QString fn = QString(QStringLiteral("%1.vert")).arg(key);
- vertexShader["uri"] = fn;
- writeShader(prog->vertShader, fn, m_subst_es2);
- if (opts.genCore) {
- QJsonObject coreVertexShader;
- QString coreKey = QString(QStringLiteral("%1_core").arg(key));
- fn = QString(QStringLiteral("%1.vert")).arg(coreKey);
- coreVertexShader["type"] = 35633;
- coreVertexShader["uri"] = fn;
- writeShader(prog->vertShader, fn, m_subst_core);
- shaders[coreKey] = coreVertexShader;
- shaderMap.insert(QString(prog->vertShader + QStringLiteral("_core")), coreKey);
- }
- shaders[key] = vertexShader;
- shaderMap.insert(prog->vertShader, key);
- }
- if (!shaderMap.contains(prog->fragShader)) {
- QJsonObject fragmentShader;
- fragmentShader["type"] = 35632;
- if (newName.isEmpty())
- newName = newShaderName();
- QString key = basename + QStringLiteral("_") + newName + QStringLiteral("_f");
- QString fn = QString(QStringLiteral("%1.frag")).arg(key);
- fragmentShader["uri"] = fn;
- writeShader(prog->fragShader, fn, m_subst_es2);
- if (opts.genCore) {
- QJsonObject coreFragmentShader;
- QString coreKey = QString(QStringLiteral("%1_core").arg(key));
- fn = QString(QStringLiteral("%1.frag")).arg(coreKey);
- coreFragmentShader["type"] = 35632;
- coreFragmentShader["uri"] = fn;
- writeShader(prog->fragShader, fn, m_subst_core);
- shaders[coreKey] = coreFragmentShader;
- shaderMap.insert(QString(prog->fragShader + QStringLiteral("_core")), coreKey);
- }
- shaders[key] = fragmentShader;
- shaderMap.insert(prog->fragShader, key);
- }
- }
- obj["shaders"] = shaders;
-
- QJsonObject programs;
- QHash<const ProgramInfo *, ProgramNames> programMap;
- for (const ProgramInfo *prog : qAsConst(m_usedPrograms)) {
- QJsonObject program;
- program["vertexShader"] = shaderMap[prog->vertShader];
- program["fragmentShader"] = shaderMap[prog->fragShader];
- QJsonArray attrs;
- for (const ProgramInfo::Param &param : prog->attributes) {
- attrs << param.nameInShader;
- }
- program["attributes"] = attrs;
- QString programName = newProgramName();
- programMap[prog].name = programName;
- programs[programMap[prog].name] = program;
- if (opts.genCore) {
- program["vertexShader"] = shaderMap[QString(prog->vertShader + QLatin1String("_core"))];
- program["fragmentShader"] = shaderMap[QString(prog->fragShader + QLatin1String("_core"))];
- QJsonArray attrs;
- for (const ProgramInfo::Param &param : prog->attributes) {
- attrs << param.nameInShader;
- }
- program["attributes"] = attrs;
- programMap[prog].coreName = programName + QLatin1String("_core");
- programs[programMap[prog].coreName] = program;
- }
- }
- obj["programs"] = programs;
-
- QJsonObject techniques;
- for (const TechniqueInfo &techniqueInfo : qAsConst(m_techniques)) {
- QJsonObject technique;
- QJsonObject parameters;
- const ProgramInfo *prog = techniqueInfo.prog;
- exportParameter(parameters, prog->attributes);
- exportParameter(parameters, prog->uniforms);
- technique["parameters"] = parameters;
- technique["program"] = programMap[prog].name;
- QJsonObject progAttrs;
- for (const ProgramInfo::Param &param : prog->attributes) {
- progAttrs[param.nameInShader] = param.name;
- }
- technique["attributes"] = progAttrs;
- QJsonObject progUniforms;
- for (const ProgramInfo::Param &param : prog->uniforms) {
- progUniforms[param.nameInShader] = param.name;
- }
- technique["uniforms"] = progUniforms;
- QJsonObject states;
- QJsonArray enabledStates;
- enabledStates << GLT_DEPTH_TEST << GLT_CULL_FACE;
- if (!techniqueInfo.opaque) {
- enabledStates << GLT_BLEND;
- QJsonObject funcs;
- // GL_ONE, GL_ONE_MINUS_SRC_ALPHA
- funcs["blendFuncSeparate"] = QJsonArray() << 1 << 771 << 1 << 771;
- states["functions"] = funcs;
- }
- states["enable"] = enabledStates;
- technique["states"] = states;
- techniques[techniqueInfo.name] = technique;
-
- if (opts.genCore) {
- //GL2 (same as ES2)
- techniques[techniqueInfo.gl2Name] = technique;
-
- //Core
- technique["program"] = programMap[prog].coreName;
- techniques[techniqueInfo.coreName] = technique;
- }
- }
- obj["techniques"] = techniques;
-}
-
-void GltfExporter::exportAnimations(QJsonObject &obj,
- QVector<Importer::BufferInfo> &bufList,
- QVector<Importer::MeshInfo::BufferView> &bvList,
- QVector<Importer::MeshInfo::Accessor> &accList)
-{
- const auto animationInfos = m_importer->animations();
- if (animationInfos.empty()) {
- obj["animations"] = QJsonObject();
- return;
- }
-
- QString bvName = newBufferViewName();
- QByteArray extraData;
-
- int sz = 0;
- for (const Importer::AnimationInfo &ai : animationInfos)
- sz += ai.keyFrames.count() * (1 + 3 + 4 + 3) * sizeof(float);
- extraData.resize(sz);
-
- float *base = reinterpret_cast<float *>(extraData.data());
- float *p = base;
-
- QJsonObject animations;
- for (const Importer::AnimationInfo &ai : animationInfos) {
- QJsonObject animation;
- animation["name"] = ai.name;
- animation["count"] = ai.keyFrames.count();
- QJsonObject samplers;
- QJsonArray channels;
-
- if (ai.hasTranslation) {
- QJsonObject sampler;
- sampler["input"] = QStringLiteral("TIME");
- sampler["interpolation"] = QStringLiteral("LINEAR");
- sampler["output"] = QStringLiteral("translation");
- samplers["sampler_translation"] = sampler;
- QJsonObject channel;
- channel["sampler"] = QStringLiteral("sampler_translation");
- QJsonObject target;
- target["id"] = ai.targetNode;
- target["path"] = QStringLiteral("translation");
- channel["target"] = target;
- channels << channel;
- }
- if (ai.hasRotation) {
- QJsonObject sampler;
- sampler["input"] = QStringLiteral("TIME");
- sampler["interpolation"] = QStringLiteral("LINEAR");
- sampler["output"] = QStringLiteral("rotation");
- samplers["sampler_rotation"] = sampler;
- QJsonObject channel;
- channel["sampler"] = QStringLiteral("sampler_rotation");
- QJsonObject target;
- target["id"] = ai.targetNode;
- target["path"] = QStringLiteral("rotation");
- channel["target"] = target;
- channels << channel;
- }
- if (ai.hasScale) {
- QJsonObject sampler;
- sampler["input"] = QStringLiteral("TIME");
- sampler["interpolation"] = QStringLiteral("LINEAR");
- sampler["output"] = QStringLiteral("scale");
- samplers["sampler_scale"] = sampler;
- QJsonObject channel;
- channel["sampler"] = QStringLiteral("sampler_scale");
- QJsonObject target;
- target["id"] = ai.targetNode;
- target["path"] = QStringLiteral("scale");
- channel["target"] = target;
- channels << channel;
- }
-
- animation["samplers"] = samplers;
- animation["channels"] = channels;
- QJsonObject parameters;
-
- // Multiple animations sharing the same data should ideally use the
- // same accessors. This we unfortunately cannot do due to assimp's/our
- // own data structures so everything will get its own accessor and data
- // for now.
-
- Importer::MeshInfo::Accessor acc;
- acc.name = newAccessorName();
- acc.bufferView = bvName;
- acc.count = ai.keyFrames.count();
- acc.componentType = GLT_FLOAT;
- acc.type = QStringLiteral("SCALAR");
- acc.offset = uint((p - base) * sizeof(float));
- for (const Importer::KeyFrame &kf : ai.keyFrames)
- *p++ = kf.t;
- parameters["TIME"] = acc.name;
- accList << acc;
-
- if (ai.hasTranslation) {
- acc.name = newAccessorName();
- acc.componentType = GLT_FLOAT;
- acc.type = QStringLiteral("VEC3");
- acc.offset = uint((p - base) * sizeof(float));
- QVector<float> lastV;
- for (const Importer::KeyFrame &kf : ai.keyFrames) {
- const QVector<float> *v = kf.transValid ? &kf.trans : &lastV;
- *p++ = v->at(0);
- *p++ = v->at(1);
- *p++ = v->at(2);
- if (kf.transValid)
- lastV = *v;
- }
- parameters["translation"] = acc.name;
- accList << acc;
- }
- if (ai.hasRotation) {
- acc.name = newAccessorName();
- acc.componentType = GLT_FLOAT;
- acc.type = QStringLiteral("VEC4");
- acc.offset = uint((p - base) * sizeof(float));
- QVector<float> lastV;
- for (const Importer::KeyFrame &kf : ai.keyFrames) {
- const QVector<float> *v = kf.rotValid ? &kf.rot : &lastV;
- *p++ = v->at(1); // x
- *p++ = v->at(2); // y
- *p++ = v->at(3); // z
- *p++ = v->at(0); // w
- if (kf.rotValid)
- lastV = *v;
- }
- parameters["rotation"] = acc.name;
- accList << acc;
- }
- if (ai.hasScale) {
- acc.name = newAccessorName();
- acc.componentType = GLT_FLOAT;
- acc.type = QStringLiteral("VEC3");
- acc.offset = uint((p - base) * sizeof(float));
- QVector<float> lastV;
- for (const Importer::KeyFrame &kf : ai.keyFrames) {
- const QVector<float> *v = kf.scaleValid ? &kf.scale : &lastV;
- *p++ = v->at(0);
- *p++ = v->at(1);
- *p++ = v->at(2);
- if (kf.scaleValid)
- lastV = *v;
- }
- parameters["scale"] = acc.name;
- accList << acc;
- }
- animation["parameters"] = parameters;
-
- animations[newAnimationName()] = animation;
- }
- obj["animations"] = animations;
-
- // Now all the key frame data is in extraData. Append it to the first buffer
- // and create a single buffer view for it.
- if (!extraData.isEmpty()) {
- if (bufList.isEmpty()) {
- Importer::BufferInfo b;
- b.name = QStringLiteral("buf");
- bufList << b;
- }
- Importer::BufferInfo &buf(bufList[0]);
- Importer::MeshInfo::BufferView bv;
- bv.name = bvName;
- bv.offset = buf.data.size();
- bv.length = uint((p - base) * sizeof(float));
- bv.componentType = GLT_FLOAT;
- bvList << bv;
- extraData.resize(bv.length);
- buf.data += extraData;
- if (opts.showLog)
- qDebug().noquote() << "Animation data in buffer uses" << extraData.size() << "bytes";
- }
-}
-
-void GltfExporter::save(const QString &inputFilename)
-{
- if (opts.showLog)
- qDebug() << "Exporting";
-
- m_files.clear();
- m_techniques.clear();
- m_usedPrograms.clear();
-
- QFile f;
- QString basename = QFileInfo(inputFilename).baseName();
- QString bufNameTempl = basename + QStringLiteral("_%1.bin");
-
- copyExternalTextures(inputFilename);
- exportEmbeddedTextures();
- compressTextures();
-
- m_obj = QJsonObject();
-
- QVector<Importer::BufferInfo> bufList = m_importer->buffers();
- QVector<Importer::MeshInfo::BufferView> bvList = m_importer->bufferViews();
- QVector<Importer::MeshInfo::Accessor> accList = m_importer->accessors();
-
- // Animations add data to the buffer so process them first.
- exportAnimations(m_obj, bufList, bvList, accList);
-
- QJsonObject asset;
- asset["generator"] = QString(QStringLiteral("qgltf %1")).arg(QCoreApplication::applicationVersion());
- asset["version"] = QStringLiteral("1.0");
- asset["premultipliedAlpha"] = true;
- m_obj["asset"] = asset;
-
- for (int i = 0; i < bufList.count(); ++i) {
- QString bufName = bufNameTempl.arg(i + 1);
- f.setFileName(opts.outDir + bufName);
- if (opts.showLog)
- qDebug().noquote() << (opts.compress ? "Writing (compressed)" : "Writing") << (opts.outDir + bufName);
- if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- m_files.insert(QFileInfo(f.fileName()).fileName());
- QByteArray data = bufList[i].data;
- if (opts.compress)
- data = qCompress(data);
- f.write(data);
- f.close();
- }
- }
-
- QJsonObject buffers;
- for (int i = 0; i < bufList.count(); ++i) {
- QJsonObject buffer;
- buffer["byteLength"] = bufList[i].data.size();
- buffer["type"] = QStringLiteral("arraybuffer");
- buffer["uri"] = bufNameTempl.arg(i + 1);
- if (opts.compress)
- buffer["compression"] = QStringLiteral("Qt");
- buffers[bufList[i].name] = buffer;
- }
- m_obj["buffers"] = buffers;
-
- QJsonObject bufferViews;
- for (const Importer::MeshInfo::BufferView &bv : qAsConst(bvList)) {
- QJsonObject bufferView;
- bufferView["buffer"] = bufList[bv.bufIndex].name;
- bufferView["byteLength"] = int(bv.length);
- bufferView["byteOffset"] = int(bv.offset);
- if (bv.target)
- bufferView["target"] = int(bv.target);
- bufferViews[bv.name] = bufferView;
- }
- m_obj["bufferViews"] = bufferViews;
-
- QJsonObject accessors;
- for (const Importer::MeshInfo::Accessor &acc : qAsConst(accList)) {
- QJsonObject accessor;
- accessor["bufferView"] = acc.bufferView;
- accessor["byteOffset"] = int(acc.offset);
- accessor["byteStride"] = int(acc.stride);
- accessor["count"] = int(acc.count);
- accessor["componentType"] = int(acc.componentType);
- accessor["type"] = acc.type;
- if (!acc.minVal.isEmpty() && !acc.maxVal.isEmpty()) {
- accessor["min"] = vec2jsvec(acc.minVal);
- accessor["max"] = vec2jsvec(acc.maxVal);
- }
- accessors[acc.name] = accessor;
- }
- m_obj["accessors"] = accessors;
-
- QJsonObject meshes;
- for (uint i = 0; i < m_importer->meshCount(); ++i) {
- const Importer::MeshInfo meshInfo = m_importer->meshInfo(i);
- QJsonObject mesh;
- mesh["name"] = meshInfo.originalName;
- QJsonArray prims;
- QJsonObject prim;
- prim["mode"] = 4; // triangles
- QJsonObject attrs;
- for (const Importer::MeshInfo::Accessor &acc : meshInfo.accessors) {
- if (acc.usage != QStringLiteral("INDEX"))
- attrs[acc.usage] = acc.name;
- else
- prim["indices"] = acc.name;
- }
- prim["attributes"] = attrs;
- prim["material"] = m_importer->materialInfo(meshInfo.materialIndex).name;
- prims.append(prim);
- mesh["primitives"] = prims;
- meshes[meshInfo.name] = mesh;
- }
- m_obj["meshes"] = meshes;
-
- QJsonObject cameras;
- const auto cameraInfos = m_importer->cameraInfo();
- for (const Importer::CameraInfo &camInfo : cameraInfos) {
- QJsonObject camera;
- QJsonObject persp;
- persp["aspect_ratio"] = camInfo.aspectRatio;
- persp["yfov"] = camInfo.yfov;
- persp["znear"] = camInfo.znear;
- persp["zfar"] = camInfo.zfar;
- camera["perspective"] = persp;
- camera["type"] = QStringLiteral("perspective");
- cameras[camInfo.name] = camera;
- }
- m_obj["cameras"] = cameras;
-
- QJsonArray sceneNodes;
- QJsonObject nodes;
- for (const Importer::Node *n : qAsConst(m_importer->rootNode()->children)) {
- if (nodeIsUseful(n))
- sceneNodes << exportNode(n, nodes);
- }
- m_obj["nodes"] = nodes;
-
- QJsonObject scenes;
- QJsonObject defaultScene;
- defaultScene["nodes"] = sceneNodes;
- scenes["defaultScene"] = defaultScene;
- m_obj["scenes"] = scenes;
- m_obj["scene"] = QStringLiteral("defaultScene");
-
- QJsonObject materials;
- QHash<QString, QString> textureNameMap;
- exportMaterials(materials, &textureNameMap);
- m_obj["materials"] = materials;
-
- QJsonObject textures;
- QHash<QString, QString> imageMap; // uri -> key
- for (QHash<QString, QString>::const_iterator it = textureNameMap.constBegin(); it != textureNameMap.constEnd(); ++it) {
- QJsonObject texture;
- if (!imageMap.contains(it.key()))
- imageMap[it.key()] = newImageName();
- texture["source"] = imageMap[it.key()];
- texture["format"] = 0x1908; // RGBA
- const bool compressed = m_compressedTextures.contains(it.key());
- texture["internalFormat"] = !compressed ? 0x1908 : 0x8D64; // RGBA / ETC1
- texture["sampler"] = !compressed ? QStringLiteral("sampler_mip_rep") : QStringLiteral("sampler_nonmip_rep");
- texture["target"] = 3553; // TEXTURE_2D
- texture["type"] = 5121; // UNSIGNED_BYTE
- textures[it.value()] = texture;
- }
- m_obj["textures"] = textures;
-
- QJsonObject images;
- for (QHash<QString, QString>::const_iterator it = imageMap.constBegin(); it != imageMap.constEnd(); ++it) {
- QJsonObject image;
- image["uri"] = m_compressedTextures.contains(it.key()) ? m_compressedTextures[it.key()] : it.key();
- images[it.value()] = image;
- }
- m_obj["images"] = images;
-
- QJsonObject samplers;
- QJsonObject sampler;
- sampler["magFilter"] = 9729; // LINEAR
- sampler["minFilter"] = 9987; // LINEAR_MIPMAP_LINEAR
- sampler["wrapS"] = 10497; // REPEAT
- sampler["wrapT"] = 10497;
- samplers["sampler_mip_rep"] = sampler;
- // Compressed textures may not support mipmapping with GLES.
- if (!m_compressedTextures.isEmpty()) {
- sampler["minFilter"] = 9729; // LINEAR
- samplers["sampler_nonmip_rep"] = sampler;
- }
- m_obj["samplers"] = samplers;
-
- exportTechniques(m_obj, basename);
-
- QString gltfName = opts.outDir + basename + QStringLiteral(".qgltf");
- f.setFileName(gltfName);
-
-#if QT_CONFIG(cborstreamwriter)
- if (opts.showLog)
- qDebug().noquote() << (opts.genBin ? "Writing (CBOR)" : "Writing") << gltfName;
-
- const QIODevice::OpenMode openMode = opts.genBin
- ? (QIODevice::WriteOnly | QIODevice::Truncate)
- : (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
- const QByteArray data = opts.genBin
- ? QCborValue::fromJsonValue(m_obj).toCbor()
- : QJsonDocument(m_obj).toJson(opts.compact ? QJsonDocument::Compact
- : QJsonDocument::Indented);
-#else
- if (opts.showLog)
- qDebug().noquote() << "Writing" << gltfName;
-
- const QIODevice::OpenMode openMode
- = QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text;
- const QByteArray data
- = QJsonDocument(m_obj).toJson(opts.compact ? QJsonDocument::Compact
- : QJsonDocument::Indented);
-#endif
-
- if (f.open(openMode)) {
- m_files.insert(QFileInfo(f.fileName()).fileName());
- f.write(data);
- f.close();
- }
-
- QString qrcName = opts.outDir + basename + QStringLiteral(".qrc");
- f.setFileName(qrcName);
- if (opts.showLog)
- qDebug().noquote() << "Writing" << qrcName;
- if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
- QByteArray pre = "<RCC><qresource prefix=\"/models\">\n";
- QByteArray post = "</qresource></RCC>\n";
- f.write(pre);
- for (const QString &file : qAsConst(m_files)) {
- QString line = QString(QStringLiteral(" <file>%1</file>\n")).arg(file);
- f.write(line.toUtf8());
- }
- f.write(post);
- f.close();
- }
-
- if (opts.showLog)
- qDebug() << "Done\n";
-}
-
-static const char *description =
- "qgltf uses Assimp to import a variety of 3D model formats "
- "and export it into fast-to-load, optimized glTF "
- "assets embedded into Qt resource files.\n\n"
- "Note: this tool should typically not be invoked directly. Instead, "
- "let qmake manage it based on QT3D_MODELS in the .pro file.\n\n"
- "For standard Qt 3D usage the recommended options are -b -S.";
-
-int main(int argc, char **argv)
-{
- QCoreApplication app(argc, argv);
- app.setApplicationVersion(QStringLiteral("0.2"));
- app.setApplicationName(QStringLiteral("Qt glTF converter"));
-
- QCommandLineParser cmdLine;
- cmdLine.addHelpOption();
- cmdLine.addVersionOption();
- cmdLine.setApplicationDescription(QString::fromUtf8(description));
- QCommandLineOption outDirOpt(QStringLiteral("d"), QStringLiteral("Place all output data into <dir>"), QStringLiteral("dir"));
- cmdLine.addOption(outDirOpt);
-#if QT_CONFIG(cborstreamwriter)
- QCommandLineOption binOpt(QStringLiteral("b"), QStringLiteral("Store CBOR data in the .qgltf file"));
- cmdLine.addOption(binOpt);
-#endif
- QCommandLineOption compactOpt(QStringLiteral("m"), QStringLiteral("Store compact JSON in the .qgltf file"));
- cmdLine.addOption(compactOpt);
- QCommandLineOption compOpt(QStringLiteral("c"), QStringLiteral("qCompress() vertex/index data in the .bin file"));
- cmdLine.addOption(compOpt);
- QCommandLineOption tangentOpt(QStringLiteral("t"), QStringLiteral("Generate tangent vectors"));
- cmdLine.addOption(tangentOpt);
- QCommandLineOption nonInterleavedOpt(QStringLiteral("n"), QStringLiteral("Use non-interleaved buffer layout"));
- cmdLine.addOption(nonInterleavedOpt);
- QCommandLineOption scaleOpt(QStringLiteral("e"), QStringLiteral("Scale vertices by the float scale factor <factor>"), QStringLiteral("factor"));
- cmdLine.addOption(scaleOpt);
- QCommandLineOption coreOpt(QStringLiteral("g"), QStringLiteral("Generate OpenGL 3.2+ core profile shaders too"));
- cmdLine.addOption(coreOpt);
- QCommandLineOption etc1Opt(QStringLiteral("1"), QStringLiteral("Generate ETC1 compressed textures by invoking etc1tool (PNG only)"));
- cmdLine.addOption(etc1Opt);
- QCommandLineOption noCommonMatOpt(QStringLiteral("T"), QStringLiteral("Do not generate KHR_materials_common block"));
- cmdLine.addOption(noCommonMatOpt);
- QCommandLineOption noShadersOpt(QStringLiteral("S"), QStringLiteral("Do not generate shaders/programs/techniques"));
- cmdLine.addOption(noShadersOpt);
- QCommandLineOption silentOpt(QStringLiteral("s"), QStringLiteral("Silence debug output"));
- cmdLine.addOption(silentOpt);
- cmdLine.process(app);
- opts.outDir = cmdLine.value(outDirOpt);
-#if QT_CONFIG(cborstreamwriter)
- opts.genBin = cmdLine.isSet(binOpt);
-#endif
- opts.compact = cmdLine.isSet(compactOpt);
- opts.compress = cmdLine.isSet(compOpt);
- opts.genTangents = cmdLine.isSet(tangentOpt);
- opts.interleave = !cmdLine.isSet(nonInterleavedOpt);
- opts.scale = 1;
- if (cmdLine.isSet(scaleOpt)) {
- bool ok = false;
- float v;
- v = cmdLine.value(scaleOpt).toFloat(&ok);
- if (ok)
- opts.scale = v;
- }
- opts.genCore = cmdLine.isSet(coreOpt);
- opts.texComp = cmdLine.isSet(etc1Opt) ? Options::ETC1 : Options::NoTextureCompression;
- opts.commonMat = !cmdLine.isSet(noCommonMatOpt);
- opts.shaders = !cmdLine.isSet(noShadersOpt);
- opts.showLog = !cmdLine.isSet(silentOpt);
- if (!opts.outDir.isEmpty()) {
- if (!opts.outDir.endsWith('/'))
- opts.outDir.append('/');
- QDir().mkpath(opts.outDir);
- }
-
- const auto fileNames = cmdLine.positionalArguments();
- if (fileNames.isEmpty())
- cmdLine.showHelp();
-
- AssimpImporter importer;
- GltfExporter exporter(&importer);
- for (const QString &fn : fileNames) {
- if (!importer.load(fn)) {
- qWarning() << "Failed to import" << fn;
- continue;
- }
- exporter.save(fn);
- }
-
- return 0;
-}
diff --git a/tools/qgltf/qgltf.pro b/tools/qgltf/qgltf.pro
deleted file mode 100644
index c40016015..000000000
--- a/tools/qgltf/qgltf.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-option(host_build)
-
-SOURCES = qgltf.cpp
-
-include(../../src/3rdparty/assimp/assimp_dependency.pri)
-
-load(qt_tool)
diff --git a/tools/tools.pro b/tools/tools.pro
deleted file mode 100644
index 3b457ed50..000000000
--- a/tools/tools.pro
+++ /dev/null
@@ -1,9 +0,0 @@
-TEMPLATE = subdirs
-
-!qtHaveModule(3dcore): \
- return()
-
-QT_FOR_CONFIG += 3dcore-private
-qtConfig(assimp):qtConfig(commandlineparser): {
- SUBDIRS += qgltf
-}