add basic Oven QCoreApplication, start to output results

This commit is contained in:
Stephen Birarda 2017-04-05 15:20:19 -07:00
parent 711938fb3d
commit 1b30afa03e
6 changed files with 182 additions and 28 deletions

View file

@ -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})

View file

@ -10,33 +10,117 @@
//
#include <fbxsdk.h>
#include <fbxsdk/scene/shading/fbxlayeredtexture.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QThread>
#include <NetworkAccessManager.h>
#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<QNetworkReply*>(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;
}

View file

@ -12,8 +12,10 @@
#ifndef hifi_FBXBaker_h
#define hifi_FBXBaker_h
#include <QLoggingCategory>
#include <QUrl>
#include <QtCore/QDir>
#include <QtCore/QLoggingCategory>
#include <QtCore/QUrl>
#include <QtNetwork/QNetworkReply>
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 };

23
tools/oven/src/Oven.cpp Normal file
View file

@ -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 <QtCore/QTimer>
#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();
}

30
tools/oven/src/Oven.h Normal file
View file

@ -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 <QtCore/QCoreApplication>
#include <FBXBaker.h>
class Oven : public QCoreApplication {
Q_OBJECT
public:
Oven(int argc, char* argv[]);
private:
FBXBaker _testBake;
};
#endif // hifi_Oven_h

View file

@ -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 <FBXBaker.h>
#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();
}