diff --git a/KomplexHubPlugin/common/shaderpackmetadata.h b/KomplexHubPlugin/common/shaderpackmetadata.h index e51ce67..6ae2711 100644 --- a/KomplexHubPlugin/common/shaderpackmetadata.h +++ b/KomplexHubPlugin/common/shaderpackmetadata.h @@ -18,7 +18,378 @@ #include "komplex_global.h" -class KOMPLEX_EXPORT ShaderPackMetadata : public QObject +class KOMPLEX_EXPORT ShaderPackChannel : public QObject +{ + Q_OBJECT + QML_ELEMENT + +public: + enum Type + { + Image, + Video, + Shader, + Cubemap, + Audio, + Scene, + Model + }; + Q_ENUM(Type) + + enum MirrorMode + { + MirrorVertical, + MirrorHorizontal, + NoMirror + }; + Q_ENUM(MirrorMode) + + enum Format + { + RGB8A, + RGB16F, + RGB32F + }; + Q_ENUM(Format) + + enum TextureRepeat + { + ClampToEdge, + RepeatVertically, + RepeatHorizontally, + Repeat + }; + Q_ENUM(TextureRepeat) + + inline auto source() const -> QString { return m_source; } + inline auto setSource(const QString &source) -> void + { + if(source == this->source()) + { + return; + } + + m_source = source; + Q_EMIT sourceChanged(); + } + + inline auto type() const -> Type { return m_type; } + inline auto setType(Type type) -> void + { + if(type == this->type()) + { + return; + } + + m_type = type; + Q_EMIT typeChanged(); + } + + inline auto mirrorMode() const -> MirrorMode { return m_mirrorMode; } + inline auto setMirrorMode(MirrorMode mode) + { + if(mirrorMode() == mode) + { + return; + } + + m_mirrorMode = mode; + Q_EMIT mirrorModeChanged(); + } + + inline auto textureRepeat() const -> TextureRepeat { return m_textureRepeat; } + inline auto setTextureRepeat(TextureRepeat mode) -> void + { + if(textureRepeat() == mode) + { + return; + } + + m_textureRepeat = mode; + Q_EMIT textureRepeatChanged(); + } + + inline auto resolutionY() const -> qsizetype { return m_resolutionY; } + inline auto setResolutionY(qsizetype resolution) + { + if(resolutionY() == resolution) + { + return; + } + + m_resolutionY = resolution; + Q_EMIT resolutionYChanged(); + } + + inline auto resolutionX() const -> qsizetype { return m_resolutionX; } + inline auto setResolutionX(qsizetype resolution) + { + if(resolutionX() == resolution) + { + return; + } + + m_resolutionX = resolution; + Q_EMIT resolutionXChanged(); + } + + inline auto resolutionScale() const -> qreal { return m_resolutionScale; } + inline auto setResolutionScale(qreal scale) + { + if(qFuzzyCompare(resolutionScale(), scale)) + { + return; + } + + m_resolutionScale = scale; + Q_EMIT resolutionScaledChanged(); + } + + inline auto speed() const -> qreal { return m_speed; } + inline auto setSpeed(qreal speed) + { + if(qFuzzyCompare(this->speed(), speed)) + { + return; + } + + m_speed = speed; + Q_EMIT speedChanged(); + } + + inline auto mouseSpeedBias() const -> qreal { return m_mouseSpeedBias; } + inline auto setMouseSpeedBias(qreal bias) + { + if(qFuzzyCompare(mouseSpeedBias(), bias)) + { + return; + } + + m_mouseSpeedBias = bias; + Q_EMIT mouseSpeedBiasChanged(); + } + + inline auto bufferA() const -> ShaderPackChannel* { return m_bufferA; } + inline auto setBufferA(ShaderPackChannel *buffer) -> void + { + if (m_bufferA == buffer) + { + return; + } + + m_bufferA = buffer; + Q_EMIT bufferAChanged(); + } + + inline auto bufferB() const -> ShaderPackChannel* { return m_bufferB; } + inline auto setBufferB(ShaderPackChannel *buffer) -> void + { + if (m_bufferB == buffer) + { + return; + } + + m_bufferB = buffer; + Q_EMIT bufferBChanged(); + } + + inline auto bufferC() const -> ShaderPackChannel* { return m_bufferC; } + inline auto setBufferC(ShaderPackChannel *buffer) -> void + { + if (m_bufferC == buffer) + { + return; + } + + m_bufferC = buffer; + Q_EMIT bufferCChanged(); + } + + inline auto bufferD() const -> ShaderPackChannel* { return m_bufferD; } + inline auto setBufferD(ShaderPackChannel *buffer) -> void + { + if (m_bufferD == buffer) + { + return; + } + + m_bufferD = buffer; + Q_EMIT bufferDChanged(); + } + + inline auto channel0() const -> ShaderPackChannel* { return m_channel0; } + inline auto setChannel0(ShaderPackChannel *channel) -> void + { + if (m_channel0 == channel) + { + return; + } + + m_channel0 = channel; + Q_EMIT channel0Changed(); + } + + inline auto channel1() const -> ShaderPackChannel* { return m_channel1; } + inline auto setChannel1(ShaderPackChannel *channel) -> void + { + if (m_channel1 == channel) + { + return; + } + + m_channel1 = channel; + Q_EMIT channel1Changed(); + } + + inline auto channel2() const -> ShaderPackChannel* { return m_channel2; } + inline auto setChannel2(ShaderPackChannel *channel) -> void + { + if (m_channel2 == channel) + { + return; + } + + m_channel2 = channel; + Q_EMIT channel2Changed(); + } + + inline auto channel3() const -> ShaderPackChannel* { return m_channel3; } + inline auto setChannel3(ShaderPackChannel *channel) -> void + { + if (m_channel3 == channel) + { + return; + } + + m_channel3 = channel; + Q_EMIT channel3Changed(); + } + + inline auto frameBufferChannel() const -> qint8 { return m_frameBufferChannel; }; + inline auto setFrameBufferChannel(qint8 frameBufferChannel) -> void + { + if (m_frameBufferChannel == frameBufferChannel) + { + return; + } + + m_frameBufferChannel = frameBufferChannel; + Q_EMIT frameBufferChannelChanged(); + } + + inline auto invert() const -> bool { return m_invert; } + inline auto setInvert(bool invert) -> void + { + if (m_invert == invert) + { + return; + } + + m_invert = invert; + emit invertChanged(); + } + + inline auto mipmap() const -> bool { return m_mipmap; } + inline auto setMipmap(bool on) + { + if(on == mipmap()) + { + return; + } + + m_mipmap = on; + Q_EMIT mipmapChanged(); + } + + inline auto format() const -> Format { return m_format; } + inline auto setFormat(Format format) + { + if(this->format() == format) + { + return; + } + + m_format = format; + Q_EMIT formatChanged(); + } + +Q_SIGNALS: + auto sourceChanged() -> void; + auto typeChanged() -> void; + auto mirrorModeChanged() -> void; + auto textureRepeatChanged() -> void; + auto resolutionXChanged() -> void; + auto resolutionYChanged() -> void; + auto resolutionScaledChanged() -> void; + auto speedChanged() -> void; + auto mouseSpeedBiasChanged() -> void; + auto bufferAChanged() -> void; + auto bufferBChanged() -> void; + auto bufferCChanged() -> void; + auto bufferDChanged() -> void; + auto channel0Changed() -> void; + auto channel1Changed() -> void; + auto channel2Changed() -> void; + auto channel3Changed() -> void; + auto resolutionScaleChanged() -> void; + auto frameBufferChannelChanged() -> void; + auto invertChanged() -> void; + auto mipmapChanged() -> void; + auto formatChanged() -> void; + +private: + ShaderPackChannel *m_bufferA = nullptr; + ShaderPackChannel *m_bufferB = nullptr; + ShaderPackChannel *m_bufferC = nullptr; + ShaderPackChannel *m_bufferD = nullptr; + + ShaderPackChannel *m_channel0 = nullptr; + ShaderPackChannel *m_channel1 = nullptr; + ShaderPackChannel *m_channel2 = nullptr; + ShaderPackChannel *m_channel3 = nullptr; + + QString m_source; + Type m_type = Image; + MirrorMode m_mirrorMode = MirrorVertical; + TextureRepeat m_textureRepeat = ClampToEdge; + Format m_format = RGB8A; + + qsizetype m_resolutionX = 0; + qsizetype m_resolutionY = 0; + qreal m_resolutionScale = 1.0; + qreal m_speed = 1.0; + qreal m_mouseSpeedBias = 1.0; + + qint8 m_frameBufferChannel = -1; + bool m_invert = false; + bool m_mipmap = false; + + Q_PROPERTY(ShaderPackChannel *bufferA READ bufferA WRITE setBufferA NOTIFY bufferAChanged FINAL) + Q_PROPERTY(ShaderPackChannel *bufferB READ bufferB WRITE setBufferB NOTIFY bufferBChanged FINAL) + Q_PROPERTY(ShaderPackChannel *bufferC READ bufferC WRITE setBufferC NOTIFY bufferCChanged FINAL) + Q_PROPERTY(ShaderPackChannel *bufferD READ bufferD WRITE setBufferD NOTIFY bufferDChanged FINAL) + Q_PROPERTY(ShaderPackChannel *channel0 READ channel0 WRITE setChannel0 NOTIFY channel0Changed FINAL) + Q_PROPERTY(ShaderPackChannel *channel1 READ channel1 WRITE setChannel1 NOTIFY channel1Changed FINAL) + Q_PROPERTY(ShaderPackChannel *channel2 READ channel2 WRITE setChannel2 NOTIFY channel2Changed FINAL) + Q_PROPERTY(ShaderPackChannel *channel3 READ channel3 WRITE setChannel3 NOTIFY channel3Changed FINAL) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged FINAL) + Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged FINAL) + Q_PROPERTY(MirrorMode mirrorMode READ mirrorMode WRITE setMirrorMode NOTIFY mirrorModeChanged FINAL) + Q_PROPERTY(TextureRepeat textureRepeat READ textureRepeat WRITE setTextureRepeat NOTIFY textureRepeatChanged FINAL) + Q_PROPERTY(qsizetype resolutionX READ resolutionX WRITE setResolutionX NOTIFY resolutionXChanged FINAL) + Q_PROPERTY(qsizetype resolutionY READ resolutionY WRITE setResolutionY NOTIFY resolutionYChanged FINAL) + Q_PROPERTY(qreal resolutionScale READ resolutionScale WRITE setResolutionScale NOTIFY resolutionScaleChanged FINAL) + Q_PROPERTY(qreal speed READ speed WRITE setSpeed NOTIFY speedChanged FINAL) + Q_PROPERTY(qreal mouseSpeedBias READ mouseSpeedBias WRITE setMouseSpeedBias NOTIFY mouseSpeedBiasChanged FINAL) + Q_PROPERTY(qint8 frameBufferChannel READ frameBufferChannel WRITE setFrameBufferChannel NOTIFY frameBufferChannelChanged FINAL) + Q_PROPERTY(bool invert READ invert WRITE setInvert NOTIFY invertChanged FINAL) + Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged FINAL) + Q_PROPERTY(Format format READ format WRITE setFormat NOTIFY formatChanged FINAL) +}; + +Q_DECLARE_METATYPE(ShaderPackChannel) + +class KOMPLEX_EXPORT ShaderPackMetadata : public ShaderPackChannel { Q_OBJECT QML_ELEMENT @@ -132,6 +503,110 @@ public: Q_EMIT versionChanged(); } } + + auto json() -> QJsonDocument + { + QJsonObject rootObject; + + rootObject[QStringLiteral("author")] = author(); + rootObject[QStringLiteral("version")] = version(); + rootObject[QStringLiteral("name")] = name(); + rootObject[QStringLiteral("id")] = id(); + rootObject[QStringLiteral("engine")] = engine(); + rootObject[QStringLiteral("license")] = license(); + + QJsonObject bufferObject = bufferJson(this); + QJsonObject channelObject = channelJson(this); + + const QStringList bufferKeys = bufferObject.keys(); + for(const QString &key : bufferKeys) + { + rootObject[key] = bufferObject[key]; + } + + const QStringList channelKeys = channelObject.keys(); + for(const QString &key : channelKeys) + { + rootObject[key] = channelObject[key]; + } + + return QJsonDocument + { + rootObject + }; + } + +private: + + auto bufferJson(ShaderPackChannel *channel) -> QJsonObject + { + QJsonObject channelObject; + + if(channel->bufferA()) + { + channelObject[QStringLiteral("bufferA")] = channelJson(channel->bufferA()); + } + if(channel->bufferB()) + { + channelObject[QStringLiteral("bufferB")] = channelJson(channel->bufferB()); + } + if(channel->bufferC()) + { + channelObject[QStringLiteral("bufferC")] = channelJson(channel->bufferC()); + } + if(channel->bufferD()) + { + channelObject[QStringLiteral("bufferD")] = channelJson(channel->bufferD()); + } + + return channelObject; + } + + auto channelJson(ShaderPackChannel *channel) -> QJsonObject + { + if(channel == nullptr) + { + return {}; + } + + QJsonObject channelObject; + + if(channel->channel0() != nullptr) + { + channelObject[QStringLiteral("channel0")] = channelJson(channel->channel0()); + } + + if(channel->channel1() != nullptr) + { + channelObject[QStringLiteral("channel1")] = channelJson(channel->channel1()); + } + + if(channel->channel2() != nullptr) + { + channelObject[QStringLiteral("channel2")] = channelJson(channel->channel2()); + } + + if(channel->channel3() != nullptr) + { + channelObject[QStringLiteral("channel3")] = channelJson(channel->channel3()); + } + + channelObject[QStringLiteral("source")] = channel->source(); + channelObject[QStringLiteral("type")] = channel->type(); + channelObject[QStringLiteral("texture_mirroring")] = channel->mirrorMode(); + channelObject[QStringLiteral("wrap_mode")] = channel->textureRepeat(); + channelObject[QStringLiteral("invert")] = channel->invert(); + channelObject[QStringLiteral("time_scale")] = channel->speed(); + channelObject[QStringLiteral("resolution_scale")] = channel->resolutionScale(); + channelObject[QStringLiteral("mouse_scale")] = channel->mouseSpeedBias(); + channelObject[QStringLiteral("resolution_x")] = channel->resolutionX(); + channelObject[QStringLiteral("resolution_y")] = channel->resolutionY(); + channelObject[QStringLiteral("frame_buffer_channel")] = channel->frameBufferChannel(); + channelObject[QStringLiteral("format")] = channel->format(); + channelObject[QStringLiteral("mipmap")] = channel->mipmap(); + + return channelObject; + } }; Q_DECLARE_METATYPE(ShaderPackMetadata) diff --git a/KomplexHubPlugin/downloadmanager.cpp b/KomplexHubPlugin/downloadmanager.cpp index 14007aa..a093a9a 100644 --- a/KomplexHubPlugin/downloadmanager.cpp +++ b/KomplexHubPlugin/downloadmanager.cpp @@ -50,42 +50,189 @@ auto DownloadManager::downloadImage(const QString &author, const QString &author QUrl localUri; QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces); - try - { - QFuture downloadUri = download(request, id); + QFuture downloadUri = download(request, id); - downloadUri - .then - ( - [this, author, description, id](QUrl result) -> QUrl + downloadUri + .then + ( + [this, author, description, id](QUrl result) -> QUrl + { + ShaderPackMetadata metadata; + metadata.setAuthor(author); + metadata.setDescription(description); + metadata.setName(QStringLiteral("Pexels Image (%1)").arg(id)); + + QUrl packUri + ( + QStringLiteral("%1/%2").arg + ( + QStandardPaths::writableLocation(QStandardPaths::TempLocation), + id + ) + ); + + QUrl packImageUri + ( + QStringLiteral("%1/%2/images/%3").arg + ( + QStandardPaths::writableLocation(QStandardPaths::TempLocation), + id, + result.fileName() + ) + ); + + QDir packDirectory(packUri.toLocalFile()); + packDirectory.mkpath(packUri.toLocalFile()); + packDirectory.mkdir(QStringLiteral("images")); + + QFile::rename(result.toLocalFile(), packImageUri.toLocalFile()); + + QFile packFile + ( + packDirectory.absoluteFilePath + ( + QStringLiteral("pack.json") + ) + ); + + if(!packFile.open(QFile::ReadWrite)) { - ShaderPackMetadata metadata; - metadata.setAuthor(author); - metadata.setDescription(description); - metadata.setName(QStringLiteral("Pexels Image (%1)").arg(id)); - - setState(Complete); - Q_EMIT downloadComplete(result.toString()); + setError(QStringLiteral("File Error"), packFile.errorString()); + throw FileException(packFile.errorString()); } - ) - .onFailed - ( - [] () + + QByteArray data = metadata.json().toJson(QJsonDocument::Compact); + + if(packFile.write(data) != data.length()) { - + setError(QStringLiteral("File Error"), packFile.errorString()); + throw FileException(packFile.errorString()); } - ); - } - catch (FileException e) - { - setError(QStringLiteral("File Exception"), e.message); - localUri.clear(); - } - catch (NetworkException e) - { - setError(QStringLiteral("Network Exception"), e.message); - localUri.clear(); - } + + packFile.close(); + + return packUri; + } + ) + .then + ( + [this](QUrl result) + { + install(result); + } + ) + .onCanceled + ( + [this]() + { + reset(); + } + ) + .onFailed + ( + [this] () + { + reset(); + } + ); + } + ); +} + +auto DownloadManager::downloadVideo(const QString &author, const QString &authorId, const QString &description, const QUrl &url) noexcept(false) -> void +{ + QFuture future = QtConcurrent::run + ( + [this, url, author, authorId, description]() + { + QNetworkRequest request(url); + QString id = QUuid::createUuidV7().toString(QUuid::WithoutBraces); + + QFuture downloadUri = download(request, id); + + downloadUri + .then + ( + [this, author, description, id](QUrl result) -> QUrl + { + ShaderPackMetadata metadata; + metadata.setAuthor(author); + metadata.setDescription(description); + metadata.setName(QStringLiteral("Pexels Video (%1)").arg(id)); + + QUrl packUri + ( + QStringLiteral("%1/%2").arg + ( + QStandardPaths::writableLocation(QStandardPaths::TempLocation), + id + ) + ); + + QUrl packImageUri + ( + QStringLiteral("%1/%2/images/%3").arg + ( + QStandardPaths::writableLocation(QStandardPaths::TempLocation), + id, + result.fileName() + ) + ); + + QDir packDirectory(packUri.toLocalFile()); + packDirectory.mkpath(packUri.toLocalFile()); + packDirectory.mkdir(QStringLiteral("images")); + + QFile::rename(result.toLocalFile(), packImageUri.toLocalFile()); + + QFile packFile + ( + packDirectory.absoluteFilePath + ( + QStringLiteral("pack.json") + ) + ); + + if(!packFile.open(QFile::ReadWrite)) + { + setError(QStringLiteral("File Error"), packFile.errorString()); + throw FileException(packFile.errorString()); + } + + QByteArray data = metadata.json().toJson(QJsonDocument::Compact); + + if(packFile.write(data) != data.length()) + { + setError(QStringLiteral("File Error"), packFile.errorString()); + throw FileException(packFile.errorString()); + } + + packFile.close(); + + return packUri; + } + ) + .then + ( + [this](QUrl result) + { + install(result); + } + ) + .onCanceled + ( + [this]() + { + reset(); + } + ) + .onFailed + ( + [this] () + { + reset(); + } + ); } ); } @@ -108,21 +255,20 @@ auto DownloadManager::downloadPack(const QString &id) noexcept(false) -> void QNetworkRequest request(downloadUrl); request.setRawHeader(QByteArray("uuid"), id.toUtf8()); - //QUrl localUri = download(request, id, Post); - QFuture compiledUri = download(request, id, Post); + QFuture downloadUri = download(request, id, Post); - compiledUri + downloadUri .then ( [this](QUrl result) -> QUrl { - m_compiler->process(result); + return m_compiler->process(result).result(); } ) .then ( - [this](QUrl result) -> QUrl + [this](QUrl result) { install(result); } @@ -131,8 +277,16 @@ auto DownloadManager::downloadPack(const QString &id) noexcept(false) -> void ( [this]() { + reset(); setError(m_compiler->errorTitle(), m_compiler->errorMessage()); } + ) + .onCanceled + ( + [this]() + { + reset(); + } ); } ); diff --git a/KomplexHubPlugin/downloadmanager.h b/KomplexHubPlugin/downloadmanager.h index aa64aa3..2fd5fa4 100644 --- a/KomplexHubPlugin/downloadmanager.h +++ b/KomplexHubPlugin/downloadmanager.h @@ -50,6 +50,7 @@ public: * @param url */ auto downloadImage(const QString &author, const QString &authorId, const QString &description, const QUrl &url) noexcept(false) -> void; + auto downloadVideo(const QString &author, const QString &authorId, const QString &description, const QUrl &url) noexcept(false) -> void; /** * @brief downloadPack