ff4ff35918
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
237 lines
8.7 KiB
C++
237 lines
8.7 KiB
C++
// Copyright (C) 2021 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include "custommaterial.h"
|
|
|
|
#include <QtCore/qdir.h>
|
|
|
|
#include <QtQuick3DAssetUtils/private/qssgrtutilities_p.h>
|
|
#include <QtQuick3DAssetUtils/private/qssgqmlutilities_p.h>
|
|
|
|
#include <QtQuick3D/private/qquick3dshaderutils_p.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
using TextureStore = QHash<QString, QImage *>;
|
|
Q_GLOBAL_STATIC(TextureStore, s_textureStore);
|
|
|
|
template<typename T>
|
|
static void setProperty(QQuick3DObject &obj, const char *name, T v)
|
|
{
|
|
if (QQuick3DObjectPrivate::get(&obj)->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
|
|
if constexpr (std::is_same_v<T, QSSGSceneDesc::Texture *>) {
|
|
if (QQuick3DTexture *texture = qobject_cast<QQuick3DTexture *>(v ? v->obj : nullptr)) {
|
|
auto textureInput = new QQuick3DShaderUtilsTextureInput(&obj);
|
|
textureInput->setTexture(texture);
|
|
obj.setProperty(name, QVariant::fromValue(textureInput));
|
|
}
|
|
} else {
|
|
obj.setProperty(name, QVariant::fromValue(v));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CustomMaterial::setUniform(QSSGSceneDesc::Material &material, const Uniform &uniform)
|
|
{
|
|
if (uniform.name.isEmpty()) {
|
|
qWarning() << "Uniform without name! Skipping";
|
|
return;
|
|
}
|
|
|
|
constexpr auto Dynamic = QSSGSceneDesc::Property::Type::Dynamic;
|
|
|
|
switch (uniform.type) {
|
|
case Uniform::Type::Bool:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<bool>, uniform.b, Dynamic);
|
|
break;
|
|
case Uniform::Type::Int:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<int>, uniform.i, Dynamic);
|
|
break;
|
|
case Uniform::Type::Float:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<float>, uniform.f, Dynamic);
|
|
break;
|
|
case Uniform::Type::Vec2:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<QVector2D>, uniform.vec2, Dynamic);
|
|
break;
|
|
case Uniform::Type::Vec3:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<QVector3D>, uniform.vec3, Dynamic);
|
|
break;
|
|
case Uniform::Type::Vec4:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<QVector4D>, uniform.vec4, Dynamic);
|
|
break;
|
|
case Uniform::Type::Mat44:
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<QMatrix4x4>, uniform.m44, Dynamic);
|
|
break;
|
|
case Uniform::Type::Sampler:
|
|
{
|
|
QFileInfo fi(uniform.imagePath);
|
|
const auto &path = fi.canonicalFilePath();
|
|
if (!path.isEmpty()) {
|
|
auto it = s_textureStore->constFind(path);
|
|
const auto end = s_textureStore->constEnd();
|
|
if (it == end) {
|
|
QImage image;
|
|
if (image.load(path))
|
|
it = s_textureStore->insert(path, new QImage(image));
|
|
else
|
|
qWarning("Failed to load image %s", qPrintable(path));
|
|
}
|
|
|
|
if (it != end) {
|
|
const auto &image = *(*it);
|
|
const QSize resSize = image.size();
|
|
// Note: the image must not be deleted or modified while the textureData node is in the scene
|
|
auto *imageData = reinterpret_cast<const char *>(image.constBits());
|
|
QByteArray dataref = QByteArray::fromRawData(imageData, image.sizeInBytes());
|
|
const auto format = QByteArrayLiteral("rgba8888");
|
|
const auto &baseName = QString(fi.baseName() + QString::number(material.id));
|
|
auto name = baseName.toUtf8();
|
|
auto textureData = new QSSGSceneDesc::TextureData(dataref, resSize, format, 0, name);
|
|
QSSGSceneDesc::addNode(material, *textureData);
|
|
auto texture = new QSSGSceneDesc::Texture(QSSGSceneDesc::Texture::RuntimeType::Image2D);
|
|
QSSGSceneDesc::addNode(material, *texture);
|
|
QSSGSceneDesc::setProperty(*texture, "textureData", &QQuick3DTexture::setTextureData, textureData);
|
|
QSSGSceneDesc::setProperty(material, uniform.name.constData(), &setProperty<QSSGSceneDesc::Texture *>, texture, Dynamic);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Uniform::Type::Last:
|
|
Q_UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
|
|
QPointer<QQuick3DCustomMaterial> CustomMaterial::create(QQuick3DNode &parent, const UniformTable &uniforms, const Properties &properties, const Shaders &shaders)
|
|
{
|
|
using namespace QSSGSceneDesc;
|
|
QQuick3DCustomMaterial *ret = nullptr;
|
|
if (scene.root)
|
|
scene.reset();
|
|
|
|
QSSGSceneDesc::Material *material = new Material(Material::RuntimeType::CustomMaterial);
|
|
addNode(scene, *material);
|
|
|
|
// Set uniforms
|
|
for (const auto &uniform : uniforms)
|
|
setUniform(*material, uniform);
|
|
|
|
// Set common properties
|
|
const Properties def;
|
|
if (def.cullMode != properties.cullMode)
|
|
setProperty(*material, "cullMode", &QQuick3DCustomMaterial::setCullMode, properties.cullMode);
|
|
if (def.depthDrawMode != properties.depthDrawMode)
|
|
setProperty(*material, "depthDrawMode", &QQuick3DCustomMaterial::setDepthDrawMode, properties.depthDrawMode);
|
|
if (def.shadingMode != properties.shadingMode)
|
|
setProperty(*material, "shadingMode", &QQuick3DCustomMaterial::setShadingMode, properties.shadingMode);
|
|
if (def.sourceBlend != properties.sourceBlend)
|
|
setProperty(*material, "sourceBlend", &QQuick3DCustomMaterial::setSrcBlend, properties.sourceBlend);
|
|
if (def.destinationBlend != properties.destinationBlend)
|
|
setProperty(*material, "destinationBlend", &QQuick3DCustomMaterial::setDstBlend, properties.destinationBlend);
|
|
|
|
if (!shaders.vert.isEmpty())
|
|
setProperty(*material, "vertexShader", &QQuick3DCustomMaterial::setVertexShader, QUrl{ shaders.vert.toString() });
|
|
if (!shaders.frag.isEmpty())
|
|
setProperty(*material, "fragmentShader", &QQuick3DCustomMaterial::setFragmentShader, QUrl{ shaders.frag.toString() });
|
|
|
|
auto resourceParent = std::make_unique<QQuick3DNode>();
|
|
QSSGRuntimeUtils::createScene(parent, scene);
|
|
if (auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material->obj)) {
|
|
resourceParent.release()->setParent(&parent);
|
|
ret = customMaterial;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool CustomMaterial::isValid() const { return scene.root != nullptr && scene.root->runtimeType == QSSGSceneDesc::Material::RuntimeType::CustomMaterial; }
|
|
|
|
QDataStream &CustomMaterial::readFromDataStream(QDataStream &stream, Uniform &uniform)
|
|
{
|
|
int type;
|
|
stream >> type >> uniform.name;
|
|
uniform.type = Uniform::Type(type);
|
|
switch (uniform.type) {
|
|
case Uniform::Type::Bool:
|
|
stream >> uniform.b;
|
|
break;
|
|
case Uniform::Type::Int:
|
|
stream >> uniform.i;
|
|
break;
|
|
case Uniform::Type::Float:
|
|
stream >> uniform.f;
|
|
break;
|
|
case Uniform::Type::Vec2:
|
|
stream >> uniform.vec2;
|
|
break;
|
|
case Uniform::Type::Vec3:
|
|
stream >> uniform.vec3;
|
|
break;
|
|
case Uniform::Type::Vec4:
|
|
stream >> uniform.vec4;
|
|
break;
|
|
case Uniform::Type::Mat44:
|
|
stream >> uniform.m44;
|
|
break;
|
|
case Uniform::Type::Sampler:
|
|
{
|
|
QImage image;
|
|
stream >> uniform.imagePath >> image;
|
|
s_textureStore->insert(uniform.imagePath, new QImage(image));
|
|
}
|
|
break;
|
|
case Uniform::Type::Last:
|
|
Q_UNREACHABLE();
|
|
break;
|
|
}
|
|
return stream;
|
|
}
|
|
|
|
QDataStream &CustomMaterial::writeToDataStream(QDataStream &stream, const Uniform &uniform)
|
|
{
|
|
stream << int(uniform.type) << uniform.name;
|
|
switch (uniform.type) {
|
|
case Uniform::Type::Bool:
|
|
stream << uniform.b;
|
|
break;
|
|
case Uniform::Type::Int:
|
|
stream << uniform.i;
|
|
break;
|
|
case Uniform::Type::Float:
|
|
stream << uniform.f;
|
|
break;
|
|
case Uniform::Type::Vec2:
|
|
stream << uniform.vec2;
|
|
break;
|
|
case Uniform::Type::Vec3:
|
|
stream << uniform.vec3;
|
|
break;
|
|
case Uniform::Type::Vec4:
|
|
stream << uniform.vec4;
|
|
break;
|
|
case Uniform::Type::Mat44:
|
|
stream << uniform.m44;
|
|
break;
|
|
case Uniform::Type::Sampler:
|
|
{
|
|
const auto &path = uniform.imagePath;
|
|
auto it = s_textureStore->constFind(path);
|
|
const auto end = s_textureStore->cend();
|
|
if (it != end)
|
|
stream << path << *(*it);
|
|
}
|
|
break;
|
|
case Uniform::Type::Last:
|
|
Q_UNREACHABLE();
|
|
break;
|
|
}
|
|
return stream;
|
|
}
|
|
|
|
void CustomMaterial::writeQmlComponent(const QSSGSceneDesc::Material &material, QTextStream &stream)
|
|
{
|
|
QSSGQmlUtilities::writeQmlComponent(material, stream, QDir());
|
|
}
|
|
|
|
QT_END_NAMESPACE
|