mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:43:50 +02:00
cleaning up oven
This commit is contained in:
parent
86c948f116
commit
270b96aa8d
9 changed files with 431 additions and 288 deletions
|
@ -25,6 +25,9 @@ public:
|
|||
JSBaker(const QUrl& jsURL, const QString& bakedOutputDir);
|
||||
static bool bakeJS(const QByteArray& inputFile, QByteArray& outputFile);
|
||||
|
||||
QString getJSPath() const { return _jsURL.fileName(); }
|
||||
QString getBakedJSFilePath() const { return _bakedJSFilePath; }
|
||||
|
||||
public slots:
|
||||
virtual void bake() override;
|
||||
|
||||
|
|
|
@ -32,11 +32,12 @@
|
|||
#endif
|
||||
|
||||
ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory) :
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory, bool hasBeenBaked) :
|
||||
_modelURL(inputModelURL),
|
||||
_bakedOutputDir(bakedOutputDirectory),
|
||||
_originalOutputDir(originalOutputDirectory),
|
||||
_textureThreadGetter(inputTextureThreadGetter)
|
||||
_textureThreadGetter(inputTextureThreadGetter),
|
||||
_hasBeenBaked(hasBeenBaked)
|
||||
{
|
||||
auto tempDir = PathUtils::generateTemporaryDir();
|
||||
|
||||
|
|
|
@ -30,16 +30,19 @@
|
|||
using TextureBakerThreadGetter = std::function<QThread*()>;
|
||||
using GetMaterialIDCallback = std::function <int(int)>;
|
||||
|
||||
static const QString BAKED_FBX_EXTENSION = ".baked.fbx";
|
||||
static const QString BAKEABLE_MODEL_FBX_EXTENSION { ".fbx" };
|
||||
static const QString BAKEABLE_MODEL_OBJ_EXTENSION { ".obj" };
|
||||
static const QString FST_EXTENSION { ".fst" };
|
||||
static const QString BAKED_FST_EXTENSION { ".baked.fst" };
|
||||
static const QString FBX_EXTENSION { ".fbx" };
|
||||
static const QString BAKED_FBX_EXTENSION { ".baked.fbx" };
|
||||
static const QString OBJ_EXTENSION { ".obj" };
|
||||
static const QString GLTF_EXTENSION { ".gltf" };
|
||||
|
||||
class ModelBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "");
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "", bool hasBeenBaked = false);
|
||||
virtual ~ModelBaker();
|
||||
|
||||
void initializeOutputDirs();
|
||||
|
@ -59,7 +62,7 @@ protected:
|
|||
void texturesFinished();
|
||||
void embedTextureMetaData();
|
||||
void exportScene();
|
||||
|
||||
|
||||
FBXNode _rootNode;
|
||||
QHash<QByteArray, QByteArray> _textureContentMap;
|
||||
QUrl _modelURL;
|
||||
|
@ -79,12 +82,14 @@ private:
|
|||
void bakeTexture(const QUrl & textureURL, image::TextureUsage::Type textureType, const QDir & outputDir,
|
||||
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;
|
||||
bool _pendingErrorEmission{ false };
|
||||
bool _pendingErrorEmission { false };
|
||||
|
||||
bool _hasBeenBaked { false };
|
||||
};
|
||||
|
||||
#endif // hifi_ModelBaker_h
|
||||
|
|
|
@ -14,33 +14,26 @@
|
|||
#include "../FBXBaker.h"
|
||||
#include "../OBJBaker.h"
|
||||
|
||||
QUrl getBakeableModelURL(const QUrl& url, bool shouldRebakeOriginals) {
|
||||
// Check if the file pointed to by this URL is a bakeable model, by comparing extensions
|
||||
auto modelFileName = url.fileName();
|
||||
// Check if the file pointed to by this URL is a bakeable model, by comparing extensions
|
||||
QUrl getBakeableModelURL(const QUrl& url) {
|
||||
static const std::vector<QString> extensionsToBake = {
|
||||
FST_EXTENSION,
|
||||
BAKED_FST_EXTENSION,
|
||||
FBX_EXTENSION,
|
||||
BAKED_FBX_EXTENSION,
|
||||
OBJ_EXTENSION,
|
||||
GLTF_EXTENSION
|
||||
};
|
||||
|
||||
bool isBakedModel = modelFileName.endsWith(BAKED_FBX_EXTENSION, Qt::CaseInsensitive);
|
||||
bool isBakeableFBX = modelFileName.endsWith(BAKEABLE_MODEL_FBX_EXTENSION, Qt::CaseInsensitive);
|
||||
bool isBakeableOBJ = modelFileName.endsWith(BAKEABLE_MODEL_OBJ_EXTENSION, Qt::CaseInsensitive);
|
||||
bool isBakeable = isBakeableFBX || isBakeableOBJ;
|
||||
|
||||
if (isBakeable || (shouldRebakeOriginals && isBakedModel)) {
|
||||
if (isBakedModel) {
|
||||
// Grab a URL to the original, that we assume is stored a directory up, in the "original" folder
|
||||
// with just the fbx extension
|
||||
qDebug() << "Inferring original URL for baked model URL" << url;
|
||||
|
||||
auto originalFileName = modelFileName;
|
||||
originalFileName.replace(".baked", "");
|
||||
qDebug() << "Original model URL must be present at" << url;
|
||||
|
||||
return url.resolved("../original/" + originalFileName);
|
||||
} else {
|
||||
// Grab a clean version of the URL without a query or fragment
|
||||
return url.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
QUrl cleanURL = url.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
QString cleanURLString = cleanURL.fileName();
|
||||
for (auto& extension : extensionsToBake) {
|
||||
if (cleanURLString.endsWith(extension, Qt::CaseInsensitive)) {
|
||||
return cleanURL;
|
||||
}
|
||||
}
|
||||
|
||||
qWarning() << "Unknown model type: " << modelFileName;
|
||||
qWarning() << "Unknown model type: " << url.fileName();
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
|
@ -59,11 +52,14 @@ std::unique_ptr<ModelBaker> getModelBaker(const QUrl& bakeableModelURL, TextureB
|
|||
QString originalOutputDirectory = contentOutputPath + subDirName + "/original";
|
||||
|
||||
std::unique_ptr<ModelBaker> baker;
|
||||
|
||||
if (filename.endsWith(BAKEABLE_MODEL_FBX_EXTENSION, Qt::CaseInsensitive)) {
|
||||
baker = std::make_unique<FBXBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory);
|
||||
} else if (filename.endsWith(BAKEABLE_MODEL_OBJ_EXTENSION, Qt::CaseInsensitive)) {
|
||||
if (filename.endsWith(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)) {
|
||||
//baker = std::make_unique<GLTFBaker>(bakeableModelURL, inputTextureThreadGetter, bakedOutputDirectory, originalOutputDirectory);
|
||||
} else {
|
||||
qDebug() << "Could not create ModelBaker for url" << bakeableModelURL;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// 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
|
||||
QUrl getBakeableModelURL(const QUrl& url, bool shouldRebakeOriginals);
|
||||
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
|
||||
|
|
|
@ -37,25 +37,16 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString&
|
|||
|
||||
qDebug() << "Baking file type: " << type;
|
||||
|
||||
static const QString MODEL_EXTENSION { "fbx" };
|
||||
static const QString MODEL_EXTENSION { "model" };
|
||||
static const QString FBX_EXTENSION { "fbx" }; // legacy
|
||||
static const QString MATERIAL_EXTENSION { "material" };
|
||||
static const QString SCRIPT_EXTENSION { "js" };
|
||||
|
||||
// check what kind of baker we should be creating
|
||||
bool isModel = type == MODEL_EXTENSION;
|
||||
bool isScript = type == SCRIPT_EXTENSION;
|
||||
|
||||
// If the type doesn't match the above, we assume we have a texture, and the type specified is the
|
||||
// texture usage type (albedo, cubemap, normals, etc.)
|
||||
auto url = inputUrl.toDisplayString();
|
||||
auto idx = url.lastIndexOf('.');
|
||||
auto extension = idx >= 0 ? url.mid(idx + 1).toLower() : "";
|
||||
bool isSupportedImage = QImageReader::supportedImageFormats().contains(extension.toLatin1());
|
||||
|
||||
_outputPath = outputPath;
|
||||
|
||||
// create our appropiate baker
|
||||
if (isModel) {
|
||||
QUrl bakeableModelURL = getBakeableModelURL(inputUrl, false);
|
||||
if (type == MODEL_EXTENSION || type == FBX_EXTENSION) {
|
||||
QUrl bakeableModelURL = getBakeableModelURL(inputUrl);
|
||||
if (!bakeableModelURL.isEmpty()) {
|
||||
auto getWorkerThreadCallback = []() -> QThread* {
|
||||
return Oven::instance().getNextWorkerThread();
|
||||
|
@ -65,35 +56,49 @@ void BakerCLI::bakeFile(QUrl inputUrl, const QString& outputPath, const QString&
|
|||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
}
|
||||
}
|
||||
} else if (isScript) {
|
||||
} else if (type == SCRIPT_EXTENSION) {
|
||||
_baker = std::unique_ptr<Baker> { new JSBaker(inputUrl, outputPath) };
|
||||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
} else if (isSupportedImage) {
|
||||
static const std::unordered_map<QString, image::TextureUsage::Type> STRING_TO_TEXTURE_USAGE_TYPE_MAP {
|
||||
{ "default", image::TextureUsage::DEFAULT_TEXTURE },
|
||||
{ "strict", image::TextureUsage::STRICT_TEXTURE },
|
||||
{ "albedo", image::TextureUsage::ALBEDO_TEXTURE },
|
||||
{ "normal", image::TextureUsage::NORMAL_TEXTURE },
|
||||
{ "bump", image::TextureUsage::BUMP_TEXTURE },
|
||||
{ "specular", image::TextureUsage::SPECULAR_TEXTURE },
|
||||
{ "metallic", image::TextureUsage::METALLIC_TEXTURE },
|
||||
{ "roughness", image::TextureUsage::ROUGHNESS_TEXTURE },
|
||||
{ "gloss", image::TextureUsage::GLOSS_TEXTURE },
|
||||
{ "emissive", image::TextureUsage::EMISSIVE_TEXTURE },
|
||||
{ "cube", image::TextureUsage::CUBE_TEXTURE },
|
||||
{ "occlusion", image::TextureUsage::OCCLUSION_TEXTURE },
|
||||
{ "scattering", image::TextureUsage::SCATTERING_TEXTURE },
|
||||
{ "lightmap", image::TextureUsage::LIGHTMAP_TEXTURE },
|
||||
};
|
||||
|
||||
auto it = STRING_TO_TEXTURE_USAGE_TYPE_MAP.find(type);
|
||||
if (it == STRING_TO_TEXTURE_USAGE_TYPE_MAP.end()) {
|
||||
qCDebug(model_baking) << "Unknown texture usage type:" << type;
|
||||
QCoreApplication::exit(OVEN_STATUS_CODE_FAIL);
|
||||
}
|
||||
_baker = std::unique_ptr<Baker> { new TextureBaker(inputUrl, it->second, outputPath) };
|
||||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
} else if (type == MATERIAL_EXTENSION) {
|
||||
//_baker = std::unique_ptr<Baker> { new MaterialBaker(inputUrl, outputPath) };
|
||||
//_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
} else {
|
||||
// If the type doesn't match the above, we assume we have a texture, and the type specified is the
|
||||
// texture usage type (albedo, cubemap, normals, etc.)
|
||||
auto url = inputUrl.toDisplayString();
|
||||
auto idx = url.lastIndexOf('.');
|
||||
auto extension = idx >= 0 ? url.mid(idx + 1).toLower() : "";
|
||||
|
||||
if (QImageReader::supportedImageFormats().contains(extension.toLatin1())) {
|
||||
static const std::unordered_map<QString, image::TextureUsage::Type> STRING_TO_TEXTURE_USAGE_TYPE_MAP {
|
||||
{ "default", image::TextureUsage::DEFAULT_TEXTURE },
|
||||
{ "strict", image::TextureUsage::STRICT_TEXTURE },
|
||||
{ "albedo", image::TextureUsage::ALBEDO_TEXTURE },
|
||||
{ "normal", image::TextureUsage::NORMAL_TEXTURE },
|
||||
{ "bump", image::TextureUsage::BUMP_TEXTURE },
|
||||
{ "specular", image::TextureUsage::SPECULAR_TEXTURE },
|
||||
{ "metallic", image::TextureUsage::METALLIC_TEXTURE },
|
||||
{ "roughness", image::TextureUsage::ROUGHNESS_TEXTURE },
|
||||
{ "gloss", image::TextureUsage::GLOSS_TEXTURE },
|
||||
{ "emissive", image::TextureUsage::EMISSIVE_TEXTURE },
|
||||
{ "cube", image::TextureUsage::CUBE_TEXTURE },
|
||||
{ "skybox", image::TextureUsage::CUBE_TEXTURE },
|
||||
{ "occlusion", image::TextureUsage::OCCLUSION_TEXTURE },
|
||||
{ "scattering", image::TextureUsage::SCATTERING_TEXTURE },
|
||||
{ "lightmap", image::TextureUsage::LIGHTMAP_TEXTURE },
|
||||
};
|
||||
|
||||
auto it = STRING_TO_TEXTURE_USAGE_TYPE_MAP.find(type);
|
||||
if (it == STRING_TO_TEXTURE_USAGE_TYPE_MAP.end()) {
|
||||
qCDebug(model_baking) << "Unknown texture usage type:" << type;
|
||||
QCoreApplication::exit(OVEN_STATUS_CODE_FAIL);
|
||||
}
|
||||
_baker = std::unique_ptr<Baker> { new TextureBaker(inputUrl, it->second, outputPath) };
|
||||
_baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
}
|
||||
}
|
||||
|
||||
if (!_baker) {
|
||||
qCDebug(model_baking) << "Failed to determine baker type for file" << inputUrl;
|
||||
QCoreApplication::exit(OVEN_STATUS_CODE_FAIL);
|
||||
return;
|
||||
|
|
|
@ -27,8 +27,7 @@ DomainBaker::DomainBaker(const QUrl& localModelFileURL, const QString& domainNam
|
|||
bool shouldRebakeOriginals) :
|
||||
_localEntitiesFileURL(localModelFileURL),
|
||||
_domainName(domainName),
|
||||
_baseOutputPath(baseOutputPath),
|
||||
_shouldRebakeOriginals(shouldRebakeOriginals)
|
||||
_baseOutputPath(baseOutputPath)
|
||||
{
|
||||
// make sure the destination path has a trailing slash
|
||||
if (!destinationPath.toString().endsWith('/')) {
|
||||
|
@ -145,11 +144,139 @@ void DomainBaker::loadLocalFile() {
|
|||
}
|
||||
}
|
||||
|
||||
const QString ENTITY_MODEL_URL_KEY = "modelURL";
|
||||
const QString ENTITY_SKYBOX_KEY = "skybox";
|
||||
const QString ENTITY_SKYBOX_URL_KEY = "url";
|
||||
const QString ENTITY_KEYLIGHT_KEY = "keyLight";
|
||||
const QString ENTITY_KEYLIGHT_AMBIENT_URL_KEY = "ambientURL";
|
||||
void DomainBaker::addModelBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef) {
|
||||
// grab a QUrl for the model URL
|
||||
QUrl bakeableModelURL = getBakeableModelURL(url);
|
||||
if (!bakeableModelURL.isEmpty()) {
|
||||
// setup a ModelBaker for this URL, as long as we don't already have one
|
||||
if (!_modelBakers.contains(bakeableModelURL)) {
|
||||
auto getWorkerThreadCallback = []() -> QThread* {
|
||||
return Oven::instance().getNextWorkerThread();
|
||||
};
|
||||
QSharedPointer<ModelBaker> baker = QSharedPointer<ModelBaker>(getModelBaker(bakeableModelURL, getWorkerThreadCallback, _contentOutputPath).release(), &ModelBaker::deleteLater);
|
||||
if (baker) {
|
||||
// make sure our handler is called when the baker is done
|
||||
connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedModelBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_modelBakers.insert(bakeableModelURL, baker);
|
||||
|
||||
// move the baker to the baker thread
|
||||
// and kickoff the bake
|
||||
baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(baker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that we can easily re-write
|
||||
// the model URL to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(bakeableModelURL, { property, jsonRef });
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::addTextureBaker(const QString& property, const QString& url, image::TextureUsage::Type type, QJsonValueRef& jsonRef) {
|
||||
auto idx = url.lastIndexOf('.');
|
||||
auto extension = idx >= 0 ? url.mid(idx + 1).toLower() : "";
|
||||
|
||||
if (QImageReader::supportedImageFormats().contains(extension.toLatin1())) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
QUrl textureURL = QUrl(url).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a texture already
|
||||
if (!_textureBakers.contains(textureURL)) {
|
||||
// setup a baker for this texture
|
||||
|
||||
QSharedPointer<TextureBaker> textureBaker {
|
||||
new TextureBaker(textureURL, type, _contentOutputPath),
|
||||
&TextureBaker::deleteLater
|
||||
};
|
||||
|
||||
// make sure our handler is called when the texture baker is done
|
||||
connect(textureBaker.data(), &TextureBaker::finished, this, &DomainBaker::handleFinishedTextureBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_textureBakers.insert(textureURL, textureBaker);
|
||||
|
||||
// move the baker to a worker thread and kickoff the bake
|
||||
textureBaker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(textureBaker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the texture URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(textureURL, { property, jsonRef });
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::addScriptBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
QUrl scriptURL = QUrl(url).adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a texture already
|
||||
if (!_scriptBakers.contains(scriptURL)) {
|
||||
// setup a baker for this texture
|
||||
|
||||
QSharedPointer<JSBaker> scriptBaker {
|
||||
new JSBaker(scriptURL, _contentOutputPath),
|
||||
&JSBaker::deleteLater
|
||||
};
|
||||
|
||||
// make sure our handler is called when the texture baker is done
|
||||
connect(scriptBaker.data(), &JSBaker::finished, this, &DomainBaker::handleFinishedScriptBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_scriptBakers.insert(scriptURL, scriptBaker);
|
||||
|
||||
// move the baker to a worker thread and kickoff the bake
|
||||
scriptBaker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(scriptBaker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the texture URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(scriptURL, { property, jsonRef });
|
||||
}
|
||||
|
||||
// All the Entity Properties that can be baked
|
||||
// ***************************************************************************************
|
||||
|
||||
// Models
|
||||
const QString MODEL_URL_KEY = "modelURL";
|
||||
const QString COMPOUND_SHAPE_URL_KEY = "compoundShapeURL";
|
||||
const QString GRAP_KEY = "grab";
|
||||
const QString EQUIPPABLE_INDICATOR_URL_KEY = "equippableIndicatorURL";
|
||||
const QString ANIMATION_KEY = "animation";
|
||||
const QString ANIMATION_URL_KEY = "url";
|
||||
|
||||
// Textures
|
||||
const QString TEXTURES_KEY = "textures";
|
||||
const QString IMAGE_URL_KEY = "imageURL";
|
||||
const QString X_TEXTURE_URL_KEY = "xTextureURL";
|
||||
const QString Y_TEXTURE_URL_KEY = "yTextureURL";
|
||||
const QString Z_TEXTURE_URL_KEY = "zTextureURL";
|
||||
const QString AMBIENT_LIGHT_KEY = "ambientLight";
|
||||
const QString AMBIENT_URL_KEY = "ambientURL";
|
||||
const QString SKYBOX_KEY = "skybox";
|
||||
const QString SKYBOX_URL_KEY = "url";
|
||||
|
||||
// Scripts
|
||||
const QString SCRIPT_KEY = "script";
|
||||
const QString SERVER_SCRIPTS_KEY = "serverScripts";
|
||||
|
||||
// Materials
|
||||
const QString MATERIAL_URL_KEY = "materialURL";
|
||||
const QString MATERIAL_DATA_KEY = "materialData";
|
||||
|
||||
// ***************************************************************************************
|
||||
|
||||
void DomainBaker::enumerateEntities() {
|
||||
qDebug() << "Enumerating" << _entities.size() << "entities from domain";
|
||||
|
@ -159,65 +286,65 @@ void DomainBaker::enumerateEntities() {
|
|||
if (it->isObject()) {
|
||||
auto entity = it->toObject();
|
||||
|
||||
// check if this is an entity with a model URL or is a skybox texture
|
||||
if (entity.contains(ENTITY_MODEL_URL_KEY)) {
|
||||
// grab a QUrl for the model URL
|
||||
QUrl bakeableModelURL = getBakeableModelURL(entity[ENTITY_MODEL_URL_KEY].toString(), _shouldRebakeOriginals);
|
||||
|
||||
if (!bakeableModelURL.isEmpty()) {
|
||||
|
||||
// setup a ModelBaker for this URL, as long as we don't already have one
|
||||
if (!_modelBakers.contains(bakeableModelURL)) {
|
||||
auto getWorkerThreadCallback = []() -> QThread* {
|
||||
return Oven::instance().getNextWorkerThread();
|
||||
};
|
||||
QSharedPointer<ModelBaker> baker = QSharedPointer<ModelBaker>(getModelBaker(bakeableModelURL, getWorkerThreadCallback, _contentOutputPath).release(), &ModelBaker::deleteLater);
|
||||
if (baker) {
|
||||
// make sure our handler is called when the baker is done
|
||||
connect(baker.data(), &Baker::finished, this, &DomainBaker::handleFinishedModelBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_modelBakers.insert(bakeableModelURL, baker);
|
||||
|
||||
// move the baker to the baker thread
|
||||
// and kickoff the bake
|
||||
baker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(baker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that we can easily re-write
|
||||
// the model URL to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(bakeableModelURL, *it);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// // We check now to see if we have either a texture for a skybox or a keylight, or both.
|
||||
// if (entity.contains(ENTITY_SKYBOX_KEY)) {
|
||||
// auto skyboxObject = entity[ENTITY_SKYBOX_KEY].toObject();
|
||||
// if (skyboxObject.contains(ENTITY_SKYBOX_URL_KEY)) {
|
||||
// // we have a URL to a skybox, grab it
|
||||
// QUrl skyboxURL { skyboxObject[ENTITY_SKYBOX_URL_KEY].toString() };
|
||||
//
|
||||
// // setup a bake of the skybox
|
||||
// bakeSkybox(skyboxURL, *it);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (entity.contains(ENTITY_KEYLIGHT_KEY)) {
|
||||
// auto keyLightObject = entity[ENTITY_KEYLIGHT_KEY].toObject();
|
||||
// if (keyLightObject.contains(ENTITY_KEYLIGHT_AMBIENT_URL_KEY)) {
|
||||
// // we have a URL to a skybox, grab it
|
||||
// QUrl skyboxURL { keyLightObject[ENTITY_KEYLIGHT_AMBIENT_URL_KEY].toString() };
|
||||
//
|
||||
// // setup a bake of the skybox
|
||||
// bakeSkybox(skyboxURL, *it);
|
||||
// }
|
||||
// }
|
||||
// Models
|
||||
if (entity.contains(MODEL_URL_KEY)) {
|
||||
addModelBaker(MODEL_URL_KEY, entity[MODEL_URL_KEY].toString(), *it);
|
||||
}
|
||||
if (entity.contains(COMPOUND_SHAPE_URL_KEY)) {
|
||||
// TODO: handle compoundShapeURL
|
||||
}
|
||||
if (entity.contains(ANIMATION_KEY)) {
|
||||
auto animationObject = entity[ANIMATION_KEY].toObject();
|
||||
if (animationObject.contains(ANIMATION_URL_KEY)) {
|
||||
addModelBaker(ANIMATION_KEY + "." + ANIMATION_URL_KEY, animationObject[ANIMATION_URL_KEY].toString(), *it);
|
||||
}
|
||||
}
|
||||
if (entity.contains(GRAP_KEY)) {
|
||||
auto grabObject = entity[GRAP_KEY].toObject();
|
||||
if (grabObject.contains(EQUIPPABLE_INDICATOR_URL_KEY)) {
|
||||
addModelBaker(GRAP_KEY + "." + EQUIPPABLE_INDICATOR_URL_KEY, grabObject[EQUIPPABLE_INDICATOR_URL_KEY].toString(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
// Textures
|
||||
if (entity.contains(TEXTURES_KEY)) {
|
||||
// TODO: the textures property is treated differently for different entity types
|
||||
}
|
||||
if (entity.contains(IMAGE_URL_KEY)) {
|
||||
addTextureBaker(IMAGE_URL_KEY, entity[IMAGE_URL_KEY].toString(), image::TextureUsage::DEFAULT_TEXTURE, *it);
|
||||
}
|
||||
if (entity.contains(X_TEXTURE_URL_KEY)) {
|
||||
addTextureBaker(X_TEXTURE_URL_KEY, entity[X_TEXTURE_URL_KEY].toString(), image::TextureUsage::DEFAULT_TEXTURE, *it);
|
||||
}
|
||||
if (entity.contains(Y_TEXTURE_URL_KEY)) {
|
||||
addTextureBaker(Y_TEXTURE_URL_KEY, entity[Y_TEXTURE_URL_KEY].toString(), image::TextureUsage::DEFAULT_TEXTURE, *it);
|
||||
}
|
||||
if (entity.contains(Z_TEXTURE_URL_KEY)) {
|
||||
addTextureBaker(Z_TEXTURE_URL_KEY, entity[Z_TEXTURE_URL_KEY].toString(), image::TextureUsage::DEFAULT_TEXTURE, *it);
|
||||
}
|
||||
if (entity.contains(AMBIENT_LIGHT_KEY)) {
|
||||
auto ambientLight = entity[AMBIENT_LIGHT_KEY].toObject();
|
||||
if (ambientLight.contains(AMBIENT_URL_KEY)) {
|
||||
addTextureBaker(AMBIENT_LIGHT_KEY + "." + AMBIENT_URL_KEY, ambientLight[AMBIENT_URL_KEY].toString(), image::TextureUsage::CUBE_TEXTURE, *it);
|
||||
}
|
||||
}
|
||||
if (entity.contains(SKYBOX_KEY)) {
|
||||
auto skybox = entity[SKYBOX_KEY].toObject();
|
||||
if (skybox.contains(SKYBOX_URL_KEY)) {
|
||||
addTextureBaker(SKYBOX_KEY + "." + SKYBOX_URL_KEY, skybox[SKYBOX_URL_KEY].toString(), image::TextureUsage::CUBE_TEXTURE, *it);
|
||||
}
|
||||
}
|
||||
|
||||
// Scripts
|
||||
if (entity.contains(SCRIPT_KEY)) {
|
||||
addScriptBaker(SCRIPT_KEY, entity[SCRIPT_KEY].toString(), *it);
|
||||
}
|
||||
if (entity.contains(SERVER_SCRIPTS_KEY)) {
|
||||
// TODO: serverScripts can be multiple scripts, need to handle that
|
||||
}
|
||||
|
||||
// Materials
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,48 +352,6 @@ void DomainBaker::enumerateEntities() {
|
|||
emit bakeProgress(0, _totalNumberOfSubBakes);
|
||||
}
|
||||
|
||||
void DomainBaker::bakeSkybox(QUrl skyboxURL, QJsonValueRef entity) {
|
||||
|
||||
auto skyboxFileName = skyboxURL.fileName();
|
||||
|
||||
static const QStringList BAKEABLE_SKYBOX_EXTENSIONS {
|
||||
".jpg", ".png", ".gif", ".bmp", ".pbm", ".pgm", ".ppm", ".xbm", ".xpm", ".svg"
|
||||
};
|
||||
auto completeLowerExtension = skyboxFileName.mid(skyboxFileName.indexOf('.')).toLower();
|
||||
|
||||
if (BAKEABLE_SKYBOX_EXTENSIONS.contains(completeLowerExtension)) {
|
||||
// grab a clean version of the URL without a query or fragment
|
||||
skyboxURL = skyboxURL.adjusted(QUrl::RemoveQuery | QUrl::RemoveFragment);
|
||||
|
||||
// setup a texture baker for this URL, as long as we aren't baking a skybox already
|
||||
if (!_skyboxBakers.contains(skyboxURL)) {
|
||||
// setup a baker for this skybox
|
||||
|
||||
QSharedPointer<TextureBaker> skyboxBaker {
|
||||
new TextureBaker(skyboxURL, image::TextureUsage::CUBE_TEXTURE, _contentOutputPath),
|
||||
&TextureBaker::deleteLater
|
||||
};
|
||||
|
||||
// make sure our handler is called when the skybox baker is done
|
||||
connect(skyboxBaker.data(), &TextureBaker::finished, this, &DomainBaker::handleFinishedSkyboxBaker);
|
||||
|
||||
// insert it into our bakers hash so we hold a strong pointer to it
|
||||
_skyboxBakers.insert(skyboxURL, skyboxBaker);
|
||||
|
||||
// move the baker to a worker thread and kickoff the bake
|
||||
skyboxBaker->moveToThread(Oven::instance().getNextWorkerThread());
|
||||
QMetaObject::invokeMethod(skyboxBaker.data(), "bake");
|
||||
|
||||
// keep track of the total number of baking entities
|
||||
++_totalNumberOfSubBakes;
|
||||
}
|
||||
|
||||
// add this QJsonValueRef to our multi hash so that it can re-write the skybox URL
|
||||
// to the baked version once the baker is complete
|
||||
_entitiesNeedingRewrite.insert(skyboxURL, entity);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainBaker::handleFinishedModelBaker() {
|
||||
auto baker = qobject_cast<ModelBaker*>(sender());
|
||||
|
||||
|
@ -275,62 +360,51 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
// this FBXBaker is done and everything went according to plan
|
||||
qDebug() << "Re-writing entity references to" << baker->getModelURL();
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this FBX from our multi hash of
|
||||
// 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);
|
||||
}
|
||||
QUrl newURL = _destinationPath.resolved(relativeFBXFilePath);
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this model from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getModelURL())) {
|
||||
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getModelURL())) {
|
||||
QString property = propertyEntityPair.first;
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = entityValue.toObject();
|
||||
auto entity = propertyEntityPair.second.toObject();
|
||||
|
||||
// grab the old URL
|
||||
QUrl oldModelURL { entity[ENTITY_MODEL_URL_KEY].toString() };
|
||||
if (!property.contains(".")) {
|
||||
// grab the old URL
|
||||
QUrl oldURL = entity[property].toString();
|
||||
|
||||
// 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);
|
||||
// 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
|
||||
entity[property] = newURL.toString();
|
||||
} else {
|
||||
// Group property
|
||||
QStringList propertySplit = property.split(".");
|
||||
assert(propertySplit.length() == 2);
|
||||
// grab the old URL
|
||||
auto oldObject = entity[propertySplit[0]].toObject();
|
||||
QUrl oldURL = oldObject[propertySplit[1]].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
|
||||
oldObject[propertySplit[1]] = newURL.toString();
|
||||
entity[propertySplit[0]] = oldObject;
|
||||
}
|
||||
QUrl newModelURL = _destinationPath.resolved(relativeFBXFilePath);
|
||||
|
||||
// copy the fragment and query, and user info from the old model URL
|
||||
newModelURL.setQuery(oldModelURL.query());
|
||||
newModelURL.setFragment(oldModelURL.fragment());
|
||||
newModelURL.setUserInfo(oldModelURL.userInfo());
|
||||
|
||||
// set the new model URL as the value in our temp QJsonObject
|
||||
entity[ENTITY_MODEL_URL_KEY] = newModelURL.toString();
|
||||
|
||||
// check if the entity also had an animation at the same URL
|
||||
// in which case it should be replaced with our baked model URL too
|
||||
const QString ENTITY_ANIMATION_KEY = "animation";
|
||||
const QString ENTITIY_ANIMATION_URL_KEY = "url";
|
||||
|
||||
if (entity.contains(ENTITY_ANIMATION_KEY)) {
|
||||
auto animationObject = entity[ENTITY_ANIMATION_KEY].toObject();
|
||||
|
||||
if (animationObject.contains(ENTITIY_ANIMATION_URL_KEY)) {
|
||||
// grab the old animation URL
|
||||
QUrl oldAnimationURL { animationObject[ENTITIY_ANIMATION_URL_KEY].toString() };
|
||||
|
||||
// check if its stripped down version matches our stripped down model URL
|
||||
if (oldAnimationURL.matches(oldModelURL, QUrl::RemoveQuery | QUrl::RemoveFragment)) {
|
||||
// the animation URL matched the old model URL, so make the animation URL point to the baked FBX
|
||||
// with its original query and fragment
|
||||
auto newAnimationURL = _destinationPath.resolved(relativeFBXFilePath);
|
||||
newAnimationURL.setQuery(oldAnimationURL.query());
|
||||
newAnimationURL.setFragment(oldAnimationURL.fragment());
|
||||
newAnimationURL.setUserInfo(oldAnimationURL.userInfo());
|
||||
|
||||
animationObject[ENTITIY_ANIMATION_URL_KEY] = newAnimationURL.toString();
|
||||
|
||||
// replace the animation object in the entity object
|
||||
entity[ENTITY_ANIMATION_KEY] = animationObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace our temp object with the value referenced by our QJsonValueRef
|
||||
entityValue = entity;
|
||||
propertyEntityPair.second = entity;
|
||||
}
|
||||
} else {
|
||||
// this model failed to bake - this doesn't fail the entire bake but we need to add
|
||||
|
@ -352,7 +426,7 @@ void DomainBaker::handleFinishedModelBaker() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainBaker::handleFinishedSkyboxBaker() {
|
||||
void DomainBaker::handleFinishedTextureBaker() {
|
||||
auto baker = qobject_cast<TextureBaker*>(sender());
|
||||
|
||||
if (baker) {
|
||||
|
@ -360,36 +434,46 @@ void DomainBaker::handleFinishedSkyboxBaker() {
|
|||
// this FBXBaker is done and everything went according to plan
|
||||
qDebug() << "Re-writing entity references to" << baker->getTextureURL();
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this FBX from our multi hash of
|
||||
auto newURL = _destinationPath.resolved(baker->getMetaTextureFileName());
|
||||
|
||||
// enumerate the QJsonRef values for the URL of this texture from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (QJsonValueRef entityValue : _entitiesNeedingRewrite.values(baker->getTextureURL())) {
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getTextureURL())) {
|
||||
QString property = propertyEntityPair.first;
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = entityValue.toObject();
|
||||
auto entity = propertyEntityPair.second.toObject();
|
||||
|
||||
if (entity.contains(ENTITY_SKYBOX_KEY)) {
|
||||
auto skyboxObject = entity[ENTITY_SKYBOX_KEY].toObject();
|
||||
if (!property.contains(".")) {
|
||||
// grab the old URL
|
||||
QUrl oldURL = entity[property].toString();
|
||||
|
||||
if (skyboxObject.contains(ENTITY_SKYBOX_URL_KEY)) {
|
||||
if (rewriteSkyboxURL(skyboxObject[ENTITY_SKYBOX_URL_KEY], baker)) {
|
||||
// we re-wrote the URL, replace the skybox object referenced by the entity object
|
||||
entity[ENTITY_SKYBOX_KEY] = skyboxObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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());
|
||||
|
||||
if (entity.contains(ENTITY_KEYLIGHT_KEY)) {
|
||||
auto ambientObject = entity[ENTITY_KEYLIGHT_KEY].toObject();
|
||||
// set the new URL as the value in our temp QJsonObject
|
||||
entity[property] = newURL.toString();
|
||||
} else {
|
||||
// Group property
|
||||
QStringList propertySplit = property.split(".");
|
||||
assert(propertySplit.length() == 2);
|
||||
// grab the old URL
|
||||
auto oldObject = entity[propertySplit[0]].toObject();
|
||||
QUrl oldURL = oldObject[propertySplit[1]].toString();
|
||||
|
||||
if (ambientObject.contains(ENTITY_KEYLIGHT_AMBIENT_URL_KEY)) {
|
||||
if (rewriteSkyboxURL(ambientObject[ENTITY_KEYLIGHT_AMBIENT_URL_KEY], baker)) {
|
||||
// we re-wrote the URL, replace the ambient object referenced by the entity object
|
||||
entity[ENTITY_KEYLIGHT_KEY] = ambientObject;
|
||||
}
|
||||
}
|
||||
// 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
|
||||
oldObject[propertySplit[1]] = newURL.toString();
|
||||
entity[propertySplit[0]] = oldObject;
|
||||
}
|
||||
|
||||
// replace our temp object with the value referenced by our QJsonValueRef
|
||||
entityValue = entity;
|
||||
propertyEntityPair.second = entity;
|
||||
}
|
||||
} else {
|
||||
// this skybox failed to bake - this doesn't fail the entire bake but we need to add the errors from
|
||||
|
@ -401,7 +485,7 @@ void DomainBaker::handleFinishedSkyboxBaker() {
|
|||
_entitiesNeedingRewrite.remove(baker->getTextureURL());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_skyboxBakers.remove(baker->getTextureURL());
|
||||
_textureBakers.remove(baker->getTextureURL());
|
||||
|
||||
// emit progress to tell listeners how many models we have baked
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
@ -411,23 +495,72 @@ void DomainBaker::handleFinishedSkyboxBaker() {
|
|||
}
|
||||
}
|
||||
|
||||
bool DomainBaker::rewriteSkyboxURL(QJsonValueRef urlValue, TextureBaker* baker) {
|
||||
// grab the old skybox URL
|
||||
QUrl oldSkyboxURL { urlValue.toString() };
|
||||
void DomainBaker::handleFinishedScriptBaker() {
|
||||
auto baker = qobject_cast<JSBaker*>(sender());
|
||||
|
||||
if (oldSkyboxURL.matches(baker->getTextureURL(), QUrl::RemoveQuery | QUrl::RemoveFragment)) {
|
||||
// change the URL to point to the baked texture with its original query and fragment
|
||||
if (baker) {
|
||||
if (!baker->hasErrors()) {
|
||||
// this FBXBaker is done and everything went according to plan
|
||||
qDebug() << "Re-writing entity references to" << baker->getJSPath();
|
||||
|
||||
auto newSkyboxURL = _destinationPath.resolved(baker->getMetaTextureFileName());
|
||||
newSkyboxURL.setQuery(oldSkyboxURL.query());
|
||||
newSkyboxURL.setFragment(oldSkyboxURL.fragment());
|
||||
newSkyboxURL.setUserInfo(oldSkyboxURL.userInfo());
|
||||
auto newURL = _destinationPath.resolved(baker->getBakedJSFilePath());
|
||||
|
||||
urlValue = newSkyboxURL.toString();
|
||||
// enumerate the QJsonRef values for the URL of this script from our multi hash of
|
||||
// entity objects needing a URL re-write
|
||||
for (auto propertyEntityPair : _entitiesNeedingRewrite.values(baker->getJSPath())) {
|
||||
QString property = propertyEntityPair.first;
|
||||
// convert the entity QJsonValueRef to a QJsonObject so we can modify its URL
|
||||
auto entity = propertyEntityPair.second.toObject();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
if (!property.contains(".")) {
|
||||
// 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
|
||||
entity[property] = newURL.toString();
|
||||
} else {
|
||||
// Group property
|
||||
QStringList propertySplit = property.split(".");
|
||||
assert(propertySplit.length() == 2);
|
||||
// grab the old URL
|
||||
auto oldObject = entity[propertySplit[0]].toObject();
|
||||
QUrl oldURL = oldObject[propertySplit[1]].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
|
||||
oldObject[propertySplit[1]] = newURL.toString();
|
||||
entity[propertySplit[0]] = oldObject;
|
||||
}
|
||||
|
||||
// replace our temp object with the value referenced by our QJsonValueRef
|
||||
propertyEntityPair.second = entity;
|
||||
}
|
||||
} else {
|
||||
// this model failed to bake - this doesn't fail the entire bake but we need to add
|
||||
// the errors from the model to our warnings
|
||||
_warningList << baker->getErrors();
|
||||
}
|
||||
|
||||
// remove the baked URL from the multi hash of entities needing a re-write
|
||||
_entitiesNeedingRewrite.remove(baker->getJSPath());
|
||||
|
||||
// drop our shared pointer to this baker so that it gets cleaned up
|
||||
_scriptBakers.remove(baker->getJSPath());
|
||||
|
||||
// emit progress to tell listeners how many models we have baked
|
||||
emit bakeProgress(++_completedSubBakes, _totalNumberOfSubBakes);
|
||||
|
||||
// check if this was the last model we needed to re-write and if we are done now
|
||||
checkIfRewritingComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,4 +613,3 @@ void DomainBaker::writeNewEntitiesFile() {
|
|||
|
||||
qDebug() << "Exported entities file with baked model URLs to" << bakedEntitiesFilePath;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
#include <QtCore/QThread>
|
||||
|
||||
#include "Baker.h"
|
||||
#include "FBXBaker.h"
|
||||
#include "ModelBaker.h"
|
||||
#include "TextureBaker.h"
|
||||
#include "JSBaker.h"
|
||||
|
||||
class DomainBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
@ -38,7 +39,8 @@ signals:
|
|||
private slots:
|
||||
virtual void bake() override;
|
||||
void handleFinishedModelBaker();
|
||||
void handleFinishedSkyboxBaker();
|
||||
void handleFinishedTextureBaker();
|
||||
void handleFinishedScriptBaker();
|
||||
|
||||
private:
|
||||
void setupOutputFolder();
|
||||
|
@ -47,9 +49,6 @@ private:
|
|||
void checkIfRewritingComplete();
|
||||
void writeNewEntitiesFile();
|
||||
|
||||
void bakeSkybox(QUrl skyboxURL, QJsonValueRef entity);
|
||||
bool rewriteSkyboxURL(QJsonValueRef urlValue, TextureBaker* baker);
|
||||
|
||||
QUrl _localEntitiesFileURL;
|
||||
QString _domainName;
|
||||
QString _baseOutputPath;
|
||||
|
@ -62,14 +61,17 @@ private:
|
|||
QJsonArray _entities;
|
||||
|
||||
QHash<QUrl, QSharedPointer<ModelBaker>> _modelBakers;
|
||||
QHash<QUrl, QSharedPointer<TextureBaker>> _skyboxBakers;
|
||||
QHash<QUrl, QSharedPointer<TextureBaker>> _textureBakers;
|
||||
QHash<QUrl, QSharedPointer<JSBaker>> _scriptBakers;
|
||||
|
||||
QMultiHash<QUrl, QJsonValueRef> _entitiesNeedingRewrite;
|
||||
QMultiHash<QUrl, std::pair<QString, QJsonValueRef>> _entitiesNeedingRewrite;
|
||||
|
||||
int _totalNumberOfSubBakes { 0 };
|
||||
int _completedSubBakes { 0 };
|
||||
|
||||
bool _shouldRebakeOriginals { false };
|
||||
void addModelBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
|
||||
void addTextureBaker(const QString& property, const QString& url, image::TextureUsage::Type type, QJsonValueRef& jsonRef);
|
||||
void addScriptBaker(const QString& property, const QString& url, QJsonValueRef& jsonRef);
|
||||
};
|
||||
|
||||
#endif // hifi_DomainBaker_h
|
||||
|
|
|
@ -116,7 +116,7 @@ void ModelBakeWidget::chooseFileButtonClicked() {
|
|||
startDir = QDir::homePath();
|
||||
}
|
||||
|
||||
auto selectedFiles = QFileDialog::getOpenFileNames(this, "Choose Model", startDir, "Models (*.fbx *.obj)");
|
||||
auto selectedFiles = QFileDialog::getOpenFileNames(this, "Choose Model", startDir, "Models (*.fbx *.obj *.gltf *.fst)");
|
||||
|
||||
if (!selectedFiles.isEmpty()) {
|
||||
// set the contents of the model file text box to be the path to the selected file
|
||||
|
@ -165,21 +165,20 @@ void ModelBakeWidget::bakeButtonClicked() {
|
|||
return;
|
||||
}
|
||||
|
||||
// make sure we have a valid output directory
|
||||
QDir outputDirectory(_outputDirLineEdit->text());
|
||||
if (!outputDirectory.exists()) {
|
||||
QMessageBox::warning(this, "Unable to create directory", "Unable to create output directory. Please create it manually or choose a different directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
// split the list from the model line edit to see how many models we need to bake
|
||||
auto fileURLStrings = _modelLineEdit->text().split(',');
|
||||
foreach (QString fileURLString, fileURLStrings) {
|
||||
// construct a URL from the path in the model file text box
|
||||
QUrl modelToBakeURL(fileURLString);
|
||||
|
||||
// make sure we have a valid output directory
|
||||
QDir outputDirectory(_outputDirLineEdit->text());
|
||||
if (!outputDirectory.exists()) {
|
||||
QMessageBox::warning(this, "Unable to create directory", "Unable to create output directory. Please create it manually or choose a different directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl bakeableModelURL = getBakeableModelURL(QUrl(modelToBakeURL), false);
|
||||
|
||||
QUrl bakeableModelURL = getBakeableModelURL(QUrl(modelToBakeURL));
|
||||
if (!bakeableModelURL.isEmpty()) {
|
||||
auto getWorkerThreadCallback = []() -> QThread* {
|
||||
return Oven::instance().getNextWorkerThread();
|
||||
|
|
Loading…
Reference in a new issue