// // BakeAssetTask.cpp // assignment-client/src/assets // // Created by Stephen Birarda on 9/18/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 "BakeAssetTask.h" #include #include #include #include #include static const int OVEN_STATUS_CODE_SUCCESS { 0 }; static const int OVEN_STATUS_CODE_FAIL { 1 }; static const int OVEN_STATUS_CODE_ABORT { 2 }; BakeAssetTask::BakeAssetTask(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath) : _assetHash(assetHash), _assetPath(assetPath), _filePath(filePath) { qRegisterMetaType("QProcess::ProcessError"); qRegisterMetaType("QProcess::ExitStatus"); } void cleanupTempFiles(QString tempOutputDir, std::vector files) { for (const auto& filename : files) { QFile f { filename }; if (!f.remove()) { qDebug() << "Failed to remove:" << filename; } } if (!tempOutputDir.isEmpty()) { QDir dir { tempOutputDir }; if (!dir.rmdir(".")) { qDebug() << "Failed to remove temporary directory:" << tempOutputDir; } } }; void BakeAssetTask::run() { _isBaking.store(true); QString tempOutputDir = PathUtils::generateTemporaryDir(); _outputDir = tempOutputDir; auto base = QFileInfo(QCoreApplication::applicationFilePath()).absoluteDir(); QString path = base.absolutePath() + "/oven"; QString extension = _assetPath.mid(_assetPath.lastIndexOf('.') + 1); QStringList args { "-i", _filePath, "-o", tempOutputDir, "-t", extension, }; qDebug().noquote() << "Path: " << path << args.join(' '); QProcess* proc = new QProcess(); connect(proc, static_cast(&QProcess::finished), this, [this, proc, tempOutputDir](int exitCode, QProcess::ExitStatus exitStatus) { qDebug() << "Finished process: " << exitCode << exitStatus; qDebug() << "stdout: " << proc->readAllStandardOutput(); auto files = _outputDir.entryInfoList(QDir::Files); QVector outputFiles; for (auto& file : files) { qDebug() << "Output file: " << file.absoluteFilePath(); outputFiles.push_back(file.absoluteFilePath()); } if (exitCode == OVEN_STATUS_CODE_SUCCESS) { _didFinish.store(true); emit bakeComplete(_assetHash, _assetPath, tempOutputDir, outputFiles); } else if (exitCode == OVEN_STATUS_CODE_ABORT) { _wasAborted.store(true); emit bakeAborted(_assetHash, _assetPath); } else { QString errors; if (exitCode == OVEN_STATUS_CODE_FAIL) { _didFinish.store(true); auto errorFilePath = _outputDir.absoluteFilePath("errors.txt"); QFile errorFile { errorFilePath }; if (errorFile.open(QIODevice::ReadOnly)) { errors = errorFile.readAll(); errorFile.close(); } else { errors = "Unknown error occurred"; } } emit bakeFailed(_assetHash, _assetPath, errors); } }); connect(proc, &QProcess::errorOccurred, this, []() { qDebug() << "Error occurred :("; }); connect(proc, &QProcess::started, this, []() { qDebug() << "Process started"; }); proc->start(path, args, QIODevice::ReadOnly); proc->waitForStarted(); proc->waitForFinished(); return; qRegisterMetaType >("QVector"); TextureBakerThreadGetter fn = []() -> QThread* { return QThread::currentThread(); }; if (_assetPath.endsWith(".fbx")) { _baker = std::unique_ptr { new FBXBaker(QUrl("file:///" + _filePath), fn, tempOutputDir) }; } else if (_assetPath.endsWith(".js", Qt::CaseInsensitive)) { _baker = std::unique_ptr{ new JSBaker(QUrl("file:///" + _filePath), tempOutputDir) }; } else { _baker = std::unique_ptr { new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE, tempOutputDir) }; } QEventLoop loop; connect(_baker.get(), &Baker::finished, &loop, &QEventLoop::quit); connect(_baker.get(), &Baker::aborted, &loop, &QEventLoop::quit); QMetaObject::invokeMethod(_baker.get(), "bake", Qt::QueuedConnection); loop.exec(); if (_baker->wasAborted()) { qDebug() << "Aborted baking: " << _assetHash << _assetPath; _wasAborted.store(true); cleanupTempFiles(tempOutputDir, _baker->getOutputFiles()); emit bakeAborted(_assetHash, _assetPath); } else if (_baker->hasErrors()) { qDebug() << "Failed to bake: " << _assetHash << _assetPath << _baker->getErrors(); auto errors = _baker->getErrors().join('\n'); // Join error list into a single string for convenience _didFinish.store(true); cleanupTempFiles(tempOutputDir, _baker->getOutputFiles()); emit bakeFailed(_assetHash, _assetPath, errors); } else { auto vectorOutputFiles = QVector::fromStdVector(_baker->getOutputFiles()); qDebug() << "Finished baking: " << _assetHash << _assetPath << vectorOutputFiles; _didFinish.store(true); emit bakeComplete(_assetHash, _assetPath, tempOutputDir, vectorOutputFiles); } } void BakeAssetTask::abort() { if (_baker) { _baker->abort(); } }