From 1b30afa03ebd72c1b6d33bf821dc8a9acfffc80b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 5 Apr 2017 15:20:19 -0700 Subject: [PATCH] add basic Oven QCoreApplication, start to output results --- libraries/model-baking/CMakeLists.txt | 2 + libraries/model-baking/src/FBXBaker.cpp | 123 +++++++++++++++++++++--- libraries/model-baking/src/FBXBaker.h | 22 ++++- tools/oven/src/Oven.cpp | 23 +++++ tools/oven/src/Oven.h | 30 ++++++ tools/oven/src/main.cpp | 10 +- 6 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 tools/oven/src/Oven.cpp create mode 100644 tools/oven/src/Oven.h diff --git a/libraries/model-baking/CMakeLists.txt b/libraries/model-baking/CMakeLists.txt index 45c0350bbe..487b8536c9 100644 --- a/libraries/model-baking/CMakeLists.txt +++ b/libraries/model-baking/CMakeLists.txt @@ -2,6 +2,8 @@ set(TARGET_NAME model-baking) setup_hifi_library() +link_hifi_libraries(networking) + find_package(FBXSDK REQUIRED) target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES}) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${FBX_INCLUDE_DIR}) diff --git a/libraries/model-baking/src/FBXBaker.cpp b/libraries/model-baking/src/FBXBaker.cpp index 41fa0e1a12..0be4222f59 100644 --- a/libraries/model-baking/src/FBXBaker.cpp +++ b/libraries/model-baking/src/FBXBaker.cpp @@ -10,33 +10,117 @@ // #include -#include +#include #include -#include + +#include #include "FBXBaker.h" Q_LOGGING_CATEGORY(model_baking, "hifi.model-baking"); -FBXBaker::FBXBaker(QUrl fbxPath) : - _fbxPath(fbxPath) +FBXBaker::FBXBaker(QUrl fbxURL, QString baseOutputPath) : + _fbxURL(fbxURL), + _baseOutputPath(baseOutputPath) { // create an FBX SDK manager _sdkManager = FbxManager::Create(); + + // grab the name of the FBX from the URL, this is used for folder output names + auto fileName = fbxURL.fileName(); + _fbxName = fileName.left(fileName.indexOf('.')); } FBXBaker::~FBXBaker() { _sdkManager->Destroy(); } + void FBXBaker::start() { + // setup the output folder for the results of this bake + if (!setupOutputFolder()) { + return; + } + // check if the FBX is local or first needs to be downloaded - if (_fbxPath.isLocalFile()) { - // local file, bake now + if (_fbxURL.isLocalFile()) { + // load up the local file + QFile localFBX { _fbxURL.toLocalFile() }; + + // make a copy in the output folder + localFBX.copy(_uniqueOutputPath + _fbxURL.fileName()); + + // start the bake now that we have everything in place bake(); } else { // remote file, kick off a download + auto& networkAccessManager = NetworkAccessManager::getInstance(); + + QNetworkRequest networkRequest; + + // setup the request to follow re-directs and always hit the network + networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + + networkRequest.setUrl(_fbxURL); + + qCDebug(model_baking) << "Downloading" << _fbxURL; + + auto networkReply = networkAccessManager.get(networkRequest); + connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply); + } +} + +bool FBXBaker::setupOutputFolder() { + // construct the output path using the name of the fbx and the base output path + _uniqueOutputPath = _baseOutputPath + "/" + _fbxName + "/"; + + // make sure there isn't already an output directory using the same name + int iteration = 0; + + while (QDir(_uniqueOutputPath).exists()) { + _uniqueOutputPath = _baseOutputPath + "/" + _fbxName + "-" + QString::number(++iteration) + "/"; + } + + qCDebug(model_baking) << "Creating FBX output folder" << _uniqueOutputPath; + + // attempt to make the output folder + if (!QDir().mkdir(_uniqueOutputPath)) { + qCWarning(model_baking) << "Failed to created FBX output folder" << _uniqueOutputPath; + + emit finished(); + return false; + } + + return true; +} + +void FBXBaker::handleFBXNetworkReply() { + QNetworkReply* requestReply = qobject_cast(sender()); + + if (requestReply->error() == QNetworkReply::NoError) { + qCDebug(model_baking) << "Downloaded" << _fbxURL; + + // grab the contents of the reply and make a copy in the output folder + QFile copyOfOriginal(_uniqueOutputPath + _fbxURL.fileName()); + + qDebug(model_baking) << "Writing copy of original FBX to" << copyOfOriginal.fileName(); + + if (!copyOfOriginal.open(QIODevice::WriteOnly) || (copyOfOriginal.write(requestReply->readAll()) == -1)) { + + // add an error to the error list for this FBX stating that a duplicate of the original could not be made + emit finished(); + return; + } + + // close that file now that we are done writing to it + copyOfOriginal.close(); + + // kick off the bake process now that everything is ready to go + bake(); + } else { + qDebug() << "ERROR DOWNLOADING FBX" << requestReply->errorString(); } } @@ -46,25 +130,31 @@ void FBXBaker::bake() { // (3) export the FBX with re-written texture references // (4) enumerate the collected texture paths and bake the textures + qCDebug(model_baking) << "Baking" << _fbxURL; + // a failure at any step along the way stops the chain importScene() && rewriteAndCollectSceneTextures() && exportScene() && bakeTextures(); // emit a signal saying that we are done, with whatever errors were produced - emit finished(_errorList); + emit finished(); } bool FBXBaker::importScene() { // create an FBX SDK importer FbxImporter* importer = FbxImporter::Create(_sdkManager, ""); - // import the FBX file at the given path - bool importStatus = importer->Initialize(_fbxPath.toLocalFile().toLocal8Bit().data()); + // import the copy of the original FBX file + QString originalCopyPath = _uniqueOutputPath + _fbxURL.fileName(); + bool importStatus = importer->Initialize(originalCopyPath.toLocal8Bit().data()); if (!importStatus) { // failed to initialize importer, print an error and return - qCDebug(model_baking) << "Failed to import FBX file at" << _fbxPath << "- error:" << importer->GetStatus().GetErrorString(); + qCCritical(model_baking) << "Failed to import FBX file at" << _fbxURL + << "- error:" << importer->GetStatus().GetErrorString(); return false; + } else { + qCDebug(model_baking) << "Imported" << _fbxURL << "to FbxScene"; } // setup a new scene to hold the imported file @@ -82,8 +172,6 @@ bool FBXBaker::importScene() { static const QString BAKED_TEXTURE_DIRECTORY = "textures"; static const QString BAKED_TEXTURE_EXT = ".ktx"; -static const QString EXPORT_PATH { "/Users/birarda/code/hifi/lod/test-oven/export/DiscGolfBasket.ktx.fbx" }; - bool FBXBaker::rewriteAndCollectSceneTextures() { // get a count of the textures used in the scene int numTextures = _scene->GetTextureCount(); @@ -102,7 +190,7 @@ bool FBXBaker::rewriteAndCollectSceneTextures() { // construct the new baked texture file name and file path QString bakedTextureFileName { textureFileInfo.baseName() + BAKED_TEXTURE_EXT }; - QString bakedTextureFilePath { QFileInfo(EXPORT_PATH).absolutePath() + "/textures/" + bakedTextureFileName }; + QString bakedTextureFilePath { _uniqueOutputPath + "ktx/" + bakedTextureFileName }; qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName() << "to" << bakedTextureFilePath; @@ -127,12 +215,13 @@ bool FBXBaker::exportScene() { // setup the exporter FbxExporter* exporter = FbxExporter::Create(_sdkManager, ""); - bool exportStatus = exporter->Initialize(EXPORT_PATH.toLocal8Bit().data()); + auto rewrittenFBXPath = _uniqueOutputPath + _fbxName + ".ktx.fbx"; + bool exportStatus = exporter->Initialize(rewrittenFBXPath.toLocal8Bit().data()); if (!exportStatus) { // failed to initialize exporter, print an error and return - qCDebug(model_baking) << "Failed to export FBX file at" << _fbxPath - << "to" << EXPORT_PATH << "- error:" << exporter->GetStatus().GetErrorString(); + qCCritical(model_baking) << "Failed to export FBX file at" << _fbxURL + << "to" << rewrittenFBXPath << "- error:" << exporter->GetStatus().GetErrorString(); return false; } @@ -140,6 +229,8 @@ bool FBXBaker::exportScene() { // export the scene exporter->Export(_scene); + qCDebug(model_baking) << "Exported" << _fbxURL << "with re-written paths to" << rewrittenFBXPath; + return true; } diff --git a/libraries/model-baking/src/FBXBaker.h b/libraries/model-baking/src/FBXBaker.h index 0ae8311522..3bd721253f 100644 --- a/libraries/model-baking/src/FBXBaker.h +++ b/libraries/model-baking/src/FBXBaker.h @@ -12,8 +12,10 @@ #ifndef hifi_FBXBaker_h #define hifi_FBXBaker_h -#include -#include +#include +#include +#include +#include Q_DECLARE_LOGGING_CATEGORY(model_baking) @@ -27,23 +29,33 @@ namespace fbxsdk { class FBXBaker : public QObject { Q_OBJECT public: - FBXBaker(QUrl fbxPath); + FBXBaker(QUrl fbxURL, QString baseOutputPath); ~FBXBaker(); void start(); signals: - void finished(QStringList errorList); + void finished(); +private slots: + void handleFBXNetworkReply(); + private: void bake(); + + bool setupOutputFolder(); bool importScene(); bool rewriteAndCollectSceneTextures(); bool exportScene(); bool bakeTextures(); bool bakeTexture(); - QUrl _fbxPath; + QUrl _fbxURL; + QString _fbxName; + + QString _baseOutputPath; + QString _uniqueOutputPath; + fbxsdk::FbxManager* _sdkManager; fbxsdk::FbxScene* _scene { nullptr }; diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp new file mode 100644 index 0000000000..b517da8151 --- /dev/null +++ b/tools/oven/src/Oven.cpp @@ -0,0 +1,23 @@ +// +// Oven.cpp +// tools/oven/src +// +// Created by Stephen Birarda on 4/5/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "Oven.h" + +static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; + +Oven::Oven(int argc, char* argv[]) : + QCoreApplication(argc, argv), + _testBake(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/DiscGolfBasket.fbx"), OUTPUT_FOLDER) +{ + _testBake.start(); +} diff --git a/tools/oven/src/Oven.h b/tools/oven/src/Oven.h new file mode 100644 index 0000000000..72de77b889 --- /dev/null +++ b/tools/oven/src/Oven.h @@ -0,0 +1,30 @@ +// +// Oven.h +// tools/oven/src +// +// Created by Stephen Birarda on 4/5/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Oven_h +#define hifi_Oven_h + +#include + +#include + +class Oven : public QCoreApplication { + Q_OBJECT + +public: + Oven(int argc, char* argv[]); + +private: + FBXBaker _testBake; +}; + + +#endif // hifi_Oven_h diff --git a/tools/oven/src/main.cpp b/tools/oven/src/main.cpp index e74df068dd..9c778245b5 100644 --- a/tools/oven/src/main.cpp +++ b/tools/oven/src/main.cpp @@ -8,13 +8,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#include - +#include "Oven.h" int main (int argc, char** argv) { - - FBXBaker baker(QUrl("file:///Users/birarda/code/hifi/lod/test-oven/DiscGolfBasket.fbx")); - baker.start(); - - return 0; + Oven app(argc, argv); + return app.exec(); }