mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +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() {
|
||||
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;
|
||||
qDebug() << "FBXBaker" << _modelURL << "bake starting";
|
||||
|
||||
// setup the output folder for the results of this bake
|
||||
setupOutputFolder();
|
||||
|
@ -114,19 +90,19 @@ void FBXBaker::bakeSourceCopy() {
|
|||
|
||||
void FBXBaker::setupOutputFolder() {
|
||||
// make sure there isn't already an output directory using the same name
|
||||
if (QDir(bakedOutputDir).exists()) {
|
||||
qWarning() << "Output path" << bakedOutputDir << "already exists. Continuing.";
|
||||
if (QDir(_bakedOutputDir).exists()) {
|
||||
qWarning() << "Output path" << _bakedOutputDir << "already exists. Continuing.";
|
||||
} else {
|
||||
qCDebug(model_baking) << "Creating FBX output folder" << bakedOutputDir;
|
||||
qCDebug(model_baking) << "Creating FBX output folder" << _bakedOutputDir;
|
||||
|
||||
// attempt to make the output folder
|
||||
if (!QDir().mkpath(bakedOutputDir)) {
|
||||
handleError("Failed to create FBX output folder " + bakedOutputDir);
|
||||
if (!QDir().mkpath(_bakedOutputDir)) {
|
||||
handleError("Failed to create FBX output folder " + _bakedOutputDir);
|
||||
return;
|
||||
}
|
||||
// attempt to make the output folder
|
||||
if (!QDir().mkpath(originalOutputDir)) {
|
||||
handleError("Failed to create FBX output folder " + bakedOutputDir);
|
||||
if (!QDir().mkpath(_originalOutputDir)) {
|
||||
handleError("Failed to create FBX output folder " + _bakedOutputDir);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -134,25 +110,25 @@ void FBXBaker::setupOutputFolder() {
|
|||
|
||||
void FBXBaker::loadSourceFBX() {
|
||||
// check if the FBX is local or first needs to be downloaded
|
||||
if (modelURL.isLocalFile()) {
|
||||
if (_modelURL.isLocalFile()) {
|
||||
// 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()) {
|
||||
//QMessageBox::warning(this, "Could not find " + _fbxURL.toString(), "");
|
||||
handleError("Could not find " + modelURL.toString());
|
||||
handleError("Could not find " + _modelURL.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// make a copy in the output folder
|
||||
if (!originalOutputDir.isEmpty()) {
|
||||
qDebug() << "Copying to: " << originalOutputDir << "/" << modelURL.fileName();
|
||||
localFBX.copy(originalOutputDir + "/" + modelURL.fileName());
|
||||
if (!_originalOutputDir.isEmpty()) {
|
||||
qDebug() << "Copying to: " << _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 sourceCopyReadyToLoad();
|
||||
|
@ -167,9 +143,9 @@ void FBXBaker::loadSourceFBX() {
|
|||
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||
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);
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, this, &FBXBaker::handleFBXNetworkReply);
|
||||
|
@ -180,53 +156,53 @@ void FBXBaker::handleFBXNetworkReply() {
|
|||
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
||||
|
||||
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
|
||||
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)) {
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// close that file now that we are done writing to it
|
||||
copyOfOriginal.close();
|
||||
|
||||
if (!originalOutputDir.isEmpty()) {
|
||||
copyOfOriginal.copy(originalOutputDir + "/" + modelURL.fileName());
|
||||
if (!_originalOutputDir.isEmpty()) {
|
||||
copyOfOriginal.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||
}
|
||||
|
||||
// emit our signal to start the import of the FBX source copy
|
||||
emit sourceCopyReadyToLoad();
|
||||
} else {
|
||||
// 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() {
|
||||
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)) {
|
||||
handleError("Error opening " + originalModelFilePath + " for reading");
|
||||
handleError("Error opening " + _originalModelFilePath + " for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
FBXReader reader;
|
||||
|
||||
qCDebug(model_baking) << "Parsing" << modelURL;
|
||||
qCDebug(model_baking) << "Parsing" << _modelURL;
|
||||
_rootNode = reader._rootNode = reader.parseFBX(&fbxFile);
|
||||
_geometry = reader.extractFBXGeometry({}, modelURL.toString());
|
||||
textureContentMap = reader._textureContent;
|
||||
_geometry = reader.extractFBXGeometry({}, _modelURL.toString());
|
||||
_textureContentMap = reader._textureContent;
|
||||
}
|
||||
|
||||
void FBXBaker::rewriteAndBakeSceneModels() {
|
||||
|
@ -388,24 +364,24 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
|||
|
||||
void FBXBaker::exportScene() {
|
||||
// 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 bakedFilename = baseName + BAKED_FBX_EXTENSION;
|
||||
|
||||
bakedModelFilePath = bakedOutputDir + "/" + bakedFilename;
|
||||
_bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||
|
||||
auto fbxData = FBXWriter::encodeFBX(_rootNode);
|
||||
|
||||
QFile bakedFile(bakedModelFilePath);
|
||||
QFile bakedFile(_bakedModelFilePath);
|
||||
|
||||
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||
handleError("Error opening " + bakedModelFilePath + " for writing");
|
||||
handleError("Error opening " + _bakedModelFilePath + " for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
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:
|
||||
FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
||||
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
||||
~FBXBaker() override;
|
||||
|
||||
QUrl getFBXUrl() const { return modelURL; }
|
||||
QString getBakedFBXFilePath() const { return bakedModelFilePath; }
|
||||
QUrl getFBXUrl() const { return _modelURL; }
|
||||
QString getBakedFBXFilePath() const { return _bakedModelFilePath; }
|
||||
|
||||
public slots:
|
||||
virtual void bake() override;
|
||||
|
|
|
@ -30,12 +30,35 @@
|
|||
|
||||
ModelBaker::ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory) :
|
||||
modelURL(inputModelURL),
|
||||
textureThreadGetter(inputTextureThreadGetter),
|
||||
bakedOutputDir(bakedOutputDirectory),
|
||||
originalOutputDir(originalOutputDirectory)
|
||||
_modelURL(inputModelURL),
|
||||
_textureThreadGetter(inputTextureThreadGetter),
|
||||
_bakedOutputDir(bakedOutputDirectory),
|
||||
_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() {
|
||||
|
@ -43,7 +66,7 @@ void ModelBaker::abort() {
|
|||
|
||||
// tell our underlying TextureBaker instances to abort
|
||||
// the ModelBaker will wait until all are aborted before emitting its own abort signal
|
||||
for (auto& textureBaker : bakingTextures) {
|
||||
for (auto& textureBaker : _bakingTextures) {
|
||||
textureBaker->abort();
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +274,7 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
|||
|
||||
// figure out the URL to this texture, embedded or external
|
||||
if (!modelTextureFileInfo.filePath().isEmpty()) {
|
||||
textureContent = textureContentMap.value(modelTextureFileName.toLocal8Bit());
|
||||
textureContent = _textureContentMap.value(modelTextureFileName.toLocal8Bit());
|
||||
}
|
||||
auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull());
|
||||
|
||||
|
@ -270,16 +293,16 @@ QByteArray* ModelBaker::compressTexture(QString modelTextureFileName, getTexture
|
|||
<< "to" << bakedTextureFileName;
|
||||
|
||||
QString bakedTextureFilePath{
|
||||
bakedOutputDir + "/" + bakedTextureFileName
|
||||
_bakedOutputDir + "/" + bakedTextureFileName
|
||||
};
|
||||
|
||||
textureChild = bakedTextureFileName.toLocal8Bit();
|
||||
|
||||
if (!bakingTextures.contains(urlToTexture)) {
|
||||
if (!_bakingTextures.contains(urlToTexture)) {
|
||||
_outputFiles.push_back(bakedTextureFilePath);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
bakingTexture->moveToThread(textureThreadGetter());
|
||||
bakingTexture->moveToThread(_textureThreadGetter());
|
||||
QMetaObject::invokeMethod(bakingTexture.data(), "bake");
|
||||
}
|
||||
|
||||
|
@ -314,7 +337,7 @@ void ModelBaker::handleBakedTexture() {
|
|||
if (bakedTexture) {
|
||||
if (!shouldStop()) {
|
||||
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
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
||||
qCDebug(model_baking) << "Saving original texture for" << bakedTexture->getTextureURL();
|
||||
|
||||
// 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{
|
||||
originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName()
|
||||
_originalOutputDir + "/" + relativeTexturePath + bakedTexture->getTextureURL().fileName()
|
||||
};
|
||||
|
||||
if (relativeTexturePath.length() > 0) {
|
||||
|
@ -340,10 +363,10 @@ void ModelBaker::handleBakedTexture() {
|
|||
|
||||
if (originalTextureFile.open(QIODevice::WriteOnly) && originalTextureFile.write(bakedTexture->getOriginalTexture()) != -1) {
|
||||
qCDebug(model_baking) << "Saved original texture file" << originalTextureFile.fileName()
|
||||
<< "for" << modelURL;
|
||||
<< "for" << _modelURL;
|
||||
} else {
|
||||
handleError("Could not save original external texture " + originalTextureFile.fileName()
|
||||
+ " for " + modelURL.toString());
|
||||
+ " for " + _modelURL.toString());
|
||||
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
|
||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
|
||||
checkIfTexturesFinished();
|
||||
} else {
|
||||
|
@ -362,10 +385,10 @@ void ModelBaker::handleBakedTexture() {
|
|||
_pendingErrorEmission = true;
|
||||
|
||||
// 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
|
||||
for (auto& bakingTexture : bakingTextures) {
|
||||
for (auto& bakingTexture : _bakingTextures) {
|
||||
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
|
||||
// but we do need to remove that TextureBaker from our list
|
||||
// and then check if we're done with all textures
|
||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
|
||||
checkIfTexturesFinished();
|
||||
}
|
||||
|
@ -387,14 +410,14 @@ void ModelBaker::handleAbortedTexture() {
|
|||
TextureBaker* bakedTexture = qobject_cast<TextureBaker*>(sender());
|
||||
|
||||
if (bakedTexture) {
|
||||
bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
_bakingTextures.remove(bakedTexture->getTextureURL());
|
||||
}
|
||||
|
||||
// since a texture we were baking aborted, our status is also aborted
|
||||
_shouldAbort.store(true);
|
||||
|
||||
// abort any other ongoing texture bakes since we know we'll end up failing
|
||||
for (auto& bakingTexture : bakingTextures) {
|
||||
for (auto& bakingTexture : _bakingTextures) {
|
||||
bakingTexture->abort();
|
||||
}
|
||||
|
||||
|
@ -408,7 +431,7 @@ QUrl ModelBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativ
|
|||
auto apparentRelativePath = QFileInfo(relativeFileName.replace("\\", "/"));
|
||||
|
||||
if (isEmbedded) {
|
||||
urlToTexture = modelURL.toString() + "/" + apparentRelativePath.filePath();
|
||||
urlToTexture = _modelURL.toString() + "/" + apparentRelativePath.filePath();
|
||||
} else {
|
||||
if (textureFileInfo.exists() && textureFileInfo.isFile()) {
|
||||
// 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
|
||||
// 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
|
||||
// so use that file
|
||||
urlToTexture = QUrl::fromLocalFile(apparentRelativePath.absoluteFilePath());
|
||||
} else {
|
||||
// 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
|
||||
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
|
||||
// and emit our finished signal if we're done
|
||||
|
||||
if (bakingTextures.isEmpty()) {
|
||||
if (_bakingTextures.isEmpty()) {
|
||||
if (shouldStop()) {
|
||||
// if we're checking for completion but we have errors
|
||||
// that means one or more of our texture baking operations failed
|
||||
|
@ -461,7 +484,7 @@ void ModelBaker::checkIfTexturesFinished() {
|
|||
|
||||
return;
|
||||
} else {
|
||||
qCDebug(model_baking) << "Finished baking, emitting finished" << modelURL;
|
||||
qCDebug(model_baking) << "Finished baking, emitting finished" << _modelURL;
|
||||
|
||||
setIsFinished(true);
|
||||
}
|
||||
|
@ -494,7 +517,7 @@ void ModelBaker::setWasAborted(bool wasAborted) {
|
|||
Baker::setWasAborted(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 getTextureTypeCallback = std::function<image::TextureUsage::Type()>;
|
||||
|
||||
class ModelBaker : public Baker{
|
||||
class ModelBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModelBaker(const QUrl& inputModelURL, TextureBakerThreadGetter inputTextureThreadGetter,
|
||||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory);
|
||||
virtual ~ModelBaker();
|
||||
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, getMaterialIDCallback materialIDCallback = NULL);
|
||||
QByteArray* compressTexture(QString textureFileName, getTextureTypeCallback textureTypeCallback = NULL);
|
||||
virtual void setWasAborted(bool wasAborted) override;
|
||||
|
@ -43,15 +44,13 @@ public:
|
|||
protected:
|
||||
void checkIfTexturesFinished();
|
||||
|
||||
QHash<QByteArray, QByteArray> textureContentMap;
|
||||
QUrl modelURL;
|
||||
TextureBakerThreadGetter textureThreadGetter;
|
||||
QString bakedOutputDir;
|
||||
QString originalOutputDir;
|
||||
QString bakedModelFilePath;
|
||||
QDir modelTempDir;
|
||||
QString originalModelFilePath;
|
||||
QMultiHash<QUrl, QSharedPointer<TextureBaker>> bakingTextures;
|
||||
QHash<QByteArray, QByteArray> _textureContentMap;
|
||||
QUrl _modelURL;
|
||||
QString _bakedOutputDir;
|
||||
QString _originalOutputDir;
|
||||
QString _bakedModelFilePath;
|
||||
QDir _modelTempDir;
|
||||
QString _originalModelFilePath;
|
||||
|
||||
public slots:
|
||||
virtual void abort() override;
|
||||
|
@ -67,7 +66,8 @@ private:
|
|||
const QString & bakedFilename, const QByteArray & textureContent);
|
||||
QString texturePathRelativeToModel(QUrl modelURL, QUrl textureURL);
|
||||
|
||||
|
||||
TextureBakerThreadGetter _textureThreadGetter;
|
||||
QMultiHash<QUrl, QSharedPointer<TextureBaker>> _bakingTextures;
|
||||
QHash<QString, int> _textureNameMatchCount;
|
||||
QHash<QUrl, QString> _remappedTexturePaths;
|
||||
bool _pendingErrorEmission{ false };
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "OBJReader.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 P_NODE_NAME = "P";
|
||||
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() {
|
||||
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
|
||||
connect(this, &OBJBaker::OBJLoaded, this, &OBJBaker::bakeOBJ);
|
||||
|
||||
|
@ -77,24 +53,24 @@ void OBJBaker::bake() {
|
|||
|
||||
void OBJBaker::loadOBJ() {
|
||||
// check if the OBJ is local or it needs to be downloaded
|
||||
if (modelURL.isLocalFile()) {
|
||||
if (_modelURL.isLocalFile()) {
|
||||
// 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()) {
|
||||
handleError("Could not find " + modelURL.toString());
|
||||
handleError("Could not find " + _modelURL.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// make a copy in the output folder
|
||||
if (!originalOutputDir.isEmpty()) {
|
||||
qDebug() << "Copying to: " << originalOutputDir << "/" << modelURL.fileName();
|
||||
localOBJ.copy(originalOutputDir + "/" + modelURL.fileName());
|
||||
if (!_originalOutputDir.isEmpty()) {
|
||||
qDebug() << "Copying to: " << _originalOutputDir << "/" << _modelURL.fileName();
|
||||
localOBJ.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||
}
|
||||
|
||||
localOBJ.copy(originalModelFilePath);
|
||||
|
||||
localOBJ.copy(_originalModelFilePath);
|
||||
|
||||
// local OBJ is loaded emit signal to trigger its baking
|
||||
emit OBJLoaded();
|
||||
|
@ -108,11 +84,11 @@ void OBJBaker::loadOBJ() {
|
|||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
networkRequest.setUrl(modelURL);
|
||||
|
||||
qCDebug(model_baking) << "Downloading" << modelURL;
|
||||
networkRequest.setUrl(_modelURL);
|
||||
|
||||
qCDebug(model_baking) << "Downloading" << _modelURL;
|
||||
auto networkReply = networkAccessManager.get(networkRequest);
|
||||
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, this, &OBJBaker::handleOBJNetworkReply);
|
||||
}
|
||||
}
|
||||
|
@ -121,44 +97,44 @@ void OBJBaker::handleOBJNetworkReply() {
|
|||
auto requestReply = qobject_cast<QNetworkReply*>(sender());
|
||||
|
||||
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
|
||||
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)) {
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// close that file now that we are done writing to it
|
||||
copyOfOriginal.close();
|
||||
|
||||
if (!originalOutputDir.isEmpty()) {
|
||||
copyOfOriginal.copy(originalOutputDir + "/" + modelURL.fileName());
|
||||
if (!_originalOutputDir.isEmpty()) {
|
||||
copyOfOriginal.copy(_originalOutputDir + "/" + _modelURL.fileName());
|
||||
}
|
||||
|
||||
// remote OBJ is loaded emit signal to trigger its baking
|
||||
emit OBJLoaded();
|
||||
} else {
|
||||
// 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() {
|
||||
// Read the OBJ file
|
||||
QFile objFile(originalModelFilePath);
|
||||
QFile objFile(_originalModelFilePath);
|
||||
if (!objFile.open(QIODevice::ReadOnly)) {
|
||||
handleError("Error opening " + originalModelFilePath + " for reading");
|
||||
handleError("Error opening " + _originalModelFilePath + " for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -166,8 +142,8 @@ void OBJBaker::bakeOBJ() {
|
|||
|
||||
bool combineParts = true; // set true so that OBJReader reads material info from material library
|
||||
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
|
||||
FBXNode rootNode;
|
||||
createFBXNodeTree(rootNode, *geometry);
|
||||
|
@ -176,25 +152,25 @@ void OBJBaker::bakeOBJ() {
|
|||
auto encodedFBX = FBXWriter::encodeFBX(rootNode);
|
||||
|
||||
// Export as baked FBX
|
||||
auto fileName = modelURL.fileName();
|
||||
auto fileName = _modelURL.fileName();
|
||||
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||
auto bakedFilename = baseName + ".baked.fbx";
|
||||
|
||||
bakedModelFilePath = bakedOutputDir + "/" + bakedFilename;
|
||||
_bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||
|
||||
QFile bakedFile;
|
||||
bakedFile.setFileName(bakedModelFilePath);
|
||||
bakedFile.setFileName(_bakedModelFilePath);
|
||||
if (!bakedFile.open(QIODevice::WriteOnly)) {
|
||||
handleError("Error opening " + bakedModelFilePath + " for writing");
|
||||
handleError("Error opening " + _bakedModelFilePath + " for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
bakedFile.write(encodedFBX);
|
||||
|
||||
// Export successful
|
||||
_outputFiles.push_back(bakedModelFilePath);
|
||||
qCDebug(model_baking) << "Exported" << modelURL << "to" << bakedModelFilePath;
|
||||
|
||||
_outputFiles.push_back(_bakedModelFilePath);
|
||||
qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedModelFilePath;
|
||||
|
||||
// Export done emit finished
|
||||
emit finished();
|
||||
}
|
||||
|
@ -208,7 +184,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
// Required for Unit Scale Factor
|
||||
FBXNode globalSettingsNode;
|
||||
globalSettingsNode.name = GLOBAL_SETTINGS_NODE_NAME;
|
||||
|
||||
|
||||
// Setting the tree hierarchy: GlobalSettings -> Properties70 -> P -> Properties
|
||||
FBXNode properties70Node;
|
||||
properties70Node.name = PROPERTIES70_NODE_NAME;
|
||||
|
@ -225,10 +201,10 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
FBXNode geometryNode;
|
||||
geometryNode.name = GEOMETRY_NODE_NAME;
|
||||
setNodeProperties(geometryNode);
|
||||
|
||||
|
||||
// Compress the mesh information and store in dracoNode
|
||||
bool hasDeformers = false; // No concept of deformers for an OBJ
|
||||
FBXNode dracoNode;
|
||||
FBXNode dracoNode;
|
||||
this->compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
||||
geometryNode.children.append(dracoNode);
|
||||
|
||||
|
@ -236,12 +212,12 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
FBXNode modelNode;
|
||||
modelNode.name = MODEL_NODE_NAME;
|
||||
setNodeProperties(modelNode);
|
||||
|
||||
|
||||
_objectNode.children = { geometryNode, modelNode };
|
||||
|
||||
// Generating Objects node's child - Material node
|
||||
auto meshParts = geometry.meshes[0].parts;
|
||||
for (auto meshPart : meshParts) {
|
||||
auto& meshParts = geometry.meshes[0].parts;
|
||||
for (auto& meshPart : meshParts) {
|
||||
FBXNode materialNode;
|
||||
materialNode.name = MATERIAL_NODE_NAME;
|
||||
if (geometry.materials.size() == 1) {
|
||||
|
@ -252,24 +228,24 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
} else {
|
||||
setMaterialNodeProperties(materialNode, meshPart.materialID, geometry);
|
||||
}
|
||||
|
||||
|
||||
_objectNode.children.append(materialNode);
|
||||
}
|
||||
|
||||
|
||||
// Generating Texture Node
|
||||
// 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;
|
||||
FBXMaterial currentMaterial = geometry.materials[material];
|
||||
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
||||
_textureID = _nodeID;
|
||||
_mapTextureMaterial.push_back(QPair<qlonglong, int>(_textureID, i));
|
||||
|
||||
|
||||
FBXNode textureNode;
|
||||
textureNode.name = TEXTURE_NODE_NAME;
|
||||
QVariant textureProperty(_nodeID++);
|
||||
textureNode.properties = { textureProperty };
|
||||
|
||||
|
||||
// Texture node child - TextureName node
|
||||
FBXNode textureNameNode;
|
||||
textureNameNode.name = TEXTURENAME_NODE_NAME;
|
||||
|
@ -280,14 +256,14 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
// Texture node child - Relative Filename node
|
||||
FBXNode relativeFilenameNode;
|
||||
relativeFilenameNode.name = RELATIVEFILENAME_NODE_NAME;
|
||||
|
||||
|
||||
QByteArray textureFileName = (!currentMaterial.albedoTexture.filename.isEmpty()) ? currentMaterial.albedoTexture.filename : currentMaterial.specularTexture.filename;
|
||||
|
||||
|
||||
// Callback to get Texture content and type
|
||||
getTextureTypeCallback textureContentTypeCallback = [=]() {
|
||||
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
|
||||
QByteArray* textureFile = this->compressTexture(textureFileName, textureContentTypeCallback);
|
||||
if (textureFile) {
|
||||
|
@ -297,17 +273,17 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
return;
|
||||
}
|
||||
relativeFilenameNode.properties = { textureProperty };
|
||||
|
||||
|
||||
textureNode.children = { textureNameNode, relativeFilenameNode };
|
||||
|
||||
_objectNode.children.append(textureNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generating Connections node
|
||||
FBXNode connectionsNode;
|
||||
connectionsNode.name = CONNECTIONS_NODE_NAME;
|
||||
|
||||
|
||||
// connect Geometry to Model
|
||||
FBXNode cNode;
|
||||
cNode.name = C_NODE_NAME;
|
||||
|
@ -321,7 +297,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
connectionsNode.children = { cNode };
|
||||
|
||||
// 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;
|
||||
cNode1.name = C_NODE_NAME;
|
||||
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 };
|
||||
connectionsNode.children.append(cNode1);
|
||||
}
|
||||
|
||||
|
||||
// Connect textures to materials
|
||||
auto mapSize = _mapTextureMaterial.size();
|
||||
for (size_t i = 0;i < mapSize;i++) {
|
||||
for (size_t i = 0; i < mapSize; i++) {
|
||||
FBXNode cNode2;
|
||||
cNode2.name = C_NODE_NAME;
|
||||
propertyString = CONNECTIONS_NODE_PROPERTY_1;
|
||||
|
@ -357,7 +333,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
cNode3.properties = { property0, property1, property2, property3 };
|
||||
connectionsNode.children.append(cNode3);
|
||||
}
|
||||
|
||||
|
||||
// Make all generated nodes children of rootNode
|
||||
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
|
||||
void OBJBaker::setNodeProperties(FBXNode& parentNode) {
|
||||
if (parentNode.name == P_NODE_NAME) {
|
||||
std::vector<QByteArray> stringProperties{ "UnitScaleFactor", "double", "Number", "" };
|
||||
std::vector<double> numericProperties{ UNIT_SCALE_FACTOR };
|
||||
std::vector<QByteArray> stringProperties { "UnitScaleFactor", "double", "Number", "" };
|
||||
std::vector<double> numericProperties { UNIT_SCALE_FACTOR };
|
||||
|
||||
setPropertiesList(stringProperties, numericProperties, parentNode.properties);
|
||||
} 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()));
|
||||
|
||||
materialNode.properties = { property0, property1, property2 };
|
||||
|
||||
|
||||
FBXMaterial currentMaterial = geometry.materials[material];
|
||||
|
||||
|
||||
// Setting the hierarchy: Material -> Properties70 -> P -> Properties
|
||||
FBXNode properties70Node;
|
||||
properties70Node.name = PROPERTIES70_NODE_NAME;
|
||||
|
@ -411,8 +387,8 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material
|
|||
FBXNode pNodeDiffuseColor;
|
||||
pNodeDiffuseColor.name = P_NODE_NAME;
|
||||
|
||||
std::vector<QByteArray> stringProperties{ "DiffuseColor", "Color", "", "A" };
|
||||
std::vector<double> numericProperties{ currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] };
|
||||
std::vector<QByteArray> stringProperties { "DiffuseColor", "Color", "", "A" };
|
||||
std::vector<double> numericProperties { currentMaterial.diffuseColor[0], currentMaterial.diffuseColor[1], currentMaterial.diffuseColor[2] };
|
||||
setPropertiesList(stringProperties, numericProperties, pNodeDiffuseColor.properties);
|
||||
|
||||
properties70Node.children.append(pNodeDiffuseColor);
|
||||
|
@ -434,7 +410,7 @@ void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material
|
|||
stringProperties = { "Shininess", "Number", "", "A" };
|
||||
numericProperties = { currentMaterial.shininess };
|
||||
setPropertiesList(stringProperties, numericProperties, pNodeShininess.properties);
|
||||
|
||||
|
||||
properties70Node.children.append(pNodeShininess);
|
||||
|
||||
// Set Opacity
|
||||
|
|
|
@ -25,7 +25,6 @@ class OBJBaker : public ModelBaker {
|
|||
public:
|
||||
OBJBaker(const QUrl& objURL, TextureBakerThreadGetter textureThreadGetter,
|
||||
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
||||
~OBJBaker() override;
|
||||
void loadOBJ();
|
||||
void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry);
|
||||
void setNodeProperties(FBXNode& parentNode);
|
||||
|
|
Loading…
Reference in a new issue