mirror of
https://github.com/lubosz/overte.git
synced 2025-04-15 11:29:18 +02:00
Add FSTBaker, and make ModelBaker output an FST
Restore feature to look for baked model file in other oven directory
This commit is contained in:
parent
1576125c42
commit
efc9f993f5
12 changed files with 301 additions and 48 deletions
|
@ -52,7 +52,7 @@ protected:
|
|||
void handleErrors(const QStringList& errors);
|
||||
|
||||
// List of baked output files. For instance, for an FBX this would
|
||||
// include the .fbx and all of its texture files.
|
||||
// include the .fbx, a .fst pointing to the fbx, and all of the fbx texture files.
|
||||
std::vector<QString> _outputFiles;
|
||||
|
||||
QStringList _errorList;
|
||||
|
|
|
@ -37,6 +37,17 @@
|
|||
#include "FBXToJSON.h"
|
||||
#endif
|
||||
|
||||
FBXBaker::FBXBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory, bool hasBeenBaked) :
|
||||
ModelBaker(inputModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory, hasBeenBaked) {
|
||||
if (hasBeenBaked) {
|
||||
// Look for the original model file one directory higher. Perhaps this is an oven output directory.
|
||||
QUrl originalRelativePath = QUrl("../original/" + inputModelURL.fileName().replace(BAKED_FBX_EXTENSION, FBX_EXTENSION));
|
||||
QUrl newInputModelURL = inputModelURL.adjusted(QUrl::RemoveFilename).resolved(originalRelativePath);
|
||||
_modelURL = newInputModelURL;
|
||||
}
|
||||
}
|
||||
|
||||
void FBXBaker::bakeProcessedSource(const hfm::Model::Pointer& hfmModel, const std::vector<hifi::ByteArray>& dracoMeshes, const std::vector<std::vector<hifi::ByteArray>>& dracoMaterialLists) {
|
||||
_hfmModel = hfmModel;
|
||||
// Load the root node from the FBX file
|
||||
|
|
|
@ -31,7 +31,8 @@ using TextureBakerThreadGetter = std::function<QThread*()>;
|
|||
class FBXBaker : public ModelBaker {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using ModelBaker::ModelBaker;
|
||||
FBXBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "", bool hasBeenBaked = false);
|
||||
|
||||
protected:
|
||||
virtual void bakeProcessedSource(const hfm::Model::Pointer& hfmModel, const std::vector<hifi::ByteArray>& dracoMeshes, const std::vector<std::vector<hifi::ByteArray>>& dracoMaterialLists) override;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <model-baker/PrepareJointsTask.h>
|
||||
|
||||
#include <FBXWriter.h>
|
||||
#include <FSTReader.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( push )
|
||||
|
@ -61,12 +62,20 @@ ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter input
|
|||
qDebug() << "Made temporary dir " << _modelTempDir;
|
||||
qDebug() << "Origin file path: " << _originalModelFilePath;
|
||||
|
||||
{
|
||||
auto bakedFilename = _modelURL.fileName();
|
||||
if (!hasBeenBaked) {
|
||||
bakedFilename = bakedFilename.left(bakedFilename.lastIndexOf('.'));
|
||||
bakedFilename += BAKED_FBX_EXTENSION;
|
||||
}
|
||||
_bakedModelURL = _bakedOutputDir + "/" + bakedFilename;
|
||||
}
|
||||
}
|
||||
|
||||
ModelBaker::~ModelBaker() {
|
||||
if (_modelTempDir.exists()) {
|
||||
if (!_modelTempDir.remove(_originalModelFilePath)) {
|
||||
qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalModelFilePath;
|
||||
qCWarning(model_baking) << "Failed to remove temporary copy of model file:" << _originalModelFilePath;
|
||||
}
|
||||
if (!_modelTempDir.rmdir(".")) {
|
||||
qCWarning(model_baking) << "Failed to remove temporary directory:" << _modelTempDir;
|
||||
|
@ -74,6 +83,26 @@ ModelBaker::~ModelBaker() {
|
|||
}
|
||||
}
|
||||
|
||||
void ModelBaker::setOutputURLSuffix(const QUrl& outputURLSuffix) {
|
||||
_outputURLSuffix = outputURLSuffix;
|
||||
}
|
||||
|
||||
void ModelBaker::setMappingURL(const QUrl& mappingURL) {
|
||||
_mappingURL = mappingURL;
|
||||
}
|
||||
|
||||
void ModelBaker::setMapping(const hifi::VariantHash& mapping) {
|
||||
_mapping = mapping;
|
||||
}
|
||||
|
||||
QUrl ModelBaker::getFullOutputMappingURL() const {
|
||||
QUrl appendedURL = _outputMappingURL;
|
||||
appendedURL.setFragment(_outputURLSuffix.fragment());
|
||||
appendedURL.setQuery(_outputURLSuffix.query());
|
||||
appendedURL.setUserInfo(_outputURLSuffix.userInfo());
|
||||
return appendedURL;
|
||||
}
|
||||
|
||||
void ModelBaker::bake() {
|
||||
qDebug() << "ModelBaker" << _modelURL << "bake starting";
|
||||
|
||||
|
@ -92,19 +121,24 @@ void ModelBaker::bake() {
|
|||
|
||||
void ModelBaker::initializeOutputDirs() {
|
||||
// Attempt to make the output folders
|
||||
// Warn if there is an output directory using the same name
|
||||
// Warn if there is an output directory using the same name, unless we know a parent FST baker created them already
|
||||
|
||||
if (QDir(_bakedOutputDir).exists()) {
|
||||
qWarning() << "Output path" << _bakedOutputDir << "already exists. Continuing.";
|
||||
if (_mappingURL.isEmpty()) {
|
||||
qWarning() << "Output path" << _bakedOutputDir << "already exists. Continuing.";
|
||||
}
|
||||
} else {
|
||||
qCDebug(model_baking) << "Creating baked output folder" << _bakedOutputDir;
|
||||
if (!QDir().mkpath(_bakedOutputDir)) {
|
||||
handleError("Failed to create baked output folder " + _bakedOutputDir);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (QDir(_originalOutputDir).exists()) {
|
||||
qWarning() << "Output path" << _originalOutputDir << "already exists. Continuing.";
|
||||
if (_mappingURL.isEmpty()) {
|
||||
qWarning() << "Output path" << _originalOutputDir << "already exists. Continuing.";
|
||||
}
|
||||
} else {
|
||||
qCDebug(model_baking) << "Creating original output folder" << _originalOutputDir;
|
||||
if (!QDir().mkpath(_originalOutputDir)) {
|
||||
|
@ -122,7 +156,7 @@ void ModelBaker::saveSourceModel() {
|
|||
qDebug() << "Local file url: " << _modelURL << _modelURL.toString() << _modelURL.toLocalFile() << ", copying to: " << _originalModelFilePath;
|
||||
|
||||
if (!localModelURL.exists()) {
|
||||
//QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), "");
|
||||
//QMessageBox::warning(this, "Could not find " + _modelURL.toString(), "");
|
||||
handleError("Could not find " + _modelURL.toString());
|
||||
return;
|
||||
}
|
||||
|
@ -135,7 +169,7 @@ void ModelBaker::saveSourceModel() {
|
|||
|
||||
localModelURL.copy(_originalModelFilePath);
|
||||
|
||||
// emit our signal to start the import of the FBX source copy
|
||||
// emit our signal to start the import of the model source copy
|
||||
emit modelLoaded();
|
||||
} else {
|
||||
// remote file, kick off a download
|
||||
|
@ -214,11 +248,11 @@ void ModelBaker::bakeSourceCopy() {
|
|||
handleError("Could not recognize file type of model file " + _originalModelFilePath);
|
||||
return;
|
||||
}
|
||||
hifi::VariantHash mapping;
|
||||
mapping["combineParts"] = true; // set true so that OBJSerializer reads material info from material library
|
||||
hfm::Model::Pointer loadedModel = serializer->read(modelData, mapping, _modelURL);
|
||||
hifi::VariantHash serializerMapping = _mapping;
|
||||
serializerMapping["combineParts"] = true; // set true so that OBJSerializer reads material info from material library
|
||||
hfm::Model::Pointer loadedModel = serializer->read(modelData, serializerMapping, _modelURL);
|
||||
|
||||
baker::Baker baker(loadedModel, mapping);
|
||||
baker::Baker baker(loadedModel, serializerMapping);
|
||||
auto config = baker.getConfiguration();
|
||||
// Enable compressed draco mesh generation
|
||||
config->getJobConfig("BuildDracoMesh")->setEnabled(true);
|
||||
|
@ -269,6 +303,32 @@ void ModelBaker::bakeSourceCopy() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Output FST file, copying over input mappings if available
|
||||
QString outputFSTFilename = !_mappingURL.isEmpty() ? _mappingURL.fileName() : _modelURL.fileName();
|
||||
auto extensionStart = outputFSTFilename.indexOf(".");
|
||||
if (extensionStart != -1) {
|
||||
outputFSTFilename.resize(extensionStart);
|
||||
}
|
||||
outputFSTFilename += ".baked.fst";
|
||||
QString outputFSTURL = _bakedOutputDir + "/" + outputFSTFilename;
|
||||
|
||||
auto outputMapping = _mapping;
|
||||
outputMapping[FST_VERSION_FIELD] = FST_VERSION;
|
||||
outputMapping[FILENAME_FIELD] = _bakedModelURL.fileName();
|
||||
hifi::ByteArray fstOut = FSTReader::writeMapping(outputMapping);
|
||||
|
||||
QFile fstOutputFile { outputFSTURL };
|
||||
if (!fstOutputFile.open(QIODevice::WriteOnly)) {
|
||||
handleError("Failed to open file '" + outputFSTURL + "' for writing");
|
||||
return;
|
||||
}
|
||||
if (fstOutputFile.write(fstOut) == -1) {
|
||||
handleError("Failed to write to file '" + outputFSTURL + "'");
|
||||
return;
|
||||
}
|
||||
_outputFiles.push_back(outputFSTURL);
|
||||
_outputMappingURL = outputFSTURL;
|
||||
|
||||
// check if we're already done with textures (in case we had none to re-write)
|
||||
checkIfTexturesFinished();
|
||||
}
|
||||
|
@ -657,31 +717,25 @@ void ModelBaker::embedTextureMetaData() {
|
|||
}
|
||||
|
||||
void ModelBaker::exportScene() {
|
||||
// save the relative path to this FBX inside our passed output folder
|
||||
auto fileName = _modelURL.fileName();
|
||||
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||
auto bakedFilename = baseName + BAKED_FBX_EXTENSION;
|
||||
|
||||
_bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||
|
||||
auto fbxData = FBXWriter::encodeFBX(_rootNode);
|
||||
|
||||
QFile bakedFile(_bakedModelFilePath);
|
||||
QString bakedModelURL = _bakedModelURL.toString();
|
||||
QFile bakedFile(bakedModelURL);
|
||||
|
||||
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||
handleError("Error opening " + _bakedModelFilePath + " for writing");
|
||||
handleError("Error opening " + bakedModelURL + " for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
bakedFile.write(fbxData);
|
||||
|
||||
_outputFiles.push_back(_bakedModelFilePath);
|
||||
_outputFiles.push_back(bakedModelURL);
|
||||
|
||||
#ifdef HIFI_DUMP_FBX
|
||||
{
|
||||
FBXToJSON fbxToJSON;
|
||||
fbxToJSON << _rootNode;
|
||||
QFileInfo modelFile(_bakedModelFilePath);
|
||||
QFileInfo modelFile(_bakedModelURL.toString());
|
||||
QString outFilename(modelFile.dir().absolutePath() + "/" + modelFile.completeBaseName() + "_FBX.json");
|
||||
QFile jsonFile(outFilename);
|
||||
if (jsonFile.open(QIODevice::WriteOnly)) {
|
||||
|
@ -691,5 +745,5 @@ void ModelBaker::exportScene() {
|
|||
}
|
||||
#endif
|
||||
|
||||
qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath;
|
||||
qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << bakedModelURL;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ public:
|
|||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "", bool hasBeenBaked = false);
|
||||
virtual ~ModelBaker();
|
||||
|
||||
void setOutputURLSuffix(const QUrl& urlSuffix);
|
||||
void setMappingURL(const QUrl& mappingURL);
|
||||
void setMapping(const hifi::VariantHash& mapping);
|
||||
|
||||
void initializeOutputDirs();
|
||||
|
||||
bool buildDracoMeshNode(FBXNode& dracoMeshNode, const QByteArray& dracoMeshBytes, const std::vector<hifi::ByteArray>& dracoMaterialList);
|
||||
|
@ -52,7 +56,8 @@ public:
|
|||
virtual void setWasAborted(bool wasAborted) override;
|
||||
|
||||
QUrl getModelURL() const { return _modelURL; }
|
||||
QString getBakedModelFilePath() const { return _bakedModelFilePath; }
|
||||
virtual QUrl getFullOutputMappingURL() const;
|
||||
QUrl getBakedModelURL() const { return _bakedModelURL; }
|
||||
|
||||
signals:
|
||||
void modelLoaded();
|
||||
|
@ -72,9 +77,14 @@ protected:
|
|||
FBXNode _rootNode;
|
||||
QHash<QByteArray, QByteArray> _textureContentMap;
|
||||
QUrl _modelURL;
|
||||
QUrl _outputURLSuffix;
|
||||
QUrl _mappingURL;
|
||||
hifi::VariantHash _mapping;
|
||||
QString _bakedOutputDir;
|
||||
QString _originalOutputDir;
|
||||
QString _bakedModelFilePath;
|
||||
TextureBakerThreadGetter _textureThreadGetter;
|
||||
QString _outputMappingURL;
|
||||
QUrl _bakedModelURL;
|
||||
QDir _modelTempDir;
|
||||
QString _originalModelFilePath;
|
||||
|
||||
|
@ -93,7 +103,6 @@ private:
|
|||
const QString & bakedFilename, const QByteArray & textureContent);
|
||||
QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL);
|
||||
|
||||
TextureBakerThreadGetter _textureThreadGetter;
|
||||
QMultiHash<QUrl, QSharedPointer<TextureBaker>> _bakingTextures;
|
||||
QHash<QString, int> _textureNameMatchCount;
|
||||
QHash<QUrl, QString> _remappedTexturePaths;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "BakerLibrary.h"
|
||||
|
||||
#include "FSTBaker.h"
|
||||
#include "../FBXBaker.h"
|
||||
#include "../OBJBaker.h"
|
||||
|
||||
|
@ -51,22 +52,24 @@ std::unique_ptr<ModelBaker> getModelBaker(const QUrl& bakeableModelURL, TextureB
|
|||
QString bakedOutputDirectory = contentOutputPath + subDirName + "/baked";
|
||||
QString originalOutputDirectory = contentOutputPath + subDirName + "/original";
|
||||
|
||||
return getModelBakerWithOutputDirectories(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory);
|
||||
}
|
||||
|
||||
std::unique_ptr<ModelBaker> getModelBakerWithOutputDirectories(const QUrl& bakeableModelURL, TextureBakerThreadGetter inputTextureThreadGetter, const QString& bakedOutputDirectory, const QString& originalOutputDirectory) {
|
||||
auto filename = bakeableModelURL.fileName();
|
||||
|
||||
std::unique_ptr<ModelBaker> baker;
|
||||
if (filename.endsWith(FST_EXTENSION, Qt::CaseInsensitive)) {
|
||||
//baker = std::make_unique<FSTBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory, filename.endsWith(BAKED_FST_EXTENSION, Qt::CaseInsensitive));
|
||||
baker = std::make_unique<FSTBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory, filename.endsWith(BAKED_FST_EXTENSION, Qt::CaseInsensitive));
|
||||
} else if (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive)) {
|
||||
baker = std::make_unique<FBXBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory, filename.endsWith(BAKED_FBX_EXTENSION, Qt::CaseInsensitive));
|
||||
} else if (filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive)) {
|
||||
baker = std::make_unique<OBJBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory);
|
||||
} else if (filename.endsWith(GLTF_EXTENSION, Qt::CaseInsensitive)) {
|
||||
//} else if (filename.endsWith(GLTF_EXTENSION, Qt::CaseInsensitive)) {
|
||||
//baker = std::make_unique<GLTFBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory);
|
||||
} else {
|
||||
qDebug() << "Could not create ModelBaker for url" << bakeableModelURL;
|
||||
}
|
||||
|
||||
if (baker) {
|
||||
QDir(contentOutputPath).mkpath(subDirName);
|
||||
}
|
||||
|
||||
return baker;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
|
||||
#include "../ModelBaker.h"
|
||||
|
||||
// Returns either the given model URL, or, if the model is baked and shouldRebakeOriginals is true,
|
||||
// the guessed location of the original model
|
||||
// Returns an empty URL if no bakeable URL found
|
||||
// Returns either the given model URL if valid, or an empty URL
|
||||
QUrl getBakeableModelURL(const QUrl& url);
|
||||
|
||||
// Assuming the URL is valid, gets the appropriate baker for the given URL, and creates the base directory where the baker's output will later be stored
|
||||
// Returns an empty pointer if a baker could not be created
|
||||
std::unique_ptr<ModelBaker> getModelBaker(const QUrl& bakeableModelURL, TextureBakerThreadGetter inputTextureThreadGetter, const QString& contentOutputPath);
|
||||
|
||||
#endif hifi_BakerLibrary_h
|
||||
// Similar to getModelBaker, but gives control over where the output folders will be
|
||||
std::unique_ptr<ModelBaker> getModelBakerWithOutputDirectories(const QUrl& bakeableModelURL, TextureBakerThreadGetter inputTextureThreadGetter, const QString& bakedOutputDirectory, const QString& originalOutputDirectory);
|
||||
|
||||
#endif // hifi_BakerLibrary_h
|
||||
|
|
128
libraries/baking/src/baking/FSTBaker.cpp
Normal file
128
libraries/baking/src/baking/FSTBaker.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// FSTBaker.cpp
|
||||
// libraries/baking/src/baking
|
||||
//
|
||||
// Created by Sabrina Shanman on 2019/03/06.
|
||||
// Copyright 2019 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 "FSTBaker.h"
|
||||
|
||||
#include <PathUtils.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "BakerLibrary.h"
|
||||
|
||||
#include <FSTReader.h>
|
||||
|
||||
FSTBaker::FSTBaker(const QUrl& inputMappingURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory, bool hasBeenBaked) :
|
||||
ModelBaker(inputMappingURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory, hasBeenBaked) {
|
||||
if (hasBeenBaked) {
|
||||
// Look for the original model file one directory higher. Perhaps this is an oven output directory.
|
||||
QUrl originalRelativePath = QUrl("../original/" + inputMappingURL.fileName().replace(BAKED_FST_EXTENSION, FST_EXTENSION));
|
||||
QUrl newInputMappingURL = inputMappingURL.adjusted(QUrl::RemoveFilename).resolved(originalRelativePath);
|
||||
_modelURL = newInputMappingURL;
|
||||
}
|
||||
_mappingURL = _modelURL;
|
||||
|
||||
{
|
||||
// Unused, but defined for consistency
|
||||
auto bakedFilename = _modelURL.fileName();
|
||||
bakedFilename.replace(FST_EXTENSION, BAKED_FST_EXTENSION);
|
||||
_bakedModelURL = _bakedOutputDir + "/" + bakedFilename;
|
||||
}
|
||||
}
|
||||
|
||||
QUrl FSTBaker::getFullOutputMappingURL() const {
|
||||
if (_modelBaker) {
|
||||
return _modelBaker->getFullOutputMappingURL();
|
||||
}
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
void FSTBaker::bakeSourceCopy() {
|
||||
if (shouldStop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile fstFile(_originalModelFilePath);
|
||||
if (!fstFile.open(QIODevice::ReadOnly)) {
|
||||
handleError("Error opening " + _originalModelFilePath + " for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
hifi::ByteArray fstData = fstFile.readAll();
|
||||
_mapping = FSTReader::readMapping(fstData);
|
||||
|
||||
auto filenameField = _mapping[FILENAME_FIELD].toString();
|
||||
if (filenameField.isEmpty()) {
|
||||
handleError("The '" + FILENAME_FIELD + "' property in the FST file '" + _originalModelFilePath + "' could not be found");
|
||||
return;
|
||||
}
|
||||
auto modelURL = _mappingURL.adjusted(QUrl::RemoveFilename).resolved(filenameField);
|
||||
auto bakeableModelURL = getBakeableModelURL(modelURL);
|
||||
if (bakeableModelURL.isEmpty()) {
|
||||
handleError("The '" + FILENAME_FIELD + "' property in the FST file '" + _originalModelFilePath + "' could not be resolved to a valid bakeable model url");
|
||||
return;
|
||||
}
|
||||
|
||||
auto baker = getModelBakerWithOutputDirectories(bakeableModelURL, _textureThreadGetter, _bakedOutputDir, _originalOutputDir);
|
||||
_modelBaker = std::unique_ptr<ModelBaker>(dynamic_cast<ModelBaker*>(baker.release()));
|
||||
if (!_modelBaker) {
|
||||
handleError("The model url '" + bakeableModelURL.toString() + "' from the FST file '" + _originalModelFilePath + "' (property: '" + FILENAME_FIELD + "') could not be used to initialize a valid model baker");
|
||||
return;
|
||||
}
|
||||
if (dynamic_cast<FSTBaker*>(_modelBaker.get())) {
|
||||
// Could be interesting, but for now let's just prevent infinite FST loops in the most straightforward way possible
|
||||
handleError("The FST file '" + _originalModelFilePath + "' (property: '" + FILENAME_FIELD + "') references another FST file. FST chaining is not supported.");
|
||||
return;
|
||||
}
|
||||
_modelBaker->setMappingURL(_mappingURL);
|
||||
_modelBaker->setMapping(_mapping);
|
||||
// Hold on to the old url userinfo/query/fragment data so ModelBaker::getFullOutputMappingURL retains that data from the original model URL
|
||||
_modelBaker->setOutputURLSuffix(modelURL);
|
||||
|
||||
connect(_modelBaker.get(), &ModelBaker::aborted, this, &FSTBaker::handleModelBakerAborted);
|
||||
connect(_modelBaker.get(), &ModelBaker::finished, this, &FSTBaker::handleModelBakerFinished);
|
||||
|
||||
// FSTBaker can't do much while waiting for the ModelBaker to finish, so start the bake on this thread.
|
||||
_modelBaker->bake();
|
||||
}
|
||||
|
||||
void FSTBaker::handleModelBakerEnded() {
|
||||
for (auto& warning : _modelBaker->getWarnings()) {
|
||||
_warningList.push_back(warning);
|
||||
}
|
||||
for (auto& error : _modelBaker->getErrors()) {
|
||||
_errorList.push_back(error);
|
||||
}
|
||||
|
||||
// Get the output files, including but not limited to the FST file and the baked model file
|
||||
for (auto& outputFile : _modelBaker->getOutputFiles()) {
|
||||
_outputFiles.push_back(outputFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FSTBaker::handleModelBakerAborted() {
|
||||
handleModelBakerEnded();
|
||||
if (!wasAborted()) {
|
||||
setWasAborted(true);
|
||||
}
|
||||
}
|
||||
|
||||
void FSTBaker::handleModelBakerFinished() {
|
||||
handleModelBakerEnded();
|
||||
setIsFinished(true);
|
||||
}
|
||||
|
||||
void FSTBaker::abort() {
|
||||
ModelBaker::abort();
|
||||
if (_modelBaker) {
|
||||
_modelBaker->abort();
|
||||
}
|
||||
}
|
45
libraries/baking/src/baking/FSTBaker.h
Normal file
45
libraries/baking/src/baking/FSTBaker.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// FSTBaker.h
|
||||
// libraries/baking/src/baking
|
||||
//
|
||||
// Created by Sabrina Shanman on 2019/03/06.
|
||||
// Copyright 2019 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_FSTBaker_h
|
||||
#define hifi_FSTBaker_h
|
||||
|
||||
#include "../ModelBaker.h"
|
||||
|
||||
class FSTBaker : public ModelBaker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FSTBaker(const QUrl& inputMappingURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "", bool hasBeenBaked = false);
|
||||
|
||||
virtual QUrl getFullOutputMappingURL() const;
|
||||
|
||||
signals:
|
||||
void fstLoaded();
|
||||
|
||||
public slots:
|
||||
virtual void abort() override;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ModelBaker> _modelBaker;
|
||||
|
||||
protected slots:
|
||||
virtual void bakeSourceCopy() override;
|
||||
virtual void bakeProcessedSource(const hfm::Model::Pointer& hfmModel, const std::vector<hifi::ByteArray>& dracoMeshes, const std::vector<std::vector<hifi::ByteArray>>& dracoMaterialLists) override {};
|
||||
void handleModelBakerAborted();
|
||||
void handleModelBakerFinished();
|
||||
|
||||
private:
|
||||
void handleModelBakerEnded();
|
||||
};
|
||||
|
||||
#endif // hifi_FSTBaker_h
|
|
@ -15,6 +15,8 @@
|
|||
#include <QBuffer>
|
||||
#include <QVariantHash>
|
||||
|
||||
static const unsigned int FST_VERSION = 1;
|
||||
static const QString FST_VERSION_FIELD = "version";
|
||||
static const QString NAME_FIELD = "name";
|
||||
static const QString TYPE_FIELD = "type";
|
||||
static const QString FILENAME_FIELD = "filename";
|
||||
|
|
|
@ -152,8 +152,11 @@ void DomainBaker::addModelBaker(const QString& property, const QString& url, QJs
|
|||
auto getWorkerThreadCallback = []() -> QThread* {
|
||||
return Oven::instance().getNextWorkerThread();
|
||||
};
|
||||
QSharedPointer<ModelBaker> baker = QSharedPointer<ModelBaker>(getModelBaker(bakeableModelURL, getWorkerThreadCallback, _contentOutputPath).release(), &ModelBaker::deleteLater);
|
||||
QSharedPointer<ModelBaker> baker = QSharedPointer<ModelBaker>(getModelBaker(bakeableModelURL, getWorkerThreadCallback, _contentOutputPath).release(), &Baker::deleteLater);
|
||||
if (baker) {
|
||||
// Hold on to the old url userinfo/query/fragment data so ModelBaker::getFullOutputMappingURL retains that data from the original model URL
|
||||
baker->setOutputURLSuffix(url);
|
||||
|
||||
// make sure our handler is called when the baker is done
|
||||
connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedModelBaker);
|
||||
|
||||
|
@ -332,6 +335,7 @@ void DomainBaker::enumerateEntities() {
|
|||
addModelBaker(MODEL_URL_KEY, entity[MODEL_URL_KEY].toString(), *it);
|
||||
}
|
||||
if (entity.contains(COMPOUND_SHAPE_URL_KEY)) {
|
||||
// TODO: Do not combine mesh parts, otherwise the collision behavior will be different
|
||||
// TODO: this could be optimized so that we don't do the full baking pass for collision shapes,
|
||||
// but we have to handle the case where it's also used as a modelURL somewhere
|
||||
addModelBaker(COMPOUND_SHAPE_URL_KEY, entity[COMPOUND_SHAPE_URL_KEY].toString(), *it);
|
||||
|
@ -415,11 +419,11 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
qDebug() << "Re-writing entity references to" << baker->getModelURL();
|
||||
|
||||
// setup a new URL using the prefix we were passed
|
||||
auto relativeFBXFilePath = baker->getBakedModelFilePath().remove(_contentOutputPath);
|
||||
if (relativeFBXFilePath.startsWith("/")) {
|
||||
relativeFBXFilePath = relativeFBXFilePath.right(relativeFBXFilePath.length() - 1);
|
||||
auto relativeMappingFilePath = baker->getFullOutputMappingURL().toString().remove(_contentOutputPath);
|
||||
if (relativeMappingFilePath.startsWith("/")) {
|
||||
relativeMappingFilePath = relativeMappingFilePath.right(relativeMappingFilePath.length() - 1);
|
||||
}
|
||||
QUrl newURL = _destinationPath.resolved(relativeFBXFilePath);
|
||||
QUrl newURL = _destinationPath.resolved(relativeMappingFilePath);
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this model from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
|
@ -432,12 +436,8 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
// grab the old URL
|
||||
QUrl oldURL = entity[property].toString();
|
||||
|
||||
// copy the fragment and query, and user info from the old model URL
|
||||
newURL.setQuery(oldURL.query());
|
||||
newURL.setFragment(oldURL.fragment());
|
||||
newURL.setUserInfo(oldURL.userInfo());
|
||||
|
||||
// set the new URL as the value in our temp QJsonObject
|
||||
// The fragment, query, and user info from the original model URL should now be present on the filename in the FST file
|
||||
entity[property] = newURL.toString();
|
||||
} else {
|
||||
// Group property
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include "Baker.h"
|
||||
#include "ModelBaker.h"
|
||||
#include "TextureBaker.h"
|
||||
#include "JSBaker.h"
|
||||
|
|
Loading…
Reference in a new issue