mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 06:38:40 +02:00
Fix coding guideline violations in *Baker classes
This commit is contained in:
parent
730202b7fc
commit
dd2d3d97b4
6 changed files with 165 additions and 192 deletions
|
@ -40,32 +40,8 @@ FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXBaker::~FBXBaker() {
|
|
||||||
if (modelTempDir.exists()) {
|
|
||||||
if (!modelTempDir.remove(originalModelFilePath)) {
|
|
||||||
qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << originalModelFilePath;
|
|
||||||
}
|
|
||||||
if (!modelTempDir.rmdir(".")) {
|
|
||||||
qCWarning(model_baking) << "Failed to remove temporary directory:" << modelTempDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBXBaker::bake() {
|
void FBXBaker::bake() {
|
||||||
qDebug() << "FBXBaker" << modelURL << "bake starting";
|
qDebug() << "FBXBaker" << _modelURL << "bake starting";
|
||||||
|
|
||||||
auto tempDir = PathUtils::generateTemporaryDir();
|
|
||||||
|
|
||||||
if (tempDir.isEmpty()) {
|
|
||||||
handleError("Failed to create a temporary directory.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
modelTempDir = tempDir;
|
|
||||||
|
|
||||||
originalModelFilePath = modelTempDir.filePath(modelURL.fileName());
|
|
||||||
qDebug() << "Made temporary dir " << modelTempDir;
|
|
||||||
qDebug() << "Origin file path: " << originalModelFilePath;
|
|
||||||
|
|
||||||
// setup the output folder for the results of this bake
|
// setup the output folder for the results of this bake
|
||||||
setupOutputFolder();
|
setupOutputFolder();
|
||||||
|
@ -114,19 +90,19 @@ void FBXBaker::bakeSourceCopy() {
|
||||||
|
|
||||||
void FBXBaker::setupOutputFolder() {
|
void FBXBaker::setupOutputFolder() {
|
||||||
// make sure there isn't already an output directory using the same name
|
// make sure there isn't already an output directory using the same name
|
||||||
if (QDir(bakedOutputDir).exists()) {
|
if (QDir(_bakedOutputDir).exists()) {
|
||||||
qWarning() << "Output path" << bakedOutputDir << "already exists. Continuing.";
|
qWarning() << "Output path" << _bakedOutputDir << "already exists. Continuing.";
|
||||||
} else {
|
} else {
|
||||||
qCDebug(model_baking) << "Creating FBX output folder" << bakedOutputDir;
|
qCDebug(model_baking) << "Creating FBX output folder" << _bakedOutputDir;
|
||||||
|
|
||||||
// attempt to make the output folder
|
// attempt to make the output folder
|
||||||
if (!QDir().mkpath(bakedOutputDir)) {
|
if (!QDir().mkpath(_bakedOutputDir)) {
|
||||||
handleError("Failed to create FBX output folder " + bakedOutputDir);
|
handleError("Failed to create FBX output folder " + _bakedOutputDir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// attempt to make the output folder
|
// attempt to make the output folder
|
||||||
if (!QDir().mkpath(originalOutputDir)) {
|
if (!QDir().mkpath(_originalOutputDir)) {
|
||||||
handleError("Failed to create FBX output folder " + bakedOutputDir);
|
handleError("Failed to create FBX output folder " + _bakedOutputDir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,25 +110,25 @@ void FBXBaker::setupOutputFolder() {
|
||||||
|
|
||||||
void FBXBaker::loadSourceFBX() {
|
void FBXBaker::loadSourceFBX() {
|
||||||
// check if the FBX is local or first needs to be downloaded
|
// check if the FBX is local or first needs to be downloaded
|
||||||
if (modelURL.isLocalFile()) {
|
if (_modelURL.isLocalFile()) {
|
||||||
// load up the local file
|
// load up the local file
|
||||||
QFile localFBX { modelURL.toLocalFile() };
|
QFile localFBX { _modelURL.toLocalFile() };
|
||||||
|
|
||||||
qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << originalModelFilePath;
|
qDebug() << "Local file url: " << _modelURL << _modelURL.toString() << _modelURL.toLocalFile() << ", copying to: " << _originalModelFilePath;
|
||||||
|
|
||||||
if (!localFBX.exists()) {
|
if (!localFBX.exists()) {
|
||||||
//QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), "");
|
//QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), "");
|
||||||
handleError("Could not find " + modelURL.toString());
|
handleError("Could not find " + _modelURL.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a copy in the output folder
|
// make a copy in the output folder
|
||||||
if (!originalOutputDir.isEmpty()) {
|
if (!_originalOutputDir.isEmpty()) {
|
||||||
qDebug() << "Copying to: " << originalOutputDir << "/" << modelURL.fileName();
|
qDebug() << "Copying to: " << _originalOutputDir << "/" << _modelURL.fileName();
|
||||||
localFBX.copy(originalOutputDir + "/" + modelURL.fileName());
|
localFBX.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
localFBX.copy(originalModelFilePath);
|
localFBX.copy(_originalModelFilePath);
|
||||||
|
|
||||||
// emit our signal to start the import of the FBX source copy
|
// emit our signal to start the import of the FBX source copy
|
||||||
emit sourceCopyReadyToLoad();
|
emit sourceCopyReadyToLoad();
|
||||||
|
@ -167,9 +143,9 @@ void FBXBaker::loadSourceFBX() {
|
||||||
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
|
||||||
networkRequest.setUrl(modelURL);
|
networkRequest.setUrl(_modelURL);
|
||||||
|
|
||||||
qCDebug(model_baking) << "Downloading" << modelURL;
|
qCDebug(model_baking) << "Downloading" << _modelURL;
|
||||||
auto networkReply = networkAccessManager.get(networkRequest);
|
auto networkReply = networkAccessManager.get(networkRequest);
|
||||||
|
|
||||||
connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply);
|
connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply);
|
||||||
|
@ -180,53 +156,53 @@ void FBXBaker::handleFBXNetworkReply() {
|
||||||
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
if (requestReply->error() == QNetworkReply::NoError) {
|
if (requestReply->error() == QNetworkReply::NoError) {
|
||||||
qCDebug(model_baking) << "Downloaded" << modelURL;
|
qCDebug(model_baking) << "Downloaded" << _modelURL;
|
||||||
|
|
||||||
// grab the contents of the reply and make a copy in the output folder
|
// grab the contents of the reply and make a copy in the output folder
|
||||||
QFile copyOfOriginal(originalModelFilePath);
|
QFile copyOfOriginal(_originalModelFilePath);
|
||||||
|
|
||||||
qDebug(model_baking) << "Writing copy of original FBX to" << originalModelFilePath << copyOfOriginal.fileName();
|
qDebug(model_baking) << "Writing copy of original FBX to" << _originalModelFilePath << copyOfOriginal.fileName();
|
||||||
|
|
||||||
if (!copyOfOriginal.open(QIODevice::WriteOnly)) {
|
if (!copyOfOriginal.open(QIODevice::WriteOnly)) {
|
||||||
// add an error to the error list for this FBX stating that a duplicate of the original FBX could not be made
|
// add an error to the error list for this FBX stating that a duplicate of the original FBX could not be made
|
||||||
handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + originalModelFilePath + ")");
|
handleError("Could not create copy of " + _modelURL.toString() + " (Failed to open " + _originalModelFilePath + ")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (copyOfOriginal.write(requestReply->readAll()) == -1) {
|
if (copyOfOriginal.write(requestReply->readAll()) == -1) {
|
||||||
handleError("Could not create copy of " + modelURL.toString() + " (Failed to write)");
|
handleError("Could not create copy of " + _modelURL.toString() + " (Failed to write)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close that file now that we are done writing to it
|
// close that file now that we are done writing to it
|
||||||
copyOfOriginal.close();
|
copyOfOriginal.close();
|
||||||
|
|
||||||
if (!originalOutputDir.isEmpty()) {
|
if (!_originalOutputDir.isEmpty()) {
|
||||||
copyOfOriginal.copy(originalOutputDir + "/" + modelURL.fileName());
|
copyOfOriginal.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit our signal to start the import of the FBX source copy
|
// emit our signal to start the import of the FBX source copy
|
||||||
emit sourceCopyReadyToLoad();
|
emit sourceCopyReadyToLoad();
|
||||||
} else {
|
} else {
|
||||||
// add an error to our list stating that the FBX could not be downloaded
|
// add an error to our list stating that the FBX could not be downloaded
|
||||||
handleError("Failed to download " + modelURL.toString());
|
handleError("Failed to download " + _modelURL.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXBaker::importScene() {
|
void FBXBaker::importScene() {
|
||||||
qDebug() << "file path: " << originalModelFilePath.toLocal8Bit().data() << QDir(originalModelFilePath).exists();
|
qDebug() << "file path: " << _originalModelFilePath.toLocal8Bit().data() << QDir(_originalModelFilePath).exists();
|
||||||
|
|
||||||
QFile fbxFile(originalModelFilePath);
|
QFile fbxFile(_originalModelFilePath);
|
||||||
if (!fbxFile.open(QIODevice::ReadOnly)) {
|
if (!fbxFile.open(QIODevice::ReadOnly)) {
|
||||||
handleError("Error opening " + originalModelFilePath + " for reading");
|
handleError("Error opening " + _originalModelFilePath + " for reading");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXReader reader;
|
FBXReader reader;
|
||||||
|
|
||||||
qCDebug(model_baking) << "Parsing" << modelURL;
|
qCDebug(model_baking) << "Parsing" << _modelURL;
|
||||||
_rootNode = reader._rootNode = reader.parseFBX(&fbxFile);
|
_rootNode = reader._rootNode = reader.parseFBX(&fbxFile);
|
||||||
_geometry = reader.extractFBXGeometry({}, modelURL.toString());
|
_geometry = reader.extractFBXGeometry({}, _modelURL.toString());
|
||||||
textureContentMap = reader._textureContent;
|
_textureContentMap = reader._textureContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXBaker::rewriteAndBakeSceneModels() {
|
void FBXBaker::rewriteAndBakeSceneModels() {
|
||||||
|
@ -388,24 +364,24 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||||
|
|
||||||
void FBXBaker::exportScene() {
|
void FBXBaker::exportScene() {
|
||||||
// save the relative path to this FBX inside our passed output folder
|
// save the relative path to this FBX inside our passed output folder
|
||||||
auto fileName = modelURL.fileName();
|
auto fileName = _modelURL.fileName();
|
||||||
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||||
auto bakedFilename = baseName + BAKED_FBX_EXTENSION;
|
auto bakedFilename = baseName + BAKED_FBX_EXTENSION;
|
||||||
|
|
||||||
bakedModelFilePath = bakedOutputDir + "/" + bakedFilename;
|
_bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||||
|
|
||||||
auto fbxData = FBXWriter::encodeFBX(_rootNode);
|
auto fbxData = FBXWriter::encodeFBX(_rootNode);
|
||||||
|
|
||||||
QFile bakedFile(bakedModelFilePath);
|
QFile bakedFile(_bakedModelFilePath);
|
||||||
|
|
||||||
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||||
handleError("Error opening " + bakedModelFilePath + " for writing");
|
handleError("Error opening " + _bakedModelFilePath + " for writing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bakedFile.write(fbxData);
|
bakedFile.write(fbxData);
|
||||||
|
|
||||||
_outputFiles.push_back(bakedModelFilePath);
|
_outputFiles.push_back(_bakedModelFilePath);
|
||||||
|
|
||||||
qCDebug(model_baking) << "Exported" << modelURL << "with re-written paths to" << bakedModelFilePath;
|
qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,9 @@ class FBXBaker : public ModelBaker {
|
||||||
public:
|
public:
|
||||||
FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
||||||
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
||||||
~FBXBaker() override;
|
|
||||||
|
|
||||||
QUrl getFBXUrl() const { return modelURL; }
|
QUrl getFBXUrl() const { return _modelURL; }
|
||||||
QString getBakedFBXFilePath() const { return bakedModelFilePath; }
|
QString getBakedFBXFilePath() const { return _bakedModelFilePath; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void bake() override;
|
virtual void bake() override;
|
||||||
|
|
|
@ -30,12 +30,35 @@
|
||||||
|
|
||||||
ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory) :
|
const QString& bakedOutputDirectory, const QString& originalOutputDirectory) :
|
||||||
modelURL(inputModelURL),
|
_modelURL(inputModelURL),
|
||||||
textureThreadGetter(inputTextureThreadGetter),
|
_textureThreadGetter(inputTextureThreadGetter),
|
||||||
bakedOutputDir(bakedOutputDirectory),
|
_bakedOutputDir(bakedOutputDirectory),
|
||||||
originalOutputDir(originalOutputDirectory)
|
_originalOutputDir(originalOutputDirectory)
|
||||||
{
|
{
|
||||||
|
auto tempDir = PathUtils::generateTemporaryDir();
|
||||||
|
|
||||||
|
if (tempDir.isEmpty()) {
|
||||||
|
handleError("Failed to create a temporary directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_modelTempDir = tempDir;
|
||||||
|
|
||||||
|
_originalModelFilePath = _modelTempDir.filePath(_modelURL.fileName());
|
||||||
|
qDebug() << "Made temporary dir " << _modelTempDir;
|
||||||
|
qDebug() << "Origin file path: " << _originalModelFilePath;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelBaker::~ModelBaker() {
|
||||||
|
if (_modelTempDir.exists()) {
|
||||||
|
if (!_modelTempDir.remove(_originalModelFilePath)) {
|
||||||
|
qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalModelFilePath;
|
||||||
|
}
|
||||||
|
if (!_modelTempDir.rmdir(".")) {
|
||||||
|
qCWarning(model_baking) << "Failed to remove temporary directory:" << _modelTempDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBaker::abort() {
|
void ModelBaker::abort() {
|
||||||
|
@ -43,7 +66,7 @@ void ModelBaker::abort() {
|
||||||
|
|
||||||
// tell our underlying TextureBaker instances to abort
|
// tell our underlying TextureBaker instances to abort
|
||||||
// the ModelBaker will wait until all are aborted before emitting its own abort signal
|
// the ModelBaker will wait until all are aborted before emitting its own abort signal
|
||||||
for (auto& textureBaker : bakingTextures) {
|
for (auto& textureBaker : _bakingTextures) {
|
||||||
textureBaker->abort();
|
textureBaker->abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +274,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
||||||
|
|
||||||
// figure out the URL to this texture, embedded or external
|
// figure out the URL to this texture, embedded or external
|
||||||
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
||||||
textureContent = textureContentMap.value(modelTextureFileName.toLocal8Bit());
|
textureContent = _textureContentMap.value(modelTextureFileName.toLocal8Bit());
|
||||||
}
|
}
|
||||||
auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull());
|
auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull());
|
||||||
|
|
||||||
|
@ -270,16 +293,16 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
||||||
<< "to" << bakedTextureFileName;
|
<< "to" << bakedTextureFileName;
|
||||||
|
|
||||||
QString bakedTextureFilePath{
|
QString bakedTextureFilePath{
|
||||||
bakedOutputDir + "/" + bakedTextureFileName
|
_bakedOutputDir + "/" + bakedTextureFileName
|
||||||
};
|
};
|
||||||
|
|
||||||
textureChild = bakedTextureFileName.toLocal8Bit();
|
textureChild = bakedTextureFileName.toLocal8Bit();
|
||||||
|
|
||||||
if (!bakingTextures.contains(urlToTexture)) {
|
if (!_bakingTextures.contains(urlToTexture)) {
|
||||||
_outputFiles.push_back(bakedTextureFilePath);
|
_outputFiles.push_back(bakedTextureFilePath);
|
||||||
|
|
||||||
// bake this texture asynchronously
|
// bake this texture asynchronously
|
||||||
bakeTexture(urlToTexture, textureType, bakedOutputDir, bakedTextureFileName, textureContent);
|
bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,10 +323,10 @@ void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type t
|
||||||
connect(bakingTexture.data(), &TextureBaker::aborted, this, &ModelBaker::handleAbortedTexture);
|
connect(bakingTexture.data(), &TextureBaker::aborted, this, &ModelBaker::handleAbortedTexture);
|
||||||
|
|
||||||
// keep a shared pointer to the baking texture
|
// keep a shared pointer to the baking texture
|
||||||
bakingTextures.insert(textureURL, bakingTexture);
|
_bakingTextures.insert(textureURL, bakingTexture);
|
||||||
|
|
||||||
// start baking the texture on one of our available worker threads
|
// start baking the texture on one of our available worker threads
|
||||||
bakingTexture->moveToThread(textureThreadGetter());
|
bakingTexture->moveToThread(_textureThreadGetter());
|
||||||
QMetaObject::invokeMethod(bakingTexture.data(), "bake");
|
QMetaObject::invokeMethod(bakingTexture.data(), "bake");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +337,7 @@ void ModelBaker::handleBakedTexture() {
|
||||||
if (bakedTexture) {
|
if (bakedTexture) {
|
||||||
if (!shouldStop()) {
|
if (!shouldStop()) {
|
||||||
if (!bakedTexture->hasErrors()) {
|
if (!bakedTexture->hasErrors()) {
|
||||||
if (!originalOutputDir.isEmpty()) {
|
if (!_originalOutputDir.isEmpty()) {
|
||||||
// we've been asked to make copies of the originals, so we need to make copies of this if it is a linked texture
|
// we've been asked to make copies of the originals, so we need to make copies of this if it is a linked texture
|
||||||
|
|
||||||
// use the path to the texture being baked to determine if this was an embedded or a linked texture
|
// use the path to the texture being baked to determine if this was an embedded or a linked texture
|
||||||
|
@ -322,16 +345,16 @@ void ModelBaker::handleBakedTexture() {
|
||||||
// it is embeddded if the texure being baked was inside a folder with the name of the model
|
// it is embeddded if the texure being baked was inside a folder with the name of the model
|
||||||
// since that is the fake URL we provide when baking external textures
|
// since that is the fake URL we provide when baking external textures
|
||||||
|
|
||||||
if (!modelURL.isParentOf(bakedTexture->getTextureURL())) {
|
if (!_modelURL.isParentOf(bakedTexture->getTextureURL())) {
|
||||||
// for linked textures we want to save a copy of original texture beside the original model
|
// for linked textures we want to save a copy of original texture beside the original model
|
||||||
|
|
||||||
qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL();
|
qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL();
|
||||||
|
|
||||||
// check if we have a relative path to use for the texture
|
// check if we have a relative path to use for the texture
|
||||||
auto relativeTexturePath = texturePathRelativeToModel(modelURL, bakedTexture->getTextureURL());
|
auto relativeTexturePath = texturePathRelativeToModel(_modelURL, bakedTexture->getTextureURL());
|
||||||
|
|
||||||
QFile originalTextureFile{
|
QFile originalTextureFile{
|
||||||
originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName()
|
_originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (relativeTexturePath.length() > 0) {
|
if (relativeTexturePath.length() > 0) {
|
||||||
|
@ -340,10 +363,10 @@ void ModelBaker::handleBakedTexture() {
|
||||||
|
|
||||||
if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) {
|
if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) {
|
||||||
qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName()
|
qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName()
|
||||||
<< "for" << modelURL;
|
<< "for" << _modelURL;
|
||||||
} else {
|
} else {
|
||||||
handleError("Could not save original external texture " + originalTextureFile.fileName()
|
handleError("Could not save original external texture " + originalTextureFile.fileName()
|
||||||
+ " for " + modelURL.toString());
|
+ " for " + _modelURL.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +374,7 @@ void ModelBaker::handleBakedTexture() {
|
||||||
|
|
||||||
|
|
||||||
// now that this texture has been baked and handled, we can remove that TextureBaker from our hash
|
// now that this texture has been baked and handled, we can remove that TextureBaker from our hash
|
||||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||||
|
|
||||||
checkIfTexturesFinished();
|
checkIfTexturesFinished();
|
||||||
} else {
|
} else {
|
||||||
|
@ -362,10 +385,10 @@ void ModelBaker::handleBakedTexture() {
|
||||||
_pendingErrorEmission = true;
|
_pendingErrorEmission = true;
|
||||||
|
|
||||||
// now that this texture has been baked, even though it failed, we can remove that TextureBaker from our list
|
// now that this texture has been baked, even though it failed, we can remove that TextureBaker from our list
|
||||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||||
|
|
||||||
// abort any other ongoing texture bakes since we know we'll end up failing
|
// abort any other ongoing texture bakes since we know we'll end up failing
|
||||||
for (auto& bakingTexture : bakingTextures) {
|
for (auto& bakingTexture : _bakingTextures) {
|
||||||
bakingTexture->abort();
|
bakingTexture->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +398,7 @@ void ModelBaker::handleBakedTexture() {
|
||||||
// we have errors to attend to, so we don't do extra processing for this texture
|
// we have errors to attend to, so we don't do extra processing for this texture
|
||||||
// but we do need to remove that TextureBaker from our list
|
// but we do need to remove that TextureBaker from our list
|
||||||
// and then check if we're done with all textures
|
// and then check if we're done with all textures
|
||||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||||
|
|
||||||
checkIfTexturesFinished();
|
checkIfTexturesFinished();
|
||||||
}
|
}
|
||||||
|
@ -387,14 +410,14 @@ void ModelBaker::handleAbortedTexture() {
|
||||||
TextureBaker* bakedTexture = qobject_cast<TextureBaker*>(sender());
|
TextureBaker* bakedTexture = qobject_cast<TextureBaker*>(sender());
|
||||||
|
|
||||||
if (bakedTexture) {
|
if (bakedTexture) {
|
||||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
// since a texture we were baking aborted, our status is also aborted
|
// since a texture we were baking aborted, our status is also aborted
|
||||||
_shouldAbort.store(true);
|
_shouldAbort.store(true);
|
||||||
|
|
||||||
// abort any other ongoing texture bakes since we know we'll end up failing
|
// abort any other ongoing texture bakes since we know we'll end up failing
|
||||||
for (auto& bakingTexture : bakingTextures) {
|
for (auto& bakingTexture : _bakingTextures) {
|
||||||
bakingTexture->abort();
|
bakingTexture->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +431,7 @@ QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativ
|
||||||
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
||||||
|
|
||||||
if (isEmbedded) {
|
if (isEmbedded) {
|
||||||
urlToTexture = modelURL.toString() + "/" + apparentRelativePath.filePath();
|
urlToTexture = _modelURL.toString() + "/" + apparentRelativePath.filePath();
|
||||||
} else {
|
} else {
|
||||||
if (textureFileInfo.exists() && textureFileInfo.isFile()) {
|
if (textureFileInfo.exists() && textureFileInfo.isFile()) {
|
||||||
// set the texture URL to the local texture that we have confirmed exists
|
// set the texture URL to the local texture that we have confirmed exists
|
||||||
|
@ -418,14 +441,14 @@ QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativ
|
||||||
|
|
||||||
// this is a relative file path which will require different handling
|
// this is a relative file path which will require different handling
|
||||||
// depending on the location of the original model
|
// depending on the location of the original model
|
||||||
if (modelURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) {
|
if (_modelURL.isLocalFile() && apparentRelativePath.exists() && apparentRelativePath.isFile()) {
|
||||||
// the absolute path we ran into for the texture in the model exists on this machine
|
// the absolute path we ran into for the texture in the model exists on this machine
|
||||||
// so use that file
|
// so use that file
|
||||||
urlToTexture = QUrl::fromLocalFile(apparentRelativePath.absoluteFilePath());
|
urlToTexture = QUrl::fromLocalFile(apparentRelativePath.absoluteFilePath());
|
||||||
} else {
|
} else {
|
||||||
// we didn't find the texture on this machine at the absolute path
|
// we didn't find the texture on this machine at the absolute path
|
||||||
// so assume that it is right beside the model to match the behaviour of interface
|
// so assume that it is right beside the model to match the behaviour of interface
|
||||||
urlToTexture = modelURL.resolved(apparentRelativePath.fileName());
|
urlToTexture = _modelURL.resolved(apparentRelativePath.fileName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,7 +473,7 @@ void ModelBaker::checkIfTexturesFinished() {
|
||||||
// check if we're done everything we need to do for this model
|
// check if we're done everything we need to do for this model
|
||||||
// and emit our finished signal if we're done
|
// and emit our finished signal if we're done
|
||||||
|
|
||||||
if (bakingTextures.isEmpty()) {
|
if (_bakingTextures.isEmpty()) {
|
||||||
if (shouldStop()) {
|
if (shouldStop()) {
|
||||||
// if we're checking for completion but we have errors
|
// if we're checking for completion but we have errors
|
||||||
// that means one or more of our texture baking operations failed
|
// that means one or more of our texture baking operations failed
|
||||||
|
@ -461,7 +484,7 @@ void ModelBaker::checkIfTexturesFinished() {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(model_baking) << "Finished baking, emitting finished" << modelURL;
|
qCDebug(model_baking) << "Finished baking, emitting finished" << _modelURL;
|
||||||
|
|
||||||
setIsFinished(true);
|
setIsFinished(true);
|
||||||
}
|
}
|
||||||
|
@ -494,7 +517,7 @@ void ModelBaker::setWasAborted(bool wasAborted) {
|
||||||
Baker::setWasAborted(wasAborted);
|
Baker::setWasAborted(wasAborted);
|
||||||
|
|
||||||
if (wasAborted) {
|
if (wasAborted) {
|
||||||
qCDebug(model_baking) << "Aborted baking" << modelURL;
|
qCDebug(model_baking) << "Aborted baking" << _modelURL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,13 @@ using TextureBakerThreadGetter = std::function<QThread*()>;
|
||||||
using getMaterialIDCallback = std::function <int(int)>;
|
using getMaterialIDCallback = std::function <int(int)>;
|
||||||
using getTextureTypeCallback = std::function<image::TextureUsage::Type()>;
|
using getTextureTypeCallback = std::function<image::TextureUsage::Type()>;
|
||||||
|
|
||||||
class ModelBaker : public Baker{
|
class ModelBaker : public Baker {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory);
|
const QString& bakedOutputDirectory, const QString& originalOutputDirectory);
|
||||||
|
virtual ~ModelBaker();
|
||||||
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL);
|
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL);
|
||||||
QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL);
|
QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL);
|
||||||
virtual void setWasAborted(bool wasAborted) override;
|
virtual void setWasAborted(bool wasAborted) override;
|
||||||
|
@ -43,15 +44,13 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void checkIfTexturesFinished();
|
void checkIfTexturesFinished();
|
||||||
|
|
||||||
QHash<QByteArray, QByteArray> textureContentMap;
|
QHash<QByteArray, QByteArray> _textureContentMap;
|
||||||
QUrl modelURL;
|
QUrl _modelURL;
|
||||||
TextureBakerThreadGetter textureThreadGetter;
|
QString _bakedOutputDir;
|
||||||
QString bakedOutputDir;
|
QString _originalOutputDir;
|
||||||
QString originalOutputDir;
|
QString _bakedModelFilePath;
|
||||||
QString bakedModelFilePath;
|
QDir _modelTempDir;
|
||||||
QDir modelTempDir;
|
QString _originalModelFilePath;
|
||||||
QString originalModelFilePath;
|
|
||||||
QMultiHash<QUrl, QSharedPointer<TextureBaker>> bakingTextures;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void abort() override;
|
virtual void abort() override;
|
||||||
|
@ -67,7 +66,8 @@ private:
|
||||||
const QString & bakedFilename, const QByteArray & textureContent);
|
const QString & bakedFilename, const QByteArray & textureContent);
|
||||||
QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL);
|
QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL);
|
||||||
|
|
||||||
|
TextureBakerThreadGetter _textureThreadGetter;
|
||||||
|
QMultiHash<QUrl, QSharedPointer<TextureBaker>> _bakingTextures;
|
||||||
QHash<QString, int> _textureNameMatchCount;
|
QHash<QString, int> _textureNameMatchCount;
|
||||||
QHash<QUrl, QString> _remappedTexturePaths;
|
QHash<QUrl, QString> _remappedTexturePaths;
|
||||||
bool _pendingErrorEmission{ false };
|
bool _pendingErrorEmission{ false };
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "OBJReader.h"
|
#include "OBJReader.h"
|
||||||
#include "FBXWriter.h"
|
#include "FBXWriter.h"
|
||||||
|
|
||||||
const double UNIT_SCALE_FACTOR = 100;
|
const double UNIT_SCALE_FACTOR = 100.0;
|
||||||
const QByteArray PROPERTIES70_NODE_NAME = "Properties70";
|
const QByteArray PROPERTIES70_NODE_NAME = "Properties70";
|
||||||
const QByteArray P_NODE_NAME = "P";
|
const QByteArray P_NODE_NAME = "P";
|
||||||
const QByteArray C_NODE_NAME = "C";
|
const QByteArray C_NODE_NAME = "C";
|
||||||
|
@ -41,33 +41,9 @@ OBJBaker::OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJBaker::~OBJBaker() {
|
|
||||||
if (modelTempDir.exists()) {
|
|
||||||
if (!modelTempDir.remove(originalModelFilePath)) {
|
|
||||||
qCWarning(model_baking) << "Failed to remove temporary copy of OBJ file:" << originalModelFilePath;
|
|
||||||
}
|
|
||||||
if (!modelTempDir.rmdir(".")) {
|
|
||||||
qCWarning(model_baking) << "Failed to remove temporary directory:" << modelTempDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OBJBaker::bake() {
|
void OBJBaker::bake() {
|
||||||
qDebug() << "OBJBaker" << modelURL << "bake starting";
|
qDebug() << "OBJBaker" << _modelURL << "bake starting";
|
||||||
|
|
||||||
auto tempDir = PathUtils::generateTemporaryDir();
|
|
||||||
|
|
||||||
if (tempDir.isEmpty()) {
|
|
||||||
handleError("Failed to create a temporary directory.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
modelTempDir = tempDir;
|
|
||||||
|
|
||||||
originalModelFilePath = modelTempDir.filePath(modelURL.fileName());
|
|
||||||
qDebug() << "Made temporary dir " << modelTempDir;
|
|
||||||
qDebug() << "Origin file path: " << originalModelFilePath;
|
|
||||||
|
|
||||||
// trigger bakeOBJ once OBJ is loaded
|
// trigger bakeOBJ once OBJ is loaded
|
||||||
connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::bakeOBJ);
|
connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::bakeOBJ);
|
||||||
|
|
||||||
|
@ -77,24 +53,24 @@ void OBJBaker::bake() {
|
||||||
|
|
||||||
void OBJBaker::loadOBJ() {
|
void OBJBaker::loadOBJ() {
|
||||||
// check if the OBJ is local or it needs to be downloaded
|
// check if the OBJ is local or it needs to be downloaded
|
||||||
if (modelURL.isLocalFile()) {
|
if (_modelURL.isLocalFile()) {
|
||||||
// loading the local OBJ
|
// loading the local OBJ
|
||||||
QFile localOBJ{ modelURL.toLocalFile() };
|
QFile localOBJ { _modelURL.toLocalFile() };
|
||||||
|
|
||||||
qDebug() << "Local file url: " << modelURL << modelURL.toString() << modelURL.toLocalFile() << ", copying to: " << originalModelFilePath;
|
qDebug() << "Local file url: " << _modelURL << _modelURL.toString() << _modelURL.toLocalFile() << ", copying to: " << _originalModelFilePath;
|
||||||
|
|
||||||
if (!localOBJ.exists()) {
|
if (!localOBJ.exists()) {
|
||||||
handleError("Could not find " + modelURL.toString());
|
handleError("Could not find " + _modelURL.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a copy in the output folder
|
// make a copy in the output folder
|
||||||
if (!originalOutputDir.isEmpty()) {
|
if (!_originalOutputDir.isEmpty()) {
|
||||||
qDebug() << "Copying to: " << originalOutputDir << "/" << modelURL.fileName();
|
qDebug() << "Copying to: " << _originalOutputDir << "/" << _modelURL.fileName();
|
||||||
localOBJ.copy(originalOutputDir + "/" + modelURL.fileName());
|
localOBJ.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
localOBJ.copy(originalModelFilePath);
|
localOBJ.copy(_originalModelFilePath);
|
||||||
|
|
||||||
// local OBJ is loaded emit signal to trigger its baking
|
// local OBJ is loaded emit signal to trigger its baking
|
||||||
emit OBJLoaded();
|
emit OBJLoaded();
|
||||||
|
@ -108,11 +84,11 @@ void OBJBaker::loadOBJ() {
|
||||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
networkRequest.setUrl(modelURL);
|
networkRequest.setUrl(_modelURL);
|
||||||
|
|
||||||
qCDebug(model_baking) << "Downloading" << modelURL;
|
qCDebug(model_baking) << "Downloading" << _modelURL;
|
||||||
auto networkReply = networkAccessManager.get(networkRequest);
|
auto networkReply = networkAccessManager.get(networkRequest);
|
||||||
|
|
||||||
connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply);
|
connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,44 +97,44 @@ void OBJBaker::handleOBJNetworkReply() {
|
||||||
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
if (requestReply->error() == QNetworkReply::NoError) {
|
if (requestReply->error() == QNetworkReply::NoError) {
|
||||||
qCDebug(model_baking) << "Downloaded" << modelURL;
|
qCDebug(model_baking) << "Downloaded" << _modelURL;
|
||||||
|
|
||||||
// grab the contents of the reply and make a copy in the output folder
|
// grab the contents of the reply and make a copy in the output folder
|
||||||
QFile copyOfOriginal(originalModelFilePath);
|
QFile copyOfOriginal(_originalModelFilePath);
|
||||||
|
|
||||||
qDebug(model_baking) << "Writing copy of original obj to" << originalModelFilePath << copyOfOriginal.fileName();
|
qDebug(model_baking) << "Writing copy of original obj to" << _originalModelFilePath << copyOfOriginal.fileName();
|
||||||
|
|
||||||
if (!copyOfOriginal.open(QIODevice::WriteOnly)) {
|
if (!copyOfOriginal.open(QIODevice::WriteOnly)) {
|
||||||
// add an error to the error list for this obj stating that a duplicate of the original obj could not be made
|
// add an error to the error list for this obj stating that a duplicate of the original obj could not be made
|
||||||
handleError("Could not create copy of " + modelURL.toString() + " (Failed to open " + originalModelFilePath + ")");
|
handleError("Could not create copy of " + _modelURL.toString() + " (Failed to open " + _originalModelFilePath + ")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (copyOfOriginal.write(requestReply->readAll()) == -1) {
|
if (copyOfOriginal.write(requestReply->readAll()) == -1) {
|
||||||
handleError("Could not create copy of " + modelURL.toString() + " (Failed to write)");
|
handleError("Could not create copy of " + _modelURL.toString() + " (Failed to write)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close that file now that we are done writing to it
|
// close that file now that we are done writing to it
|
||||||
copyOfOriginal.close();
|
copyOfOriginal.close();
|
||||||
|
|
||||||
if (!originalOutputDir.isEmpty()) {
|
if (!_originalOutputDir.isEmpty()) {
|
||||||
copyOfOriginal.copy(originalOutputDir + "/" + modelURL.fileName());
|
copyOfOriginal.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// remote OBJ is loaded emit signal to trigger its baking
|
// remote OBJ is loaded emit signal to trigger its baking
|
||||||
emit OBJLoaded();
|
emit OBJLoaded();
|
||||||
} else {
|
} else {
|
||||||
// add an error to our list stating that the OBJ could not be downloaded
|
// add an error to our list stating that the OBJ could not be downloaded
|
||||||
handleError("Failed to download " + modelURL.toString());
|
handleError("Failed to download " + _modelURL.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OBJBaker::bakeOBJ() {
|
void OBJBaker::bakeOBJ() {
|
||||||
// Read the OBJ file
|
// Read the OBJ file
|
||||||
QFile objFile(originalModelFilePath);
|
QFile objFile(_originalModelFilePath);
|
||||||
if (!objFile.open(QIODevice::ReadOnly)) {
|
if (!objFile.open(QIODevice::ReadOnly)) {
|
||||||
handleError("Error opening " + originalModelFilePath + " for reading");
|
handleError("Error opening " + _originalModelFilePath + " for reading");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,8 +142,8 @@ void OBJBaker::bakeOBJ() {
|
||||||
|
|
||||||
bool combineParts = true; // set true so that OBJReader reads material info from material library
|
bool combineParts = true; // set true so that OBJReader reads material info from material library
|
||||||
OBJReader reader;
|
OBJReader reader;
|
||||||
FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, modelURL);
|
FBXGeometry* geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL);
|
||||||
|
|
||||||
// Write OBJ Data as FBX tree nodes
|
// Write OBJ Data as FBX tree nodes
|
||||||
FBXNode rootNode;
|
FBXNode rootNode;
|
||||||
createFBXNodeTree(rootNode, *geometry);
|
createFBXNodeTree(rootNode, *geometry);
|
||||||
|
@ -176,25 +152,25 @@ void OBJBaker::bakeOBJ() {
|
||||||
auto encodedFBX = FBXWriter::encodeFBX(rootNode);
|
auto encodedFBX = FBXWriter::encodeFBX(rootNode);
|
||||||
|
|
||||||
// Export as baked FBX
|
// Export as baked FBX
|
||||||
auto fileName = modelURL.fileName();
|
auto fileName = _modelURL.fileName();
|
||||||
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||||
auto bakedFilename = baseName + ".baked.fbx";
|
auto bakedFilename = baseName + ".baked.fbx";
|
||||||
|
|
||||||
bakedModelFilePath = bakedOutputDir + "/" + bakedFilename;
|
_bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||||
|
|
||||||
QFile bakedFile;
|
QFile bakedFile;
|
||||||
bakedFile.setFileName(bakedModelFilePath);
|
bakedFile.setFileName(_bakedModelFilePath);
|
||||||
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||||
handleError("Error opening " + bakedModelFilePath + " for writing");
|
handleError("Error opening " + _bakedModelFilePath + " for writing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bakedFile.write(encodedFBX);
|
bakedFile.write(encodedFBX);
|
||||||
|
|
||||||
// Export successful
|
// Export successful
|
||||||
_outputFiles.push_back(bakedModelFilePath);
|
_outputFiles.push_back(_bakedModelFilePath);
|
||||||
qCDebug(model_baking) << "Exported" << modelURL << "to" << bakedModelFilePath;
|
qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedModelFilePath;
|
||||||
|
|
||||||
// Export done emit finished
|
// Export done emit finished
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +184,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
// Required for Unit Scale Factor
|
// Required for Unit Scale Factor
|
||||||
FBXNode globalSettingsNode;
|
FBXNode globalSettingsNode;
|
||||||
globalSettingsNode.name = GLOBAL_SETTINGS_NODE_NAME;
|
globalSettingsNode.name = GLOBAL_SETTINGS_NODE_NAME;
|
||||||
|
|
||||||
// Setting the tree hierarchy: GlobalSettings -> Properties70 -> P -> Properties
|
// Setting the tree hierarchy: GlobalSettings -> Properties70 -> P -> Properties
|
||||||
FBXNode properties70Node;
|
FBXNode properties70Node;
|
||||||
properties70Node.name = PROPERTIES70_NODE_NAME;
|
properties70Node.name = PROPERTIES70_NODE_NAME;
|
||||||
|
@ -225,10 +201,10 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
FBXNode geometryNode;
|
FBXNode geometryNode;
|
||||||
geometryNode.name = GEOMETRY_NODE_NAME;
|
geometryNode.name = GEOMETRY_NODE_NAME;
|
||||||
setNodeProperties(geometryNode);
|
setNodeProperties(geometryNode);
|
||||||
|
|
||||||
// Compress the mesh information and store in dracoNode
|
// Compress the mesh information and store in dracoNode
|
||||||
bool hasDeformers = false; // No concept of deformers for an OBJ
|
bool hasDeformers = false; // No concept of deformers for an OBJ
|
||||||
FBXNode dracoNode;
|
FBXNode dracoNode;
|
||||||
this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
||||||
geometryNode.children.append(dracoNode);
|
geometryNode.children.append(dracoNode);
|
||||||
|
|
||||||
|
@ -236,12 +212,12 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
FBXNode modelNode;
|
FBXNode modelNode;
|
||||||
modelNode.name = MODEL_NODE_NAME;
|
modelNode.name = MODEL_NODE_NAME;
|
||||||
setNodeProperties(modelNode);
|
setNodeProperties(modelNode);
|
||||||
|
|
||||||
_objectNode.children = { geometryNode, modelNode };
|
_objectNode.children = { geometryNode, modelNode };
|
||||||
|
|
||||||
// Generating Objects node's child - Material node
|
// Generating Objects node's child - Material node
|
||||||
auto meshParts = geometry.meshes[0].parts;
|
auto& meshParts = geometry.meshes[0].parts;
|
||||||
for (auto meshPart : meshParts) {
|
for (auto& meshPart : meshParts) {
|
||||||
FBXNode materialNode;
|
FBXNode materialNode;
|
||||||
materialNode.name = MATERIAL_NODE_NAME;
|
materialNode.name = MATERIAL_NODE_NAME;
|
||||||
if (geometry.materials.size() == 1) {
|
if (geometry.materials.size() == 1) {
|
||||||
|
@ -252,24 +228,24 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
} else {
|
} else {
|
||||||
setMaterialNodeProperties(materialNode, meshPart.materialID, geometry);
|
setMaterialNodeProperties(materialNode, meshPart.materialID, geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
_objectNode.children.append(materialNode);
|
_objectNode.children.append(materialNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generating Texture Node
|
// Generating Texture Node
|
||||||
// iterate through mesh parts and process the associated textures
|
// iterate through mesh parts and process the associated textures
|
||||||
for (int i = 0;i < meshParts.size();i++) {
|
for (int i = 0; i < meshParts.size(); i++) {
|
||||||
QString material = meshParts[i].materialID;
|
QString material = meshParts[i].materialID;
|
||||||
FBXMaterial currentMaterial = geometry.materials[material];
|
FBXMaterial currentMaterial = geometry.materials[material];
|
||||||
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
||||||
_textureID = _nodeID;
|
_textureID = _nodeID;
|
||||||
_mapTextureMaterial.push_back(QPair<qlonglong, int>(_textureID, i));
|
_mapTextureMaterial.push_back(QPair<qlonglong, int>(_textureID, i));
|
||||||
|
|
||||||
FBXNode textureNode;
|
FBXNode textureNode;
|
||||||
textureNode.name = TEXTURE_NODE_NAME;
|
textureNode.name = TEXTURE_NODE_NAME;
|
||||||
QVariant textureProperty(_nodeID++);
|
QVariant textureProperty(_nodeID++);
|
||||||
textureNode.properties = { textureProperty };
|
textureNode.properties = { textureProperty };
|
||||||
|
|
||||||
// Texture node child - TextureName node
|
// Texture node child - TextureName node
|
||||||
FBXNode textureNameNode;
|
FBXNode textureNameNode;
|
||||||
textureNameNode.name = TEXTURENAME_NODE_NAME;
|
textureNameNode.name = TEXTURENAME_NODE_NAME;
|
||||||
|
@ -280,14 +256,14 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
// Texture node child - Relative Filename node
|
// Texture node child - Relative Filename node
|
||||||
FBXNode relativeFilenameNode;
|
FBXNode relativeFilenameNode;
|
||||||
relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME;
|
relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME;
|
||||||
|
|
||||||
QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename;
|
QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename;
|
||||||
|
|
||||||
// Callback to get Texture content and type
|
// Callback to get Texture content and type
|
||||||
getTextureTypeCallback textureContentTypeCallback = [=]() {
|
getTextureTypeCallback textureContentTypeCallback = [=]() {
|
||||||
return (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE;
|
return (!currentMaterial.albedoTexture.filename.isEmpty()) ? image::TextureUsage::Type::ALBEDO_TEXTURE : image::TextureUsage::Type::SPECULAR_TEXTURE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node
|
// Compress the texture using ModelBaker::compressTexture() and store compressed file's name in the node
|
||||||
QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback);
|
QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback);
|
||||||
if (textureFile) {
|
if (textureFile) {
|
||||||
|
@ -297,17 +273,17 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
relativeFilenameNode.properties = { textureProperty };
|
relativeFilenameNode.properties = { textureProperty };
|
||||||
|
|
||||||
textureNode.children = { textureNameNode, relativeFilenameNode };
|
textureNode.children = { textureNameNode, relativeFilenameNode };
|
||||||
|
|
||||||
_objectNode.children.append(textureNode);
|
_objectNode.children.append(textureNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generating Connections node
|
// Generating Connections node
|
||||||
FBXNode connectionsNode;
|
FBXNode connectionsNode;
|
||||||
connectionsNode.name = CONNECTIONS_NODE_NAME;
|
connectionsNode.name = CONNECTIONS_NODE_NAME;
|
||||||
|
|
||||||
// connect Geometry to Model
|
// connect Geometry to Model
|
||||||
FBXNode cNode;
|
FBXNode cNode;
|
||||||
cNode.name = C_NODE_NAME;
|
cNode.name = C_NODE_NAME;
|
||||||
|
@ -321,7 +297,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
connectionsNode.children = { cNode };
|
connectionsNode.children = { cNode };
|
||||||
|
|
||||||
// connect all materials to model
|
// connect all materials to model
|
||||||
for (int i = 0;i < geometry.materials.size();i++) {
|
for (int i = 0; i < geometry.materials.size(); i++) {
|
||||||
FBXNode cNode1;
|
FBXNode cNode1;
|
||||||
cNode1.name = C_NODE_NAME;
|
cNode1.name = C_NODE_NAME;
|
||||||
property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size()));
|
property0 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size()));
|
||||||
|
@ -330,10 +306,10 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
cNode1.properties = { property0, property1, property2 };
|
cNode1.properties = { property0, property1, property2 };
|
||||||
connectionsNode.children.append(cNode1);
|
connectionsNode.children.append(cNode1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect textures to materials
|
// Connect textures to materials
|
||||||
auto mapSize = _mapTextureMaterial.size();
|
auto mapSize = _mapTextureMaterial.size();
|
||||||
for (size_t i = 0;i < mapSize;i++) {
|
for (size_t i = 0; i < mapSize; i++) {
|
||||||
FBXNode cNode2;
|
FBXNode cNode2;
|
||||||
cNode2.name = C_NODE_NAME;
|
cNode2.name = C_NODE_NAME;
|
||||||
propertyString = CONNECTIONS_NODE_PROPERTY_1;
|
propertyString = CONNECTIONS_NODE_PROPERTY_1;
|
||||||
|
@ -357,7 +333,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
cNode3.properties = { property0, property1, property2, property3 };
|
cNode3.properties = { property0, property1, property2, property3 };
|
||||||
connectionsNode.children.append(cNode3);
|
connectionsNode.children.append(cNode3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make all generated nodes children of rootNode
|
// Make all generated nodes children of rootNode
|
||||||
rootNode.children = { globalSettingsNode, _objectNode, connectionsNode };
|
rootNode.children = { globalSettingsNode, _objectNode, connectionsNode };
|
||||||
}
|
}
|
||||||
|
@ -365,8 +341,8 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||||
// Set properties for P Node and Sub-Object nodes
|
// Set properties for P Node and Sub-Object nodes
|
||||||
void OBJBaker::setNodeProperties(FBXNode& parentNode) {
|
void OBJBaker::setNodeProperties(FBXNode& parentNode) {
|
||||||
if (parentNode.name == P_NODE_NAME) {
|
if (parentNode.name == P_NODE_NAME) {
|
||||||
std::vector<QByteArray> stringProperties{ "UnitScaleFactor", "double", "Number", "" };
|
std::vector<QByteArray> stringProperties { "UnitScaleFactor", "double", "Number", "" };
|
||||||
std::vector<double> numericProperties{ UNIT_SCALE_FACTOR };
|
std::vector<double> numericProperties { UNIT_SCALE_FACTOR };
|
||||||
|
|
||||||
setPropertiesList(stringProperties, numericProperties, parentNode.properties);
|
setPropertiesList(stringProperties, numericProperties, parentNode.properties);
|
||||||
} else if (parentNode.name == GEOMETRY_NODE_NAME) {
|
} else if (parentNode.name == GEOMETRY_NODE_NAME) {
|
||||||
|
@ -400,9 +376,9 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material
|
||||||
QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size()));
|
QVariant property2 = QVariant::fromValue(QByteArray(propertyString.data(), (int)propertyString.size()));
|
||||||
|
|
||||||
materialNode.properties = { property0, property1, property2 };
|
materialNode.properties = { property0, property1, property2 };
|
||||||
|
|
||||||
FBXMaterial currentMaterial = geometry.materials[material];
|
FBXMaterial currentMaterial = geometry.materials[material];
|
||||||
|
|
||||||
// Setting the hierarchy: Material -> Properties70 -> P -> Properties
|
// Setting the hierarchy: Material -> Properties70 -> P -> Properties
|
||||||
FBXNode properties70Node;
|
FBXNode properties70Node;
|
||||||
properties70Node.name = PROPERTIES70_NODE_NAME;
|
properties70Node.name = PROPERTIES70_NODE_NAME;
|
||||||
|
@ -411,8 +387,8 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material
|
||||||
FBXNode pNodeDiffuseColor;
|
FBXNode pNodeDiffuseColor;
|
||||||
pNodeDiffuseColor.name = P_NODE_NAME;
|
pNodeDiffuseColor.name = P_NODE_NAME;
|
||||||
|
|
||||||
std::vector<QByteArray> stringProperties{ "DiffuseColor", "Color", "", "A" };
|
std::vector<QByteArray> stringProperties { "DiffuseColor", "Color", "", "A" };
|
||||||
std::vector<double> numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] };
|
std::vector<double> numericProperties { currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] };
|
||||||
setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties);
|
setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties);
|
||||||
|
|
||||||
properties70Node.children.append(pNodeDiffuseColor);
|
properties70Node.children.append(pNodeDiffuseColor);
|
||||||
|
@ -434,7 +410,7 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material
|
||||||
stringProperties = { "Shininess", "Number", "", "A" };
|
stringProperties = { "Shininess", "Number", "", "A" };
|
||||||
numericProperties = { currentMaterial.shininess };
|
numericProperties = { currentMaterial.shininess };
|
||||||
setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties);
|
setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties);
|
||||||
|
|
||||||
properties70Node.children.append(pNodeShininess);
|
properties70Node.children.append(pNodeShininess);
|
||||||
|
|
||||||
// Set Opacity
|
// Set Opacity
|
||||||
|
|
|
@ -25,7 +25,6 @@ class OBJBaker : public ModelBaker {
|
||||||
public:
|
public:
|
||||||
OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter,
|
OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter,
|
||||||
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
||||||
~OBJBaker() override;
|
|
||||||
void loadOBJ();
|
void loadOBJ();
|
||||||
void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry);
|
void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry);
|
||||||
void setNodeProperties(FBXNode& parentNode);
|
void setNodeProperties(FBXNode& parentNode);
|
||||||
|
|
Loading…
Reference in a new issue