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:
sabrina-shanman 2019-03-07 17:39:19 -08:00
parent 1576125c42
commit efc9f993f5
12 changed files with 301 additions and 48 deletions

View file

@ -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;

View file

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

View 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;

View file

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

View file

@ -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;

View file

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

View file

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

View 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();
}
}

View 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

View file

@ -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";

View file

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

View file

@ -17,7 +17,6 @@
#include <QtCore/QUrl>
#include <QtCore/QThread>
#include "Baker.h"
#include "ModelBaker.h"
#include "TextureBaker.h"
#include "JSBaker.h"